Don't connect to backends that aren't needed

Change backend connection in Instance.cpp to store a bitset of
backends that have been connected. This lets us only connect to a
single backend if AdapterDiscoveryOptions are passed explicitly,
and track which connections have/have not been made. Later, we can
connect to the rest of the backends if more are requested.

This is part of some improvements to the existing code so we can
selectively discover adapters and control discovery of the
high-performance, low-power, and fallback WebGPU adapters.

Bug: chromium:1266550
Change-Id: Iceb0d3f71751f5aac6218996ace3cf89deda8a29
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/69521
Commit-Queue: Austin Eng <enga@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Austin Eng 2021-12-02 18:12:57 +00:00 committed by Dawn LUCI CQ
parent 56ff53088b
commit 2d0007ca8f
4 changed files with 117 additions and 33 deletions

View File

@ -59,6 +59,16 @@ namespace dawn_native {
return reinterpret_cast<{{as_cppType(type.name)}}Base*>(rhs);
}
{% endfor %}
template <typename T>
struct EnumCount;
{% for e in by_category["enum"] if e.contiguousFromZero %}
template<>
struct EnumCount<wgpu::{{as_cppType(e.name)}}> {
static constexpr uint32_t value = {{len(e.values)}};
};
{% endfor %}
}
#endif // DAWNNATIVE_DAWN_PLATFORM_AUTOGEN_H_

View File

@ -18,6 +18,7 @@
#include "common/Log.h"
#include "dawn_native/ErrorData.h"
#include "dawn_native/Surface.h"
#include "dawn_native/ValidationUtils_autogen.h"
#include "dawn_platform/DawnPlatform.h"
#if defined(DAWN_USE_X11)
@ -54,6 +55,34 @@ namespace dawn_native {
}
#endif // defined(DAWN_ENABLE_BACKEND_VULKAN)
namespace {
BackendsBitset GetEnabledBackends() {
BackendsBitset enabledBackends;
#if defined(DAWN_ENABLE_BACKEND_NULL)
enabledBackends.set(wgpu::BackendType::Null);
#endif // defined(DAWN_ENABLE_BACKEND_NULL)
#if defined(DAWN_ENABLE_BACKEND_D3D12)
enabledBackends.set(wgpu::BackendType::D3D12);
#endif // defined(DAWN_ENABLE_BACKEND_D3D12)
#if defined(DAWN_ENABLE_BACKEND_METAL)
enabledBackends.set(wgpu::BackendType::Metal);
#endif // defined(DAWN_ENABLE_BACKEND_METAL)
#if defined(DAWN_ENABLE_BACKEND_VULKAN)
enabledBackends.set(wgpu::BackendType::Vulkan);
#endif // defined(DAWN_ENABLE_BACKEND_VULKAN)
#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
enabledBackends.set(wgpu::BackendType::OpenGL);
#endif // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
#if defined(DAWN_ENABLE_BACKEND_OPENGLES)
enabledBackends.set(wgpu::BackendType::OpenGLES);
#endif // defined(DAWN_ENABLE_BACKEND_OPENGLES)
return enabledBackends;
}
} // anonymous namespace
// InstanceBase
// static
@ -71,7 +100,9 @@ namespace dawn_native {
}
void InstanceBase::DiscoverDefaultAdapters() {
EnsureBackendConnections();
for (wgpu::BackendType b : IterateBitSet(GetEnabledBackends())) {
EnsureBackendConnection(b);
}
if (mDiscoveredDefaultAdapters) {
return;
@ -122,8 +153,8 @@ namespace dawn_native {
return mAdapters;
}
void InstanceBase::EnsureBackendConnections() {
if (mBackendsConnected) {
void InstanceBase::EnsureBackendConnection(wgpu::BackendType backendType) {
if (mBackendsConnected[backendType]) {
return;
}
@ -135,42 +166,74 @@ namespace dawn_native {
}
};
switch (backendType) {
#if defined(DAWN_ENABLE_BACKEND_NULL)
case wgpu::BackendType::Null:
Register(null::Connect(this), wgpu::BackendType::Null);
break;
#endif // defined(DAWN_ENABLE_BACKEND_NULL)
#if defined(DAWN_ENABLE_BACKEND_D3D12)
case wgpu::BackendType::D3D12:
Register(d3d12::Connect(this), wgpu::BackendType::D3D12);
break;
#endif // defined(DAWN_ENABLE_BACKEND_D3D12)
#if defined(DAWN_ENABLE_BACKEND_METAL)
case wgpu::BackendType::Metal:
Register(metal::Connect(this), wgpu::BackendType::Metal);
break;
#endif // defined(DAWN_ENABLE_BACKEND_METAL)
#if defined(DAWN_ENABLE_BACKEND_VULKAN)
case wgpu::BackendType::Vulkan:
// TODO(https://github.com/KhronosGroup/Vulkan-Loader/issues/287):
// When we can load SwiftShader in parallel with the system driver, we should create the
// backend only once and expose SwiftShader as an additional adapter. For now, we create two
// VkInstances, one from SwiftShader, and one from the system. Note: If the Vulkan driver
// *is* SwiftShader, then this would load SwiftShader twice.
// When we can load SwiftShader in parallel with the system driver, we should
// create the backend only once and expose SwiftShader as an additional adapter.
// For now, we create two VkInstances, one from SwiftShader, and one from the
// system. Note: If the Vulkan driver *is* SwiftShader, then this would load
// SwiftShader twice.
Register(vulkan::Connect(this, false), wgpu::BackendType::Vulkan);
# if defined(DAWN_ENABLE_SWIFTSHADER)
Register(vulkan::Connect(this, true), wgpu::BackendType::Vulkan);
# endif // defined(DAWN_ENABLE_SWIFTSHADER)
break;
#endif // defined(DAWN_ENABLE_BACKEND_VULKAN)
#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
Register(opengl::Connect(this, wgpu::BackendType::OpenGL), wgpu::BackendType::OpenGL);
#endif // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
#if defined(DAWN_ENABLE_BACKEND_OPENGLES)
Register(opengl::Connect(this, wgpu::BackendType::OpenGLES), wgpu::BackendType::OpenGLES);
#endif // defined(DAWN_ENABLE_BACKEND_OPENGLES)
#if defined(DAWN_ENABLE_BACKEND_NULL)
Register(null::Connect(this), wgpu::BackendType::Null);
#endif // defined(DAWN_ENABLE_BACKEND_NULL)
mBackendsConnected = true;
#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
case wgpu::BackendType::OpenGL:
Register(opengl::Connect(this, wgpu::BackendType::OpenGL),
wgpu::BackendType::OpenGL);
break;
#endif // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
#if defined(DAWN_ENABLE_BACKEND_OPENGLES)
case wgpu::BackendType::OpenGLES:
Register(opengl::Connect(this, wgpu::BackendType::OpenGLES),
wgpu::BackendType::OpenGLES);
break;
#endif // defined(DAWN_ENABLE_BACKEND_OPENGLES)
default:
UNREACHABLE();
}
mBackendsConnected.set(backendType);
}
MaybeError InstanceBase::DiscoverAdaptersInternal(const AdapterDiscoveryOptionsBase* options) {
EnsureBackendConnections();
wgpu::BackendType backendType = static_cast<wgpu::BackendType>(options->backendType);
DAWN_TRY(ValidateBackendType(backendType));
if (!GetEnabledBackends()[backendType]) {
return DAWN_FORMAT_VALIDATION_ERROR("%s not supported.", backendType);
}
EnsureBackendConnection(backendType);
bool foundBackend = false;
for (std::unique_ptr<BackendConnection>& backend : mBackends) {
if (backend->GetType() != static_cast<wgpu::BackendType>(options->backendType)) {
if (backend->GetType() != backendType) {
continue;
}
foundBackend = true;
@ -185,7 +248,7 @@ namespace dawn_native {
}
}
DAWN_INVALID_IF(!foundBackend, "No matching backend found.");
DAWN_INVALID_IF(!foundBackend, "%s not available.", backendType);
return {};
}

View File

@ -16,6 +16,7 @@
#define DAWNNATIVE_INSTANCE_H_
#include "common/RefCounted.h"
#include "common/ityp_bitset.h"
#include "dawn_native/Adapter.h"
#include "dawn_native/BackendConnection.h"
#include "dawn_native/Features.h"
@ -36,6 +37,8 @@ namespace dawn_native {
class Surface;
class XlibXcbFunctions;
using BackendsBitset = ityp::bitset<wgpu::BackendType, kEnumCount<wgpu::BackendType>>;
// This is called InstanceBase for consistency across the frontend, even if the backends don't
// specialize this class.
class InstanceBase final : public RefCounted {
@ -87,11 +90,12 @@ namespace dawn_native {
bool Initialize(const InstanceDescriptor* descriptor);
// Lazily creates connections to all backends that have been compiled.
void EnsureBackendConnections();
void EnsureBackendConnection(wgpu::BackendType backendType);
MaybeError DiscoverAdaptersInternal(const AdapterDiscoveryOptionsBase* options);
bool mBackendsConnected = false;
BackendsBitset mBackendsConnected;
bool mDiscoveredDefaultAdapters = false;
bool mBeginCaptureOnStartup = false;

View File

@ -21,6 +21,13 @@
#include <dawn_native/dawn_platform_autogen.h>
namespace dawn_native {
// kEnumCount is a constant specifying the number of enums in a WebGPU enum type,
// if the enums are contiguous, making it suitable for iteration.
// It is defined in dawn_platform_autogen.h
template <typename T>
constexpr uint32_t kEnumCount = EnumCount<T>::value;
// Extra buffer usages
// Add an extra buffer usage and an extra binding type for binding the buffers with QueryResolve
// usage as storage buffer in the internal pipeline.