1 // Copyright 2020 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/Log.h"
16 #include "common/Platform.h"
17 #include "dawn/dawn_proc.h"
18 #include "dawn_native/DawnNative.h"
19 #include "tests/DawnTest.h"
20 #include "utils/GLFWUtils.h"
21
22 #include <gtest/gtest.h>
23
24 #include <cstdlib>
25
26 // Include windows.h before GLFW so GLFW's APIENTRY macro doesn't conflict with windows.h's.
27 #if defined(DAWN_PLATFORM_WINDOWS)
28 # include "common/windows_with_undefs.h"
29 #endif // defined(DAWN_PLATFORM_WINDOWS)
30
31 #include "GLFW/glfw3.h"
32
33 #if defined(DAWN_USE_X11)
34 # include "common/xlib_with_undefs.h"
35 #endif // defined(DAWN_USE_X11)
36
37 #if defined(DAWN_ENABLE_BACKEND_METAL)
38 # include "utils/ObjCUtils.h"
39 #endif // defined(DAWN_ENABLE_BACKEND_METAL)
40
41 #include "GLFW/glfw3native.h"
42
43 // Test for wgpu::Surface creation that only need an instance (no devices) and don't need all the
44 // complexity of DawnTest.
45 class WindowSurfaceInstanceTests : public testing::Test {
46 public:
SetUp()47 void SetUp() override {
48 glfwSetErrorCallback([](int code, const char* message) {
49 dawn::ErrorLog() << "GLFW error " << code << " " << message;
50 });
51 DAWN_TEST_UNSUPPORTED_IF(!glfwInit());
52
53 dawnProcSetProcs(&dawn_native::GetProcs());
54
55 mInstance = wgpu::CreateInstance();
56 }
57
TearDown()58 void TearDown() override {
59 if (mWindow != nullptr) {
60 glfwDestroyWindow(mWindow);
61 mWindow = nullptr;
62 }
63 }
64
AssertSurfaceCreation(const wgpu::SurfaceDescriptor * descriptor,bool succeeds)65 void AssertSurfaceCreation(const wgpu::SurfaceDescriptor* descriptor, bool succeeds) {
66 ASSERT_EQ(mInstance.CreateSurface(descriptor).Get() != nullptr, succeeds);
67 }
68
CreateWindow()69 GLFWwindow* CreateWindow() {
70 // The WindowSurfaceInstance tests don't create devices so we don't need to call
71 // SetupGLFWWindowHintsForBackend. Set GLFW_NO_API anyway to avoid GLFW bringing up a GL
72 // context that we won't use.
73 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
74 mWindow = glfwCreateWindow(400, 400, "WindowSurfaceInstanceTests window", nullptr, nullptr);
75 return mWindow;
76 }
77
78 private:
79 wgpu::Instance mInstance;
80 GLFWwindow* mWindow = nullptr;
81 };
82
83 // Test that a valid chained descriptor works (and that GLFWUtils creates a valid chained
84 // descriptor).
TEST_F(WindowSurfaceInstanceTests,ControlCase)85 TEST_F(WindowSurfaceInstanceTests, ControlCase) {
86 GLFWwindow* window = CreateWindow();
87 std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
88 utils::SetupWindowAndGetSurfaceDescriptorForTesting(window);
89
90 wgpu::SurfaceDescriptor descriptor;
91 descriptor.nextInChain = chainedDescriptor.get();
92
93 AssertSurfaceCreation(&descriptor, true);
94 }
95
96 // Test that just wgpu::SurfaceDescriptor isn't enough and needs a chained descriptor.
TEST_F(WindowSurfaceInstanceTests,NoChainedDescriptors)97 TEST_F(WindowSurfaceInstanceTests, NoChainedDescriptors) {
98 wgpu::SurfaceDescriptor descriptor;
99 descriptor.nextInChain = nullptr; // That's the default value but we set it for clarity.
100
101 AssertSurfaceCreation(&descriptor, false);
102 }
103
104 // Test that a chained descriptor with a garbage sType produces an error.
TEST_F(WindowSurfaceInstanceTests,BadChainedDescriptors)105 TEST_F(WindowSurfaceInstanceTests, BadChainedDescriptors) {
106 wgpu::ChainedStruct chainedDescriptor;
107 chainedDescriptor.sType = wgpu::SType::Invalid; // The default but we set it for clarity.
108
109 wgpu::SurfaceDescriptor descriptor;
110 descriptor.nextInChain = &chainedDescriptor;
111
112 AssertSurfaceCreation(&descriptor, false);
113 }
114
115 // Test that a chained descriptor with HTMLCanvas produces an error.
TEST_F(WindowSurfaceInstanceTests,HTMLCanvasDescriptor)116 TEST_F(WindowSurfaceInstanceTests, HTMLCanvasDescriptor) {
117 wgpu::SurfaceDescriptorFromCanvasHTMLSelector chainedDescriptor;
118 chainedDescriptor.selector = "#myCanvas";
119
120 wgpu::SurfaceDescriptor descriptor;
121 descriptor.nextInChain = &chainedDescriptor;
122
123 AssertSurfaceCreation(&descriptor, false);
124 }
125
126 // Test that it is invalid to give two valid chained descriptors
TEST_F(WindowSurfaceInstanceTests,TwoChainedDescriptors)127 TEST_F(WindowSurfaceInstanceTests, TwoChainedDescriptors) {
128 GLFWwindow* window = CreateWindow();
129 std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor1 =
130 utils::SetupWindowAndGetSurfaceDescriptorForTesting(window);
131 std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor2 =
132 utils::SetupWindowAndGetSurfaceDescriptorForTesting(window);
133
134 wgpu::SurfaceDescriptor descriptor;
135 descriptor.nextInChain = chainedDescriptor1.get();
136 chainedDescriptor1->nextInChain = chainedDescriptor2.get();
137
138 AssertSurfaceCreation(&descriptor, false);
139 }
140
141 #if defined(DAWN_PLATFORM_WINDOWS)
142
143 // Tests that GLFWUtils returns a descriptor of HWND type
TEST_F(WindowSurfaceInstanceTests,CorrectSTypeHWND)144 TEST_F(WindowSurfaceInstanceTests, CorrectSTypeHWND) {
145 GLFWwindow* window = CreateWindow();
146 std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
147 utils::SetupWindowAndGetSurfaceDescriptorForTesting(window);
148 ASSERT_EQ(chainedDescriptor->sType, wgpu::SType::SurfaceDescriptorFromWindowsHWND);
149 }
150
151 // Test with setting an invalid hwnd
TEST_F(WindowSurfaceInstanceTests,InvalidHWND)152 TEST_F(WindowSurfaceInstanceTests, InvalidHWND) {
153 wgpu::SurfaceDescriptorFromWindowsHWND chainedDescriptor;
154 chainedDescriptor.hinstance = GetModuleHandle(nullptr);
155 chainedDescriptor.hwnd = 0; // This always is an invalid HWND value.
156
157 wgpu::SurfaceDescriptor descriptor;
158 descriptor.nextInChain = &chainedDescriptor;
159 AssertSurfaceCreation(&descriptor, false);
160 }
161
162 #else // defined(DAWN_PLATFORM_WINDOWS)
163
164 // Test using HWND when it is not supported
TEST_F(WindowSurfaceInstanceTests,HWNDSurfacesAreInvalid)165 TEST_F(WindowSurfaceInstanceTests, HWNDSurfacesAreInvalid) {
166 wgpu::SurfaceDescriptorFromWindowsHWND chainedDescriptor;
167 chainedDescriptor.hinstance = nullptr;
168 chainedDescriptor.hwnd = 0;
169
170 wgpu::SurfaceDescriptor descriptor;
171 descriptor.nextInChain = &chainedDescriptor;
172 AssertSurfaceCreation(&descriptor, false);
173 }
174
175 #endif // defined(DAWN_PLATFORM_WINDOWS)
176
177 #if defined(DAWN_USE_X11)
178
179 // Tests that GLFWUtils returns a descriptor of Xlib type
TEST_F(WindowSurfaceInstanceTests,CorrectSTypeXlib)180 TEST_F(WindowSurfaceInstanceTests, CorrectSTypeXlib) {
181 GLFWwindow* window = CreateWindow();
182 std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
183 utils::SetupWindowAndGetSurfaceDescriptorForTesting(window);
184 ASSERT_EQ(chainedDescriptor->sType, wgpu::SType::SurfaceDescriptorFromXlib);
185 }
186
187 // Test with setting an invalid window
TEST_F(WindowSurfaceInstanceTests,InvalidXWindow)188 TEST_F(WindowSurfaceInstanceTests, InvalidXWindow) {
189 wgpu::SurfaceDescriptorFromXlib chainedDescriptor;
190 chainedDescriptor.display = XOpenDisplay(nullptr);
191 // From the "X Window System Protocol" "X Version 11, Release 6.8" page 2 at
192 // https://www.x.org/releases/X11R7.5/doc/x11proto/proto.pdf
193 // WINDOW 32-bit value (top three bits guaranteed to be zero.
194 // So UINT32_MAX should be an invalid window.
195 chainedDescriptor.window = 0xFFFFFFFF;
196
197 wgpu::SurfaceDescriptor descriptor;
198 descriptor.nextInChain = &chainedDescriptor;
199 AssertSurfaceCreation(&descriptor, false);
200 }
201
202 #else // defined(DAWN_USE_X11)
203
204 // Test using Xlib when it is not supported
TEST_F(WindowSurfaceInstanceTests,XlibSurfacesAreInvalid)205 TEST_F(WindowSurfaceInstanceTests, XlibSurfacesAreInvalid) {
206 wgpu::SurfaceDescriptorFromXlib chainedDescriptor;
207 chainedDescriptor.display = nullptr;
208 chainedDescriptor.window = 0;
209
210 wgpu::SurfaceDescriptor descriptor;
211 descriptor.nextInChain = &chainedDescriptor;
212 AssertSurfaceCreation(&descriptor, false);
213 }
214
215 #endif // defined(DAWN_USE_X11)
216
217 #if defined(DAWN_ENABLE_BACKEND_METAL)
218
219 // Tests that GLFWUtils returns a descriptor of Metal type
TEST_F(WindowSurfaceInstanceTests,CorrectSTypeMetal)220 TEST_F(WindowSurfaceInstanceTests, CorrectSTypeMetal) {
221 GLFWwindow* window = CreateWindow();
222 std::unique_ptr<wgpu::ChainedStruct> chainedDescriptor =
223 utils::SetupWindowAndGetSurfaceDescriptorForTesting(window);
224 ASSERT_EQ(chainedDescriptor->sType, wgpu::SType::SurfaceDescriptorFromMetalLayer);
225 }
226
227 // Test with setting an invalid layer
TEST_F(WindowSurfaceInstanceTests,InvalidMetalLayer)228 TEST_F(WindowSurfaceInstanceTests, InvalidMetalLayer) {
229 wgpu::SurfaceDescriptorFromMetalLayer chainedDescriptor;
230 // The CALayer is autoreleased. Releasing it causes a test failure when the Chromium GTest
231 // autoreleasepool is emptied.
232 chainedDescriptor.layer = utils::CreateDummyCALayer();
233
234 wgpu::SurfaceDescriptor descriptor;
235 descriptor.nextInChain = &chainedDescriptor;
236 AssertSurfaceCreation(&descriptor, false);
237 }
238
239 #else // defined(DAWN_ENABLE_BACKEND_METAL)
240
241 // Test using Metal when it is not supported
TEST_F(WindowSurfaceInstanceTests,MetalSurfacesAreInvalid)242 TEST_F(WindowSurfaceInstanceTests, MetalSurfacesAreInvalid) {
243 wgpu::SurfaceDescriptorFromMetalLayer chainedDescriptor;
244 chainedDescriptor.layer = nullptr;
245
246 wgpu::SurfaceDescriptor descriptor;
247 descriptor.nextInChain = &chainedDescriptor;
248 AssertSurfaceCreation(&descriptor, false);
249 }
250
251 #endif // defined(DAWN_ENABLE_BACKEND_METAL)
252