1 /*
2 * Copyright © Microsoft Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <gtest/gtest.h>
25
26 #include <windows.h>
27 #include <GL/gl.h>
28
29 #undef GetMessage
30
31 class window
32 {
33 public:
34 window(UINT width = 64, UINT height = 64);
35 ~window();
36
get_hwnd() const37 HWND get_hwnd() const { return _window; };
get_hdc() const38 HDC get_hdc() const { return _hdc; };
valid() const39 bool valid() const { return _window && _hdc && _hglrc; }
show()40 void show() {
41 ShowWindow(_window, SW_SHOW);
42 }
43
44 void recreate_attribs(const int *attribList);
45
46 private:
47 HWND _window = nullptr;
48 HDC _hdc = nullptr;
49 HGLRC _hglrc = nullptr;
50 };
51
window(uint32_t width,uint32_t height)52 window::window(uint32_t width, uint32_t height)
53 {
54 _window = CreateWindowW(
55 L"STATIC",
56 L"OpenGLTestWindow",
57 WS_OVERLAPPEDWINDOW,
58 0,
59 0,
60 width,
61 height,
62 NULL,
63 NULL,
64 NULL,
65 NULL
66 );
67
68 if (_window == nullptr)
69 return;
70
71 _hdc = ::GetDC(_window);
72
73 PIXELFORMATDESCRIPTOR pfd = {
74 sizeof(PIXELFORMATDESCRIPTOR), /* size */
75 1, /* version */
76 PFD_SUPPORT_OPENGL |
77 PFD_DRAW_TO_WINDOW |
78 PFD_DOUBLEBUFFER, /* support double-buffering */
79 PFD_TYPE_RGBA, /* color type */
80 8, /* prefered color depth */
81 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
82 0, /* no alpha buffer */
83 0, /* alpha bits (ignored) */
84 0, /* no accumulation buffer */
85 0, 0, 0, 0, /* accum bits (ignored) */
86 32, /* depth buffer */
87 0, /* no stencil buffer */
88 0, /* no auxiliary buffers */
89 PFD_MAIN_PLANE, /* main layer */
90 0, /* reserved */
91 0, 0, 0, /* no layer, visible, damage masks */
92 };
93 int pixel_format = ChoosePixelFormat(_hdc, &pfd);
94 if (pixel_format == 0)
95 return;
96 if (!SetPixelFormat(_hdc, pixel_format, &pfd))
97 return;
98
99 _hglrc = wglCreateContext(_hdc);
100 if (!_hglrc)
101 return;
102
103 wglMakeCurrent(_hdc, _hglrc);
104 }
105
recreate_attribs(const int * attribs)106 void window::recreate_attribs(const int *attribs)
107 {
108 using pwglCreateContextAttribsARB = HGLRC(WINAPI*)(HDC, HGLRC, const int *);
109 auto wglCreateContextAttribsARB = (pwglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB");
110 if (!wglCreateContextAttribsARB)
111 GTEST_FAIL() << "failed to get wglCreateContextAttribsARB";
112
113 wglMakeCurrent(nullptr, nullptr);
114 wglDeleteContext(_hglrc);
115 _hglrc = wglCreateContextAttribsARB(_hdc, nullptr, attribs);
116 if (!_hglrc)
117 return;
118
119 wglMakeCurrent(_hdc, _hglrc);
120 }
121
~window()122 window::~window()
123 {
124 if (_hglrc) {
125 wglMakeCurrent(NULL, NULL);
126 wglDeleteContext(_hglrc);
127 }
128 if (_hdc)
129 ReleaseDC(_window, _hdc);
130 if (_window)
131 DestroyWindow(_window);
132 }
133
TEST(wgl,basic_create)134 TEST(wgl, basic_create)
135 {
136 window wnd;
137 ASSERT_TRUE(wnd.valid());
138
139 const char *version = (const char *)glGetString(GL_VERSION);
140 ASSERT_NE(strstr(version, "Mesa"), nullptr);
141 }
142
143 #ifdef GALLIUM_D3D12
144 /* Fixture for tests for the d3d12 backend. Will be skipped if
145 * the environment isn't set up to run them.
146 */
147 #include <directx/d3d12.h>
148 #include <dxguids/dxguids.h>
149 #include <wrl/client.h>
150 #include <memory>
151 using Microsoft::WRL::ComPtr;
152
153 class d3d12 : public ::testing::Test
154 {
155 void SetUp() override;
156 };
157
SetUp()158 void d3d12::SetUp()
159 {
160 window wnd;
161 ASSERT_TRUE(wnd.valid());
162
163 const char *renderer = (const char *)glGetString(GL_RENDERER);
164 if (!strstr(renderer, "D3D12"))
165 GTEST_SKIP();
166 }
167
168 static bool
info_queue_has_swapchain(ID3D12DebugDevice * debug_device,ID3D12InfoQueue * info_queue)169 info_queue_has_swapchain(ID3D12DebugDevice *debug_device, ID3D12InfoQueue *info_queue)
170 {
171 info_queue->PushEmptyStorageFilter();
172
173 debug_device->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL);
174
175 uint32_t num_messages = info_queue->GetNumStoredMessages();
176 for (uint32_t i = 0; i < num_messages; ++i) {
177 SIZE_T message_size = 0;
178 info_queue->GetMessage(i, nullptr, &message_size);
179 EXPECT_GT(message_size, 0);
180
181 std::unique_ptr<byte[]> message_bytes(new byte[message_size]);
182 D3D12_MESSAGE *message = (D3D12_MESSAGE *)message_bytes.get();
183 info_queue->GetMessage(i, message, &message_size);
184
185 if (strstr(message->pDescription, "SwapChain")) {
186 info_queue->ClearStoredMessages();
187 info_queue->PopStorageFilter();
188 return true;
189 }
190 }
191 info_queue->ClearStoredMessages();
192 info_queue->PopStorageFilter();
193 return false;
194 }
195
TEST_F(d3d12,swapchain_cleanup)196 TEST_F(d3d12, swapchain_cleanup)
197 {
198 ComPtr<ID3D12InfoQueue> info_queue;
199 ComPtr<ID3D12DebugDevice> debug_device;
200 if (FAILED(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&info_queue))) ||
201 FAILED(info_queue.As(&debug_device)))
202 GTEST_SKIP();
203
204 ASSERT_FALSE(info_queue_has_swapchain(debug_device.Get(), info_queue.Get()));
205
206 {
207 window wnd;
208 wnd.show();
209 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
210 glClear(GL_COLOR_BUFFER_BIT);
211 SwapBuffers(wnd.get_hdc());
212
213 ASSERT_TRUE(info_queue_has_swapchain(debug_device.Get(), info_queue.Get()));
214 }
215
216 ASSERT_FALSE(info_queue_has_swapchain(debug_device.Get(), info_queue.Get()));
217 }
218
219 #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
220 #define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
221 using pglGetGraphicsResetStatusARB = GLenum(APIENTRY*)();
TEST_F(d3d12,context_reset)222 TEST_F(d3d12, context_reset)
223 {
224 ComPtr<ID3D12Device5> device;
225 if (FAILED(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device))))
226 GTEST_SKIP();
227
228 const int attribs[] = { WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, WGL_LOSE_CONTEXT_ON_RESET_ARB, 0 };
229
230 {
231 window wnd;
232 wnd.recreate_attribs(attribs);
233 EXPECT_TRUE(wnd.valid());
234
235 wnd.show();
236 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
237 glClear(GL_COLOR_BUFFER_BIT);
238 SwapBuffers(wnd.get_hdc());
239
240 auto glGetGraphicsResetStatusARB = (pglGetGraphicsResetStatusARB)wglGetProcAddress("glGetGraphicsResetStatusARB");
241 if (!glGetGraphicsResetStatusARB)
242 GTEST_FAIL() << "Couldn't get reset function";
243
244 EXPECT_EQ(glGetGraphicsResetStatusARB(), NO_ERROR);
245
246 device->RemoveDevice();
247 device.Reset();
248
249 EXPECT_NE(glGetGraphicsResetStatusARB(), NO_ERROR);
250 }
251
252 {
253 window wnd;
254 EXPECT_TRUE(wnd.valid());
255
256 wnd.recreate_attribs(attribs);
257 EXPECT_TRUE(wnd.valid());
258
259 wnd.show();
260 auto glGetGraphicsResetStatusARB = (pglGetGraphicsResetStatusARB)wglGetProcAddress("glGetGraphicsResetStatusARB");
261 EXPECT_EQ(glGetGraphicsResetStatusARB(), NO_ERROR);
262
263 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
264 glClear(GL_COLOR_BUFFER_BIT);
265 SwapBuffers(wnd.get_hdc());
266 }
267 }
268 #endif
269