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