1 // Copyright 2021 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "common/GPUInfo.h"
16 #include "common/Platform.h"
17 #include "common/SystemUtils.h"
18 #include "dawn/webgpu_cpp.h"
19 #include "dawn_native/DawnNative.h"
20 
21 #if defined(DAWN_ENABLE_BACKEND_VULKAN)
22 #    include "dawn_native/VulkanBackend.h"
23 #endif  // defined(DAWN_ENABLE_BACKEND_VULKAN)
24 
25 #if defined(DAWN_ENABLE_BACKEND_D3D12)
26 #    include "dawn_native/D3D12Backend.h"
27 #endif  // defined(DAWN_ENABLE_BACKEND_D3D12)
28 
29 #if defined(DAWN_ENABLE_BACKEND_METAL)
30 #    include "dawn_native/MetalBackend.h"
31 #endif  // defined(DAWN_ENABLE_BACKEND_METAL)
32 
33 #if defined(DAWN_ENABLE_BACKEND_METAL)
34 #    include "dawn_native/MetalBackend.h"
35 #endif  // defined(DAWN_ENABLE_BACKEND_METAL)
36 
37 #if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) || defined(DAWN_ENABLE_BACKEND_OPENGLES)
38 #    include "GLFW/glfw3.h"
39 #    include "dawn_native/OpenGLBackend.h"
40 #endif  // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL) || defined(DAWN_ENABLE_BACKEND_OPENGLES)
41 
42 #include <gtest/gtest.h>
43 
44 namespace {
45 
46     class AdapterDiscoveryTests : public ::testing::Test {};
47 
48 #if defined(DAWN_ENABLE_BACKEND_VULKAN)
49     // Test only discovering the SwiftShader adapter
TEST(AdapterDiscoveryTests, OnlySwiftShader)50     TEST(AdapterDiscoveryTests, OnlySwiftShader) {
51         dawn_native::Instance instance;
52 
53         dawn_native::vulkan::AdapterDiscoveryOptions options;
54         options.forceSwiftShader = true;
55         instance.DiscoverAdapters(&options);
56 
57         const auto& adapters = instance.GetAdapters();
58         EXPECT_LE(adapters.size(), 1u);  // 0 or 1 SwiftShader adapters.
59         for (const auto& adapter : adapters) {
60             wgpu::AdapterProperties properties;
61             adapter.GetProperties(&properties);
62 
63             EXPECT_EQ(properties.backendType, wgpu::BackendType::Vulkan);
64             EXPECT_EQ(properties.adapterType, wgpu::AdapterType::CPU);
65             EXPECT_TRUE(gpu_info::IsSwiftshader(properties.vendorID, properties.deviceID));
66         }
67     }
68 
69     // Test discovering only Vulkan adapters
TEST(AdapterDiscoveryTests, OnlyVulkan)70     TEST(AdapterDiscoveryTests, OnlyVulkan) {
71         dawn_native::Instance instance;
72 
73         dawn_native::vulkan::AdapterDiscoveryOptions options;
74         instance.DiscoverAdapters(&options);
75 
76         const auto& adapters = instance.GetAdapters();
77         for (const auto& adapter : adapters) {
78             wgpu::AdapterProperties properties;
79             adapter.GetProperties(&properties);
80 
81             EXPECT_EQ(properties.backendType, wgpu::BackendType::Vulkan);
82         }
83     }
84 #endif  // defined(DAWN_ENABLE_BACKEND_VULKAN)
85 
86 #if defined(DAWN_ENABLE_BACKEND_D3D12)
87     // Test discovering only D3D12 adapters
TEST(AdapterDiscoveryTests, OnlyD3D12)88     TEST(AdapterDiscoveryTests, OnlyD3D12) {
89         dawn_native::Instance instance;
90 
91         dawn_native::d3d12::AdapterDiscoveryOptions options;
92         instance.DiscoverAdapters(&options);
93 
94         const auto& adapters = instance.GetAdapters();
95         for (const auto& adapter : adapters) {
96             wgpu::AdapterProperties properties;
97             adapter.GetProperties(&properties);
98 
99             EXPECT_EQ(properties.backendType, wgpu::BackendType::D3D12);
100         }
101     }
102 
103     // Test discovering a D3D12 adapter from a prexisting DXGI adapter
TEST(AdapterDiscoveryTests, MatchingDXGIAdapter)104     TEST(AdapterDiscoveryTests, MatchingDXGIAdapter) {
105         using Microsoft::WRL::ComPtr;
106 
107         ComPtr<IDXGIFactory4> dxgiFactory;
108         HRESULT hr = ::CreateDXGIFactory2(0, IID_PPV_ARGS(&dxgiFactory));
109         ASSERT_EQ(hr, S_OK);
110 
111         for (uint32_t adapterIndex = 0;; ++adapterIndex) {
112             ComPtr<IDXGIAdapter1> dxgiAdapter = nullptr;
113             if (dxgiFactory->EnumAdapters1(adapterIndex, &dxgiAdapter) == DXGI_ERROR_NOT_FOUND) {
114                 break;  // No more adapters to enumerate.
115             }
116 
117             dawn_native::Instance instance;
118 
119             dawn_native::d3d12::AdapterDiscoveryOptions options;
120             options.dxgiAdapter = std::move(dxgiAdapter);
121             instance.DiscoverAdapters(&options);
122 
123             const auto& adapters = instance.GetAdapters();
124             for (const auto& adapter : adapters) {
125                 wgpu::AdapterProperties properties;
126                 adapter.GetProperties(&properties);
127 
128                 EXPECT_EQ(properties.backendType, wgpu::BackendType::D3D12);
129             }
130         }
131     }
132 #endif  // defined(DAWN_ENABLE_BACKEND_D3D12)
133 
134 #if defined(DAWN_ENABLE_BACKEND_METAL)
135     // Test discovering only Metal adapters
TEST(AdapterDiscoveryTests, OnlyMetal)136     TEST(AdapterDiscoveryTests, OnlyMetal) {
137         dawn_native::Instance instance;
138 
139         dawn_native::metal::AdapterDiscoveryOptions options;
140         instance.DiscoverAdapters(&options);
141 
142         const auto& adapters = instance.GetAdapters();
143         for (const auto& adapter : adapters) {
144             wgpu::AdapterProperties properties;
145             adapter.GetProperties(&properties);
146 
147             EXPECT_EQ(properties.backendType, wgpu::BackendType::Metal);
148         }
149     }
150 #endif  // defined(DAWN_ENABLE_BACKEND_METAL)
151 
152 #if defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
153     // Test discovering only desktop OpenGL adapters
TEST(AdapterDiscoveryTests, OnlyDesktopGL)154     TEST(AdapterDiscoveryTests, OnlyDesktopGL) {
155         if (!glfwInit()) {
156             GTEST_SKIP() << "glfwInit() failed";
157         }
158         glfwDefaultWindowHints();
159         glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
160         glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
161         glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
162         glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
163         glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
164 
165         GLFWwindow* window =
166             glfwCreateWindow(400, 400, "Dawn OpenGL test window", nullptr, nullptr);
167         glfwMakeContextCurrent(window);
168 
169         dawn_native::Instance instance;
170 
171         dawn_native::opengl::AdapterDiscoveryOptions options;
172         options.getProc = reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress);
173         instance.DiscoverAdapters(&options);
174         glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
175 
176         const auto& adapters = instance.GetAdapters();
177         for (const auto& adapter : adapters) {
178             wgpu::AdapterProperties properties;
179             adapter.GetProperties(&properties);
180 
181             EXPECT_EQ(properties.backendType, wgpu::BackendType::OpenGL);
182         }
183 
184         glfwDestroyWindow(window);
185     }
186 #endif  // defined(DAWN_ENABLE_BACKEND_DESKTOP_GL)
187 
188 #if defined(DAWN_ENABLE_BACKEND_OPENGLES)
189     // Test discovering only OpenGLES adapters
TEST(AdapterDiscoveryTests, OnlyOpenGLES)190     TEST(AdapterDiscoveryTests, OnlyOpenGLES) {
191         ScopedEnvironmentVar angleDefaultPlatform;
192         if (GetEnvironmentVar("ANGLE_DEFAULT_PLATFORM").first.empty()) {
193             angleDefaultPlatform.Set("ANGLE_DEFAULT_PLATFORM", "swiftshader");
194         }
195 
196         if (!glfwInit()) {
197             GTEST_SKIP() << "glfwInit() failed";
198         }
199         glfwDefaultWindowHints();
200         glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
201         glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
202         glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
203         glfwWindowHint(GLFW_CONTEXT_CREATION_API, GLFW_EGL_CONTEXT_API);
204         glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
205 
206         GLFWwindow* window =
207             glfwCreateWindow(400, 400, "Dawn OpenGLES test window", nullptr, nullptr);
208         glfwMakeContextCurrent(window);
209 
210         dawn_native::Instance instance;
211 
212         dawn_native::opengl::AdapterDiscoveryOptionsES options;
213         options.getProc = reinterpret_cast<void* (*)(const char*)>(glfwGetProcAddress);
214         instance.DiscoverAdapters(&options);
215         glfwWindowHint(GLFW_VISIBLE, GLFW_TRUE);
216 
217         const auto& adapters = instance.GetAdapters();
218         for (const auto& adapter : adapters) {
219             wgpu::AdapterProperties properties;
220             adapter.GetProperties(&properties);
221 
222             EXPECT_EQ(properties.backendType, wgpu::BackendType::OpenGLES);
223         }
224 
225         glfwDestroyWindow(window);
226     }
227 #endif  // defined(DAWN_ENABLE_BACKEND_OPENGLES)
228 
229 #if defined(DAWN_ENABLE_BACKEND_METAL) && defined(DAWN_ENABLE_BACKEND_VULKAN)
230     // Test discovering the Metal backend, then the Vulkan backend
231     // does not duplicate adapters.
TEST(AdapterDiscoveryTests, OneBackendThenTheOther)232     TEST(AdapterDiscoveryTests, OneBackendThenTheOther) {
233         dawn_native::Instance instance;
234         uint32_t metalAdapterCount = 0;
235         {
236             dawn_native::metal::AdapterDiscoveryOptions options;
237             instance.DiscoverAdapters(&options);
238 
239             const auto& adapters = instance.GetAdapters();
240             metalAdapterCount = adapters.size();
241             for (const auto& adapter : adapters) {
242                 wgpu::AdapterProperties properties;
243                 adapter.GetProperties(&properties);
244 
245                 ASSERT_EQ(properties.backendType, wgpu::BackendType::Metal);
246             }
247         }
248         {
249             dawn_native::vulkan::AdapterDiscoveryOptions options;
250             instance.DiscoverAdapters(&options);
251 
252             uint32_t metalAdapterCount2 = 0;
253             const auto& adapters = instance.GetAdapters();
254             for (const auto& adapter : adapters) {
255                 wgpu::AdapterProperties properties;
256                 adapter.GetProperties(&properties);
257 
258                 EXPECT_TRUE(properties.backendType == wgpu::BackendType::Metal ||
259                             properties.backendType == wgpu::BackendType::Vulkan);
260                 if (properties.backendType == wgpu::BackendType::Metal) {
261                     metalAdapterCount2++;
262                 }
263             }
264             EXPECT_EQ(metalAdapterCount, metalAdapterCount2);
265         }
266     }
267 #endif  // defined(DAWN_ENABLE_BACKEND_VULKAN) && defined(DAWN_ENABLE_BACKEND_METAL)
268 
269 }  // anonymous namespace
270