diff --git a/src/dawn_native/d3d12/BackendD3D12.cpp b/src/dawn_native/d3d12/BackendD3D12.cpp index 8ba578f02f..22d29c7bcf 100644 --- a/src/dawn_native/d3d12/BackendD3D12.cpp +++ b/src/dawn_native/d3d12/BackendD3D12.cpp @@ -151,8 +151,31 @@ namespace dawn_native { namespace d3d12 { } std::vector> Backend::DiscoverDefaultAdapters() { - std::vector> adapters; + AdapterDiscoveryOptions options; + auto result = DiscoverAdapters(&options); + if (result.IsError()) { + GetInstance()->ConsumedError(result.AcquireError()); + return {}; + } + return result.AcquireSuccess(); + } + ResultOrError>> Backend::DiscoverAdapters( + const AdapterDiscoveryOptionsBase* optionsBase) { + ASSERT(optionsBase->backendType == WGPUBackendType_D3D12); + const AdapterDiscoveryOptions* options = + static_cast(optionsBase); + + std::vector> adapters; + if (options->dxgiAdapter != nullptr) { + // |dxgiAdapter| was provided. Discover just that adapter. + std::unique_ptr adapter; + DAWN_TRY_ASSIGN(adapter, CreateAdapterFromIDXGIAdapter(this, options->dxgiAdapter)); + adapters.push_back(std::move(adapter)); + return std::move(adapters); + } + + // Enumerate and discover all available adapters. for (uint32_t adapterIndex = 0;; ++adapterIndex) { ComPtr dxgiAdapter = nullptr; if (mFactory->EnumAdapters1(adapterIndex, &dxgiAdapter) == DXGI_ERROR_NOT_FOUND) { @@ -173,21 +196,6 @@ namespace dawn_native { namespace d3d12 { return adapters; } - ResultOrError>> Backend::DiscoverAdapters( - const AdapterDiscoveryOptionsBase* optionsBase) { - ASSERT(optionsBase->backendType == WGPUBackendType_D3D12); - const AdapterDiscoveryOptions* options = - static_cast(optionsBase); - - ASSERT(options->dxgiAdapter != nullptr); - - std::unique_ptr adapter; - DAWN_TRY_ASSIGN(adapter, CreateAdapterFromIDXGIAdapter(this, options->dxgiAdapter)); - std::vector> adapters; - adapters.push_back(std::move(adapter)); - return std::move(adapters); - } - BackendConnection* Connect(InstanceBase* instance) { Backend* backend = new Backend(instance); diff --git a/src/dawn_native/d3d12/D3D12Backend.cpp b/src/dawn_native/d3d12/D3D12Backend.cpp index f84b2364a5..35baa1b960 100644 --- a/src/dawn_native/d3d12/D3D12Backend.cpp +++ b/src/dawn_native/d3d12/D3D12Backend.cpp @@ -171,6 +171,10 @@ namespace dawn_native { namespace d3d12 { memorySegment, requestedReservationSize); } + AdapterDiscoveryOptions::AdapterDiscoveryOptions() + : AdapterDiscoveryOptionsBase(WGPUBackendType_D3D12), dxgiAdapter(nullptr) { + } + AdapterDiscoveryOptions::AdapterDiscoveryOptions(ComPtr adapter) : AdapterDiscoveryOptionsBase(WGPUBackendType_D3D12), dxgiAdapter(std::move(adapter)) { } diff --git a/src/dawn_native/metal/BackendMTL.h b/src/dawn_native/metal/BackendMTL.h index fe8df5e27b..6cffa43ac6 100644 --- a/src/dawn_native/metal/BackendMTL.h +++ b/src/dawn_native/metal/BackendMTL.h @@ -24,6 +24,8 @@ namespace dawn_native { namespace metal { Backend(InstanceBase* instance); std::vector> DiscoverDefaultAdapters() override; + ResultOrError>> DiscoverAdapters( + const AdapterDiscoveryOptionsBase* optionsBase) override; }; }} // namespace dawn_native::metal diff --git a/src/dawn_native/metal/BackendMTL.mm b/src/dawn_native/metal/BackendMTL.mm index 8a7a770d87..f4166f0a0f 100644 --- a/src/dawn_native/metal/BackendMTL.mm +++ b/src/dawn_native/metal/BackendMTL.mm @@ -548,6 +548,19 @@ namespace dawn_native { namespace metal { } std::vector> Backend::DiscoverDefaultAdapters() { + AdapterDiscoveryOptions options; + auto result = DiscoverAdapters(&options); + if (result.IsError()) { + GetInstance()->ConsumedError(result.AcquireError()); + return {}; + } + return result.AcquireSuccess(); + } + + ResultOrError>> Backend::DiscoverAdapters( + const AdapterDiscoveryOptionsBase* optionsBase) { + ASSERT(optionsBase->backendType == WGPUBackendType_Metal); + std::vector> adapters; BOOL supportedVersion = NO; #if defined(DAWN_PLATFORM_MACOS) diff --git a/src/dawn_native/metal/MetalBackend.mm b/src/dawn_native/metal/MetalBackend.mm index 4d97fb83eb..4d0824d2f5 100644 --- a/src/dawn_native/metal/MetalBackend.mm +++ b/src/dawn_native/metal/MetalBackend.mm @@ -26,6 +26,10 @@ namespace dawn_native { namespace metal { return ToBackend(FromAPI(device))->GetMTLDevice(); } + AdapterDiscoveryOptions::AdapterDiscoveryOptions() + : AdapterDiscoveryOptionsBase(WGPUBackendType_Metal) { + } + ExternalImageDescriptorIOSurface::ExternalImageDescriptorIOSurface() : ExternalImageDescriptor(ExternalImageType::IOSurface) { } diff --git a/src/dawn_native/vulkan/BackendVk.cpp b/src/dawn_native/vulkan/BackendVk.cpp index c610d10be0..1c4c1b9070 100644 --- a/src/dawn_native/vulkan/BackendVk.cpp +++ b/src/dawn_native/vulkan/BackendVk.cpp @@ -359,10 +359,29 @@ namespace dawn_native { namespace vulkan { Backend::~Backend() = default; std::vector> Backend::DiscoverDefaultAdapters() { + AdapterDiscoveryOptions options; + auto result = DiscoverAdapters(&options); + if (result.IsError()) { + GetInstance()->ConsumedError(result.AcquireError()); + return {}; + } + return result.AcquireSuccess(); + } + + ResultOrError>> Backend::DiscoverAdapters( + const AdapterDiscoveryOptionsBase* optionsBase) { + ASSERT(optionsBase->backendType == WGPUBackendType_Vulkan); + + const AdapterDiscoveryOptions* options = + static_cast(optionsBase); + std::vector> adapters; InstanceBase* instance = GetInstance(); for (ICD icd : kICDs) { + if (options->forceSwiftShader && icd != ICD::SwiftShader) { + continue; + } if (mVulkanInstances[icd] == nullptr && instance->ConsumedError([&]() -> MaybeError { DAWN_TRY_ASSIGN(mVulkanInstances[icd], VulkanInstance::Create(instance, icd)); return {}; @@ -381,7 +400,6 @@ namespace dawn_native { namespace vulkan { adapters.push_back(std::move(adapter)); } } - return adapters; } diff --git a/src/dawn_native/vulkan/BackendVk.h b/src/dawn_native/vulkan/BackendVk.h index 0a9680cdfe..96541f1b0b 100644 --- a/src/dawn_native/vulkan/BackendVk.h +++ b/src/dawn_native/vulkan/BackendVk.h @@ -74,6 +74,8 @@ namespace dawn_native { namespace vulkan { MaybeError Initialize(); std::vector> DiscoverDefaultAdapters() override; + ResultOrError>> DiscoverAdapters( + const AdapterDiscoveryOptionsBase* optionsBase) override; private: ityp::array, 2> mVulkanInstances = {}; diff --git a/src/dawn_native/vulkan/VulkanBackend.cpp b/src/dawn_native/vulkan/VulkanBackend.cpp index a2ac328bf4..f406f9f55d 100644 --- a/src/dawn_native/vulkan/VulkanBackend.cpp +++ b/src/dawn_native/vulkan/VulkanBackend.cpp @@ -59,6 +59,10 @@ namespace dawn_native { namespace vulkan { return static_cast(impl->GetPreferredFormat()); } + AdapterDiscoveryOptions::AdapterDiscoveryOptions() + : AdapterDiscoveryOptionsBase(WGPUBackendType_Vulkan) { + } + #if defined(DAWN_PLATFORM_LINUX) ExternalImageDescriptorOpaqueFD::ExternalImageDescriptorOpaqueFD() : ExternalImageDescriptorFD(ExternalImageType::OpaqueFD) { diff --git a/src/include/dawn_native/D3D12Backend.h b/src/include/dawn_native/D3D12Backend.h index f9588e4d4f..a6644b11cf 100644 --- a/src/include/dawn_native/D3D12Backend.h +++ b/src/include/dawn_native/D3D12Backend.h @@ -95,6 +95,7 @@ namespace dawn_native { namespace d3d12 { }; struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptions : public AdapterDiscoveryOptionsBase { + AdapterDiscoveryOptions(); AdapterDiscoveryOptions(Microsoft::WRL::ComPtr adapter); Microsoft::WRL::ComPtr dxgiAdapter; diff --git a/src/include/dawn_native/MetalBackend.h b/src/include/dawn_native/MetalBackend.h index 90884ee7f2..0346843658 100644 --- a/src/include/dawn_native/MetalBackend.h +++ b/src/include/dawn_native/MetalBackend.h @@ -33,6 +33,11 @@ typedef __IOSurface* IOSurfaceRef; #endif //__OBJC__ namespace dawn_native { namespace metal { + + struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptions : public AdapterDiscoveryOptionsBase { + AdapterDiscoveryOptions(); + }; + struct DAWN_NATIVE_EXPORT ExternalImageDescriptorIOSurface : ExternalImageDescriptor { public: ExternalImageDescriptorIOSurface(); @@ -50,11 +55,14 @@ namespace dawn_native { namespace metal { // when they are "scheduled". Submitting other operations before the command buffer is // scheduled could lead to races in who gets scheduled first and incorrect rendering. DAWN_NATIVE_EXPORT void WaitForCommandsToBeScheduled(WGPUDevice device); + }} // namespace dawn_native::metal #ifdef __OBJC__ namespace dawn_native { namespace metal { + DAWN_NATIVE_EXPORT id GetMetalDevice(WGPUDevice device); + }} // namespace dawn_native::metal #endif // __OBJC__ diff --git a/src/include/dawn_native/VulkanBackend.h b/src/include/dawn_native/VulkanBackend.h index ff5feca915..888ef27936 100644 --- a/src/include/dawn_native/VulkanBackend.h +++ b/src/include/dawn_native/VulkanBackend.h @@ -33,6 +33,12 @@ namespace dawn_native { namespace vulkan { DAWN_NATIVE_EXPORT WGPUTextureFormat GetNativeSwapChainPreferredFormat(const DawnSwapChainImplementation* swapChain); + struct DAWN_NATIVE_EXPORT AdapterDiscoveryOptions : public AdapterDiscoveryOptionsBase { + AdapterDiscoveryOptions(); + + bool forceSwiftShader = false; + }; + struct DAWN_NATIVE_EXPORT ExternalImageDescriptorVk : ExternalImageDescriptor { public: // The following members may be ignored if |ExternalImageDescriptor::isInitialized| is false diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn index 23671a9ae3..ef33d9a33d 100644 --- a/src/tests/BUILD.gn +++ b/src/tests/BUILD.gn @@ -335,6 +335,7 @@ source_set("dawn_end2end_tests_sources") { "ParamGenerator.h", "ToggleParser.cpp", "ToggleParser.h", + "end2end/AdapterDiscoveryTests.cpp", "end2end/BasicTests.cpp", "end2end/BindGroupTests.cpp", "end2end/BufferTests.cpp", diff --git a/src/tests/end2end/AdapterDiscoveryTests.cpp b/src/tests/end2end/AdapterDiscoveryTests.cpp new file mode 100644 index 0000000000..a15fb70e6f --- /dev/null +++ b/src/tests/end2end/AdapterDiscoveryTests.cpp @@ -0,0 +1,269 @@ +// Copyright 2021 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 "common/GPUInfo.h" +#include "common/Platform.h" +#include "common/SystemUtils.h" +#include "dawn/webgpu_cpp.h" +#include "dawn_native/DawnNative.h" + +#if defined(DAWN_ENABLE_BACKEND_VULKAN) +# include "dawn_native/VulkanBackend.h" +#endif // defined(DAWN_ENABLE_BACKEND_VULKAN) + +#if defined(DAWN_ENABLE_BACKEND_D3D12) +# include "dawn_native/D3D12Backend.h" +#endif // defined(DAWN_ENABLE_BACKEND_D3D12) + +#if defined(DAWN_ENABLE_BACKEND_METAL) +# include "dawn_native/MetalBackend.h" +#endif // defined(DAWN_ENABLE_BACKEND_METAL) + +#if defined(DAWN_ENABLE_BACKEND_METAL) +# include "dawn_native/MetalBackend.h" +#endif // defined(DAWN_ENABLE_BACKEND_METAL) + +#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) || defined(DAWN_ENABLE_BACKEND_OPENGLES) +# include "GLFW/glfw3.h" +# include "dawn_native/OpenGLBackend.h" +#endif // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) || defined(DAWN_ENABLE_BACKEND_OPENGLES) + +#include + +namespace { + + class AdapterDiscoveryTests : public ::testing::Test {}; + +#if defined(DAWN_ENABLE_BACKEND_VULKAN) + // Test only discovering the SwiftShader adapter + TEST(AdapterDiscoveryTests, OnlySwiftShader) { + dawn_native::Instance instance; + + dawn_native::vulkan::AdapterDiscoveryOptions options; + options.forceSwiftShader = true; + instance.DiscoverAdapters(&options); + + const auto& adapters = instance.GetAdapters(); + EXPECT_LE(adapters.size(), 1u); // 0 or 1 SwiftShader adapters. + for (const auto& adapter : adapters) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + EXPECT_EQ(properties.backendType, wgpu::BackendType::Vulkan); + EXPECT_EQ(properties.adapterType, wgpu::AdapterType::CPU); + EXPECT_TRUE(gpu_info::IsSwiftshader(properties.vendorID, properties.deviceID)); + } + } + + // Test discovering only Vulkan adapters + TEST(AdapterDiscoveryTests, OnlyVulkan) { + dawn_native::Instance instance; + + dawn_native::vulkan::AdapterDiscoveryOptions options; + instance.DiscoverAdapters(&options); + + const auto& adapters = instance.GetAdapters(); + for (const auto& adapter : adapters) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + EXPECT_EQ(properties.backendType, wgpu::BackendType::Vulkan); + } + } +#endif // defined(DAWN_ENABLE_BACKEND_VULKAN) + +#if defined(DAWN_ENABLE_BACKEND_D3D12) + // Test discovering only D3D12 adapters + TEST(AdapterDiscoveryTests, OnlyD3D12) { + dawn_native::Instance instance; + + dawn_native::d3d12::AdapterDiscoveryOptions options; + instance.DiscoverAdapters(&options); + + const auto& adapters = instance.GetAdapters(); + for (const auto& adapter : adapters) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + EXPECT_EQ(properties.backendType, wgpu::BackendType::D3D12); + } + } + + // Test discovering a D3D12 adapter from a prexisting DXGI adapter + TEST(AdapterDiscoveryTests, MatchingDXGIAdapter) { + using Microsoft::WRL::ComPtr; + + ComPtr dxgiFactory; + HRESULT hr = ::CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory)); + ASSERT_EQ(hr, S_OK); + + for (uint32_t adapterIndex = 0;; ++adapterIndex) { + ComPtr dxgiAdapter = nullptr; + if (dxgiFactory->EnumAdapters1(adapterIndex, &dxgiAdapter) == DXGI_ERROR_NOT_FOUND) { + break; // No more adapters to enumerate. + } + + dawn_native::Instance instance; + + dawn_native::d3d12::AdapterDiscoveryOptions options; + options.dxgiAdapter = std::move(dxgiAdapter); + instance.DiscoverAdapters(&options); + + const auto& adapters = instance.GetAdapters(); + for (const auto& adapter : adapters) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + EXPECT_EQ(properties.backendType, wgpu::BackendType::D3D12); + } + } + } +#endif // defined(DAWN_ENABLE_BACKEND_D3D12) + +#if defined(DAWN_ENABLE_BACKEND_METAL) + // Test discovering only Metal adapters + TEST(AdapterDiscoveryTests, OnlyMetal) { + dawn_native::Instance instance; + + dawn_native::metal::AdapterDiscoveryOptions options; + instance.DiscoverAdapters(&options); + + const auto& adapters = instance.GetAdapters(); + for (const auto& adapter : adapters) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + EXPECT_EQ(properties.backendType, wgpu::BackendType::Metal); + } + } +#endif // defined(DAWN_ENABLE_BACKEND_METAL) + +#if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) + // Test discovering only desktop OpenGL adapters + TEST(AdapterDiscoveryTests, OnlyDesktopGL) { + if (!glfwInit()) { + GTEST_SKIP() << "glfwInit() failed"; + } + glfwDefaultWindowHints(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); + + GLFWwindow* window = + glfwCreateWindow(400, 400, "Dawn OpenGL test window", nullptr, nullptr); + glfwMakeContextCurrent(window); + + dawn_native::Instance instance; + + dawn_native::opengl::AdapterDiscoveryOptions options; + options.getProc = reinterpret_cast(glfwGetProcAddress); + instance.DiscoverAdapters(&options); + glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); + + const auto& adapters = instance.GetAdapters(); + for (const auto& adapter : adapters) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + EXPECT_EQ(properties.backendType, wgpu::BackendType::OpenGL); + } + + glfwDestroyWindow(window); + } +#endif // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) + +#if defined(DAWN_ENABLE_BACKEND_OPENGLES) + // Test discovering only OpenGLES adapters + TEST(AdapterDiscoveryTests, OnlyOpenGLES) { + ScopedEnvironmentVar angleDefaultPlatform; + if (GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM").first.empty()) { + angleDefaultPlatform.Set("ANGLE_DEFAULT_PLATFORM", "swiftshader"); + } + + if (!glfwInit()) { + GTEST_SKIP() << "glfwInit() failed"; + } + glfwDefaultWindowHints(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API); + glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE); + + GLFWwindow* window = + glfwCreateWindow(400, 400, "Dawn OpenGLES test window", nullptr, nullptr); + glfwMakeContextCurrent(window); + + dawn_native::Instance instance; + + dawn_native::opengl::AdapterDiscoveryOptionsES options; + options.getProc = reinterpret_cast(glfwGetProcAddress); + instance.DiscoverAdapters(&options); + glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE); + + const auto& adapters = instance.GetAdapters(); + for (const auto& adapter : adapters) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + EXPECT_EQ(properties.backendType, wgpu::BackendType::OpenGLES); + } + + glfwDestroyWindow(window); + } +#endif // defined(DAWN_ENABLE_BACKEND_OPENGLES) + +#if defined(DAWN_ENABLE_BACKEND_METAL) && defined(DAWN_ENABLE_BACKEND_VULKAN) + // Test discovering the Metal backend, then the Vulkan backend + // does not duplicate adapters. + TEST(AdapterDiscoveryTests, OneBackendThenTheOther) { + dawn_native::Instance instance; + uint32_t metalAdapterCount = 0; + { + dawn_native::metal::AdapterDiscoveryOptions options; + instance.DiscoverAdapters(&options); + + const auto& adapters = instance.GetAdapters(); + metalAdapterCount = adapters.size(); + for (const auto& adapter : adapters) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + ASSERT_EQ(properties.backendType, wgpu::BackendType::Metal); + } + } + { + dawn_native::vulkan::AdapterDiscoveryOptions options; + instance.DiscoverAdapters(&options); + + uint32_t metalAdapterCount2 = 0; + const auto& adapters = instance.GetAdapters(); + for (const auto& adapter : adapters) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + EXPECT_TRUE(properties.backendType == wgpu::BackendType::Metal || + properties.backendType == wgpu::BackendType::Vulkan); + if (properties.backendType == wgpu::BackendType::Metal) { + metalAdapterCount2++; + } + } + EXPECT_EQ(metalAdapterCount, metalAdapterCount2); + } + } +#endif // defined(DAWN_ENABLE_BACKEND_VULKAN) && defined(DAWN_ENABLE_BACKEND_METAL) + +} // anonymous namespace