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 31class window 32{ 33public: 34 window(UINT width = 64, UINT height = 64); 35 ~window(); 36 37 HWND get_hwnd() const { return _window; }; 38 HDC get_hdc() const { return _hdc; }; 39 bool valid() const { return _window && _hdc && _hglrc; } 40 void show() { 41 ShowWindow(_window, SW_SHOW); 42 } 43 44 void recreate_attribs(const int *attribList); 45 46private: 47 HWND _window = nullptr; 48 HDC _hdc = nullptr; 49 HGLRC _hglrc = nullptr; 50}; 51 52window::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 106void 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 122window::~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 134TEST(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> 151using Microsoft::WRL::ComPtr; 152 153class d3d12 : public ::testing::Test 154{ 155 void SetUp() override; 156}; 157 158void 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 168static bool 169info_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 196TEST_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 221using pglGetGraphicsResetStatusARB = GLenum(APIENTRY*)(); 222TEST_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