| // Copyright 2018 The Dawn Authors |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "dawn_native/Instance.h" |
| |
| #include "common/Assert.h" |
| #include "common/Log.h" |
| #include "dawn_native/ErrorData.h" |
| #include "dawn_native/Surface.h" |
| #include "dawn_platform/DawnPlatform.h" |
| |
| #if defined(DAWN_USE_X11) |
| # include "dawn_native/XlibXcbFunctions.h" |
| #endif // defined(DAWN_USE_X11) |
| |
| namespace dawn_native { |
| |
| // Forward definitions of each backend's "Connect" function that creates new BackendConnection. |
| // Conditionally compiled declarations are used to avoid using static constructors instead. |
| #if defined(DAWN_ENABLE_BACKEND_D3D12) |
| namespace d3d12 { |
| BackendConnection* Connect(InstanceBase* instance); |
| } |
| #endif // defined(DAWN_ENABLE_BACKEND_D3D12) |
| #if defined(DAWN_ENABLE_BACKEND_METAL) |
| namespace metal { |
| BackendConnection* Connect(InstanceBase* instance); |
| } |
| #endif // defined(DAWN_ENABLE_BACKEND_METAL) |
| #if defined(DAWN_ENABLE_BACKEND_NULL) |
| namespace null { |
| BackendConnection* Connect(InstanceBase* instance); |
| } |
| #endif // defined(DAWN_ENABLE_BACKEND_NULL) |
| #if defined(DAWN_ENABLE_BACKEND_OPENGL) |
| namespace opengl { |
| BackendConnection* Connect(InstanceBase* instance, wgpu::BackendType backendType); |
| } |
| #endif // defined(DAWN_ENABLE_BACKEND_OPENGL) |
| #if defined(DAWN_ENABLE_BACKEND_VULKAN) |
| namespace vulkan { |
| BackendConnection* Connect(InstanceBase* instance, bool useSwiftshader); |
| } |
| #endif // defined(DAWN_ENABLE_BACKEND_VULKAN) |
| |
| // InstanceBase |
| |
| // static |
| InstanceBase* InstanceBase::Create(const InstanceDescriptor* descriptor) { |
| Ref<InstanceBase> instance = AcquireRef(new InstanceBase); |
| if (!instance->Initialize(descriptor)) { |
| return nullptr; |
| } |
| return instance.Detach(); |
| } |
| |
| // TODO(crbug.com/dawn/832): make the platform an initialization parameter of the instance. |
| bool InstanceBase::Initialize(const InstanceDescriptor*) { |
| return true; |
| } |
| |
| void InstanceBase::DiscoverDefaultAdapters() { |
| EnsureBackendConnections(); |
| |
| if (mDiscoveredDefaultAdapters) { |
| return; |
| } |
| |
| // Query and merge all default adapters for all backends |
| for (std::unique_ptr<BackendConnection>& backend : mBackends) { |
| std::vector<std::unique_ptr<AdapterBase>> backendAdapters = |
| backend->DiscoverDefaultAdapters(); |
| |
| for (std::unique_ptr<AdapterBase>& adapter : backendAdapters) { |
| ASSERT(adapter->GetBackendType() == backend->GetType()); |
| ASSERT(adapter->GetInstance() == this); |
| mAdapters.push_back(std::move(adapter)); |
| } |
| } |
| |
| mDiscoveredDefaultAdapters = true; |
| } |
| |
| // This is just a wrapper around the real logic that uses Error.h error handling. |
| bool InstanceBase::DiscoverAdapters(const AdapterDiscoveryOptionsBase* options) { |
| return !ConsumedError(DiscoverAdaptersInternal(options)); |
| } |
| |
| const ToggleInfo* InstanceBase::GetToggleInfo(const char* toggleName) { |
| return mTogglesInfo.GetToggleInfo(toggleName); |
| } |
| |
| Toggle InstanceBase::ToggleNameToEnum(const char* toggleName) { |
| return mTogglesInfo.ToggleNameToEnum(toggleName); |
| } |
| |
| const FeatureInfo* InstanceBase::GetFeatureInfo(const char* featureName) { |
| return mFeaturesInfo.GetFeatureInfo(featureName); |
| } |
| |
| Feature InstanceBase::FeatureNameToEnum(const char* featureName) { |
| return mFeaturesInfo.FeatureNameToEnum(featureName); |
| } |
| |
| FeaturesSet InstanceBase::FeatureNamesToFeaturesSet( |
| const std::vector<const char*>& requiredFeatures) { |
| return mFeaturesInfo.FeatureNamesToFeaturesSet(requiredFeatures); |
| } |
| |
| const std::vector<std::unique_ptr<AdapterBase>>& InstanceBase::GetAdapters() const { |
| return mAdapters; |
| } |
| |
| void InstanceBase::EnsureBackendConnections() { |
| if (mBackendsConnected) { |
| return; |
| } |
| |
| auto Register = [this](BackendConnection* connection, wgpu::BackendType expectedType) { |
| if (connection != nullptr) { |
| ASSERT(connection->GetType() == expectedType); |
| ASSERT(connection->GetInstance() == this); |
| mBackends.push_back(std::unique_ptr<BackendConnection>(connection)); |
| } |
| }; |
| |
| #if defined(DAWN_ENABLE_BACKEND_D3D12) |
| Register(d3d12::Connect(this), wgpu::BackendType::D3D12); |
| #endif // defined(DAWN_ENABLE_BACKEND_D3D12) |
| #if defined(DAWN_ENABLE_BACKEND_METAL) |
| Register(metal::Connect(this), wgpu::BackendType::Metal); |
| #endif // defined(DAWN_ENABLE_BACKEND_METAL) |
| #if defined(DAWN_ENABLE_BACKEND_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. |
| 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) |
| #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; |
| } |
| |
| MaybeError InstanceBase::DiscoverAdaptersInternal(const AdapterDiscoveryOptionsBase* options) { |
| EnsureBackendConnections(); |
| |
| bool foundBackend = false; |
| for (std::unique_ptr<BackendConnection>& backend : mBackends) { |
| if (backend->GetType() != static_cast<wgpu::BackendType>(options->backendType)) { |
| continue; |
| } |
| foundBackend = true; |
| |
| std::vector<std::unique_ptr<AdapterBase>> newAdapters; |
| DAWN_TRY_ASSIGN(newAdapters, backend->DiscoverAdapters(options)); |
| |
| for (std::unique_ptr<AdapterBase>& adapter : newAdapters) { |
| ASSERT(adapter->GetBackendType() == backend->GetType()); |
| ASSERT(adapter->GetInstance() == this); |
| mAdapters.push_back(std::move(adapter)); |
| } |
| } |
| |
| DAWN_INVALID_IF(!foundBackend, "No matching backend found."); |
| return {}; |
| } |
| |
| bool InstanceBase::ConsumedError(MaybeError maybeError) { |
| if (maybeError.IsError()) { |
| std::unique_ptr<ErrorData> error = maybeError.AcquireError(); |
| |
| ASSERT(error != nullptr); |
| dawn::InfoLog() << error->GetFormattedMessage(); |
| |
| return true; |
| } |
| return false; |
| } |
| |
| bool InstanceBase::IsBackendValidationEnabled() const { |
| return mBackendValidationLevel != BackendValidationLevel::Disabled; |
| } |
| |
| void InstanceBase::SetBackendValidationLevel(BackendValidationLevel level) { |
| mBackendValidationLevel = level; |
| } |
| |
| BackendValidationLevel InstanceBase::GetBackendValidationLevel() const { |
| return mBackendValidationLevel; |
| } |
| |
| void InstanceBase::EnableBeginCaptureOnStartup(bool beginCaptureOnStartup) { |
| mBeginCaptureOnStartup = beginCaptureOnStartup; |
| } |
| |
| bool InstanceBase::IsBeginCaptureOnStartupEnabled() const { |
| return mBeginCaptureOnStartup; |
| } |
| |
| void InstanceBase::SetPlatform(dawn_platform::Platform* platform) { |
| mPlatform = platform; |
| } |
| |
| dawn_platform::Platform* InstanceBase::GetPlatform() { |
| if (mPlatform != nullptr) { |
| return mPlatform; |
| } |
| |
| if (mDefaultPlatform == nullptr) { |
| mDefaultPlatform = std::make_unique<dawn_platform::Platform>(); |
| } |
| return mDefaultPlatform.get(); |
| } |
| |
| const XlibXcbFunctions* InstanceBase::GetOrCreateXlibXcbFunctions() { |
| #if defined(DAWN_USE_X11) |
| if (mXlibXcbFunctions == nullptr) { |
| mXlibXcbFunctions = std::make_unique<XlibXcbFunctions>(); |
| } |
| return mXlibXcbFunctions.get(); |
| #else |
| UNREACHABLE(); |
| #endif // defined(DAWN_USE_X11) |
| } |
| |
| Surface* InstanceBase::APICreateSurface(const SurfaceDescriptor* descriptor) { |
| if (ConsumedError(ValidateSurfaceDescriptor(this, descriptor))) { |
| return nullptr; |
| } |
| |
| return new Surface(this, descriptor); |
| } |
| |
| } // namespace dawn_native |