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
44private:
45   HWND _window = nullptr;
46   HDC _hdc = nullptr;
47   HGLRC _hglrc = nullptr;
48};
49
50window::window(uint32_t width, uint32_t height)
51{
52   _window = CreateWindowW(
53      L"STATIC",
54      L"OpenGLTestWindow",
55      WS_OVERLAPPEDWINDOW,
56      0,
57      0,
58      width,
59      height,
60      NULL,
61      NULL,
62      NULL,
63      NULL
64   );
65
66   if (_window == nullptr)
67      return;
68
69   _hdc = ::GetDC(_window);
70
71   PIXELFORMATDESCRIPTOR pfd = {
72       sizeof(PIXELFORMATDESCRIPTOR),  /* size */
73       1,                              /* version */
74       PFD_SUPPORT_OPENGL |
75       PFD_DRAW_TO_WINDOW |
76       PFD_DOUBLEBUFFER,               /* support double-buffering */
77       PFD_TYPE_RGBA,                  /* color type */
78       8,                              /* prefered color depth */
79       0, 0, 0, 0, 0, 0,               /* color bits (ignored) */
80       0,                              /* no alpha buffer */
81       0,                              /* alpha bits (ignored) */
82       0,                              /* no accumulation buffer */
83       0, 0, 0, 0,                     /* accum bits (ignored) */
84       32,                             /* depth buffer */
85       0,                              /* no stencil buffer */
86       0,                              /* no auxiliary buffers */
87       PFD_MAIN_PLANE,                 /* main layer */
88       0,                              /* reserved */
89       0, 0, 0,                        /* no layer, visible, damage masks */
90   };
91   int pixel_format = ChoosePixelFormat(_hdc, &pfd);
92   if (pixel_format == 0)
93      return;
94   if (!SetPixelFormat(_hdc, pixel_format, &pfd))
95      return;
96
97   _hglrc = wglCreateContext(_hdc);
98   if (!_hglrc)
99      return;
100
101   wglMakeCurrent(_hdc, _hglrc);
102}
103
104window::~window()
105{
106   if (_hglrc) {
107      wglMakeCurrent(NULL, NULL);
108      wglDeleteContext(_hglrc);
109   }
110   if (_hdc)
111      ReleaseDC(_window, _hdc);
112   if (_window)
113      DestroyWindow(_window);
114}
115
116TEST(wgl, basic_create)
117{
118   window wnd;
119   ASSERT_TRUE(wnd.valid());
120
121   const char *version = (const char *)glGetString(GL_VERSION);
122   ASSERT_NE(strstr(version, "Mesa"), nullptr);
123}
124
125#ifdef GALLIUM_D3D12
126/* Fixture for tests for the d3d12 backend. Will be skipped if
127 * the environment isn't set up to run them.
128 */
129#include <directx/d3d12.h>
130#include <wrl/client.h>
131#include <memory>
132using Microsoft::WRL::ComPtr;
133
134class d3d12 : public ::testing::Test
135{
136   void SetUp() override;
137};
138
139void d3d12::SetUp()
140{
141   window wnd;
142   ASSERT_TRUE(wnd.valid());
143
144   const char *renderer = (const char *)glGetString(GL_RENDERER);
145   if (!strstr(renderer, "D3D12"))
146      GTEST_SKIP();
147}
148
149static bool
150info_queue_has_swapchain(ID3D12DebugDevice *debug_device, ID3D12InfoQueue *info_queue)
151{
152   info_queue->PushEmptyStorageFilter();
153
154   debug_device->ReportLiveDeviceObjects(D3D12_RLDO_DETAIL);
155
156   uint32_t num_messages = info_queue->GetNumStoredMessages();
157   for (uint32_t i = 0; i < num_messages; ++i) {
158      SIZE_T message_size = 0;
159      info_queue->GetMessage(i, nullptr, &message_size);
160      EXPECT_GT(message_size, 0);
161
162      std::unique_ptr<byte[]> message_bytes(new byte[message_size]);
163      D3D12_MESSAGE *message = (D3D12_MESSAGE *)message_bytes.get();
164      info_queue->GetMessage(i, message, &message_size);
165
166      if (strstr(message->pDescription, "SwapChain")) {
167         info_queue->ClearStoredMessages();
168         info_queue->PopStorageFilter();
169         return true;
170      }
171   }
172   info_queue->ClearStoredMessages();
173   info_queue->PopStorageFilter();
174   return false;
175}
176
177TEST_F(d3d12, swapchain_cleanup)
178{
179   ComPtr<ID3D12InfoQueue> info_queue;
180   ComPtr<ID3D12DebugDevice> debug_device;
181   if (FAILED(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&info_queue))) ||
182       FAILED(info_queue.As(&debug_device)))
183      GTEST_SKIP();
184
185   ASSERT_FALSE(info_queue_has_swapchain(debug_device.Get(), info_queue.Get()));
186
187   {
188      window wnd;
189      wnd.show();
190      glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
191      glClear(GL_COLOR_BUFFER_BIT);
192      SwapBuffers(wnd.get_hdc());
193
194      ASSERT_TRUE(info_queue_has_swapchain(debug_device.Get(), info_queue.Get()));
195   }
196
197   ASSERT_FALSE(info_queue_has_swapchain(debug_device.Get(), info_queue.Get()));
198}
199#endif
200