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 <unknwn.h>
28 #include <GL/gl.h>
29
30 #undef GetMessage
31
32 class window
33 {
34 public:
35 window(UINT width = 64, UINT height = 64);
36 ~window();
37
get_hwnd() const38 HWND get_hwnd() const { return _window; };
get_hdc() const39 HDC get_hdc() const { return _hdc; };
valid() const40 bool valid() const { return _window && _hdc && _hglrc; }
show()41 void show() {
42 ShowWindow(_window, SW_SHOW);
43 }
44
45 void recreate_attribs(const int *attribList);
46
47 private:
48 HWND _window = nullptr;
49 HDC _hdc = nullptr;
50 HGLRC _hglrc = nullptr;
51 };
52
window(uint32_t width,uint32_t height)53 window::window(uint32_t width, uint32_t height)
54 {
55 _window = CreateWindowW(
56 L"STATIC",
57 L"OpenGLTestWindow",
58 WS_OVERLAPPEDWINDOW,
59 0,
60 0,
61 width,
62 height,
63 NULL,
64 NULL,
65 NULL,
66 NULL
67 );
68
69 if (_window == nullptr)
70 return;
71
72 _hdc = ::GetDC(_window);
73
74 putenv("D3D12_DEBUG=singleton,debuglayer");
75
76 PIXELFORMATDESCRIPTOR pfd = {
77 sizeof(PIXELFORMATDESCRIPTOR), /* size */
78 1, /* version */
79 PFD_SUPPORT_OPENGL |
80 PFD_DRAW_TO_WINDOW |
81 PFD_DOUBLEBUFFER, /* support double-buffering */
82 PFD_TYPE_RGBA, /* color type */
83 32, /* prefered color depth */
84 0, 0, 0, 0, 0, 0, /* color bits (ignored) */
85 0, /* no alpha buffer */
86 0, /* alpha bits (ignored) */
87 0, /* no accumulation buffer */
88 0, 0, 0, 0, /* accum bits (ignored) */
89 32, /* depth buffer */
90 0, /* no stencil buffer */
91 0, /* no auxiliary buffers */
92 PFD_MAIN_PLANE, /* main layer */
93 0, /* reserved */
94 0, 0, 0, /* no layer, visible, damage masks */
95 };
96 int pixel_format = ChoosePixelFormat(_hdc, &pfd);
97 if (pixel_format == 0)
98 return;
99 if (!SetPixelFormat(_hdc, pixel_format, &pfd))
100 return;
101
102 _hglrc = wglCreateContext(_hdc);
103 if (!_hglrc)
104 return;
105
106 wglMakeCurrent(_hdc, _hglrc);
107 }
108
recreate_attribs(const int * attribs)109 void window::recreate_attribs(const int *attribs)
110 {
111 using pwglCreateContextAttribsARB = HGLRC(WINAPI*)(HDC, HGLRC, const int *);
112 auto wglCreateContextAttribsARB = (pwglCreateContextAttribsARB)wglGetProcAddress("wglCreateContextAttribsARB");
113 if (!wglCreateContextAttribsARB)
114 GTEST_FAIL() << "failed to get wglCreateContextAttribsARB";
115
116 wglMakeCurrent(nullptr, nullptr);
117 wglDeleteContext(_hglrc);
118 _hglrc = wglCreateContextAttribsARB(_hdc, nullptr, attribs);
119 if (!_hglrc)
120 return;
121
122 wglMakeCurrent(_hdc, _hglrc);
123 }
124
~window()125 window::~window()
126 {
127 if (_hglrc) {
128 wglMakeCurrent(NULL, NULL);
129 wglDeleteContext(_hglrc);
130 }
131 if (_hdc)
132 ReleaseDC(_window, _hdc);
133 if (_window)
134 DestroyWindow(_window);
135 }
136
TEST(wgl,basic_create)137 TEST(wgl, basic_create)
138 {
139 window wnd;
140 ASSERT_TRUE(wnd.valid());
141
142 const char *version = (const char *)glGetString(GL_VERSION);
143 ASSERT_NE(strstr(version, "Mesa"), nullptr);
144 }
145
146 #ifdef GALLIUM_D3D12
147 /* Fixture for tests for the d3d12 backend. Will be skipped if
148 * the environment isn't set up to run them.
149 */
150 #include <directx/d3d12.h>
151 #include <dxguids/dxguids.h>
152 #include <wrl/client.h>
153 #include <memory>
154 using Microsoft::WRL::ComPtr;
155
156 class d3d12 : public ::testing::Test
157 {
158 void SetUp() override;
159 };
160
SetUp()161 void d3d12::SetUp()
162 {
163 window wnd;
164 ASSERT_TRUE(wnd.valid());
165
166 const char *renderer = (const char *)glGetString(GL_RENDERER);
167 if (!strstr(renderer, "D3D12"))
168 GTEST_SKIP();
169 }
170
171 static bool
info_queue_has_swapchain(ID3D12DebugDevice * debug_device,ID3D12InfoQueue * info_queue)172 info_queue_has_swapchain(ID3D12DebugDevice *debug_device, ID3D12InfoQueue *info_queue)
173 {
174 info_queue->PushEmptyStorageFilter();
175
176 debug_device->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL);
177
178 uint32_t num_messages = info_queue->GetNumStoredMessages();
179 for (uint32_t i = 0; i < num_messages; ++i) {
180 SIZE_T message_size = 0;
181 info_queue->GetMessage(i, nullptr, &message_size);
182 EXPECT_GT(message_size, 0);
183
184 std::unique_ptr<byte[]> message_bytes(new byte[message_size]);
185 D3D12_MESSAGE *message = (D3D12_MESSAGE *)message_bytes.get();
186 info_queue->GetMessage(i, message, &message_size);
187
188 if (strstr(message->pDescription, "SwapChain")) {
189 info_queue->ClearStoredMessages();
190 info_queue->PopStorageFilter();
191 return true;
192 }
193 }
194 info_queue->ClearStoredMessages();
195 info_queue->PopStorageFilter();
196 return false;
197 }
198
TEST_F(d3d12,swapchain_cleanup)199 TEST_F(d3d12, swapchain_cleanup)
200 {
201 ComPtr<ID3D12InfoQueue> info_queue;
202 ComPtr<ID3D12DebugDevice> debug_device;
203 if (FAILED(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&info_queue))) ||
204 FAILED(info_queue.As(&debug_device)))
205 GTEST_SKIP();
206
207 ASSERT_FALSE(info_queue_has_swapchain(debug_device.Get(), info_queue.Get()));
208
209 {
210 window wnd;
211 wnd.show();
212 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
213 glClear(GL_COLOR_BUFFER_BIT);
214 SwapBuffers(wnd.get_hdc());
215
216 ASSERT_TRUE(info_queue_has_swapchain(debug_device.Get(), info_queue.Get()));
217 }
218
219 ASSERT_FALSE(info_queue_has_swapchain(debug_device.Get(), info_queue.Get()));
220 }
221
222 #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
223 #define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
224 using pglGetGraphicsResetStatusARB = GLenum(APIENTRY*)();
TEST_F(d3d12,context_reset)225 TEST_F(d3d12, context_reset)
226 {
227 ComPtr<ID3D12Device5> device;
228 if (FAILED(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&device))))
229 GTEST_SKIP();
230
231 const int attribs[] = { WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, WGL_LOSE_CONTEXT_ON_RESET_ARB, 0 };
232
233 {
234 window wnd;
235 wnd.recreate_attribs(attribs);
236 EXPECT_TRUE(wnd.valid());
237
238 wnd.show();
239 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
240 glClear(GL_COLOR_BUFFER_BIT);
241 SwapBuffers(wnd.get_hdc());
242
243 auto glGetGraphicsResetStatusARB = (pglGetGraphicsResetStatusARB)wglGetProcAddress("glGetGraphicsResetStatusARB");
244 if (!glGetGraphicsResetStatusARB)
245 GTEST_FAIL() << "Couldn't get reset function";
246
247 EXPECT_EQ(glGetGraphicsResetStatusARB(), NO_ERROR);
248
249 device->RemoveDevice();
250 device.Reset();
251
252 EXPECT_NE(glGetGraphicsResetStatusARB(), NO_ERROR);
253 }
254
255 {
256 window wnd;
257 EXPECT_TRUE(wnd.valid());
258
259 wnd.recreate_attribs(attribs);
260 EXPECT_TRUE(wnd.valid());
261
262 wnd.show();
263 auto glGetGraphicsResetStatusARB = (pglGetGraphicsResetStatusARB)wglGetProcAddress("glGetGraphicsResetStatusARB");
264 EXPECT_EQ(glGetGraphicsResetStatusARB(), NO_ERROR);
265
266 glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
267 glClear(GL_COLOR_BUFFER_BIT);
268 SwapBuffers(wnd.get_hdc());
269 }
270 }
271 #endif
272