xref: /aosp_15_r20/external/deqp/framework/platform/win32/tcuWin32EGLNativeDisplayFactory.cpp (revision 35238bce31c2a825756842865a792f8cf7f89930)
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Tester Core
3  * ----------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Win32 EGL native display factory
22  *//*--------------------------------------------------------------------*/
23 
24 #include "tcuWin32EGLNativeDisplayFactory.hpp"
25 
26 #include "egluDefs.hpp"
27 #include "tcuWin32Window.hpp"
28 #include "tcuWin32API.h"
29 #include "tcuTexture.hpp"
30 #include "deMemory.h"
31 #include "deThread.h"
32 #include "deClock.h"
33 #include "eglwLibrary.hpp"
34 #include "eglwEnums.hpp"
35 
36 // Assume no call translation is needed
37 DE_STATIC_ASSERT(sizeof(eglw::EGLNativeDisplayType) == sizeof(HDC));
38 DE_STATIC_ASSERT(sizeof(eglw::EGLNativePixmapType) == sizeof(HBITMAP));
39 DE_STATIC_ASSERT(sizeof(eglw::EGLNativeWindowType) == sizeof(HWND));
40 
41 namespace tcu
42 {
43 namespace win32
44 {
45 namespace
46 {
47 
48 using namespace eglw;
49 
50 enum
51 {
52     DEFAULT_SURFACE_WIDTH  = 400,
53     DEFAULT_SURFACE_HEIGHT = 300,
54     WAIT_WINDOW_VISIBLE_MS =
55         500 //!< Time to wait before issuing screenshot after changing window visibility (hack for DWM)
56 };
57 
58 static const eglu::NativeDisplay::Capability DISPLAY_CAPABILITIES = eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY;
59 static const eglu::NativePixmap::Capability BITMAP_CAPABILITIES = eglu::NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY;
60 static const eglu::NativeWindow::Capability WINDOW_CAPABILITIES = (eglu::NativeWindow::Capability)(
61     eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY | eglu::NativeWindow::CAPABILITY_GET_SURFACE_SIZE |
62     eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE | eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS |
63     eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE | eglu::NativeWindow::CAPABILITY_CHANGE_VISIBILITY);
64 
65 class NativeDisplay : public eglu::NativeDisplay
66 {
67 public:
68     NativeDisplay(void);
~NativeDisplay(void)69     virtual ~NativeDisplay(void)
70     {
71     }
72 
getLegacyNative(void)73     virtual EGLNativeDisplayType getLegacyNative(void)
74     {
75         return m_deviceContext;
76     }
getLibrary(void) const77     const eglw::Library &getLibrary(void) const
78     {
79         return m_library;
80     }
81 
getDeviceContext(void)82     HDC getDeviceContext(void)
83     {
84         return m_deviceContext;
85     }
86 
87 private:
88     HDC m_deviceContext;
89     eglw::DefaultLibrary m_library;
90 };
91 
92 class NativePixmapFactory : public eglu::NativePixmapFactory
93 {
94 public:
95     NativePixmapFactory(void);
~NativePixmapFactory(void)96     ~NativePixmapFactory(void)
97     {
98     }
99 
100     virtual eglu::NativePixmap *createPixmap(eglu::NativeDisplay *nativeDisplay, int width, int height) const;
101     virtual eglu::NativePixmap *createPixmap(eglu::NativeDisplay *nativeDisplay, EGLDisplay display, EGLConfig config,
102                                              const EGLAttrib *attribList, int width, int height) const;
103 };
104 
105 class NativePixmap : public eglu::NativePixmap
106 {
107 public:
108     NativePixmap(NativeDisplay *nativeDisplay, int width, int height, int bitDepth);
109     virtual ~NativePixmap(void);
110 
getLegacyNative(void)111     EGLNativePixmapType getLegacyNative(void)
112     {
113         return m_bitmap;
114     }
115 
116 private:
117     HBITMAP m_bitmap;
118 };
119 
120 class NativeWindowFactory : public eglu::NativeWindowFactory
121 {
122 public:
123     NativeWindowFactory(HINSTANCE instance);
~NativeWindowFactory(void)124     virtual ~NativeWindowFactory(void)
125     {
126     }
127 
128     virtual eglu::NativeWindow *createWindow(eglu::NativeDisplay *nativeDisplay,
129                                              const eglu::WindowParams &params) const;
130 
131 private:
132     const HINSTANCE m_instance;
133 };
134 
135 class NativeWindow : public eglu::NativeWindow
136 {
137 public:
138     NativeWindow(NativeDisplay *nativeDisplay, HINSTANCE instance, const eglu::WindowParams &params);
139     virtual ~NativeWindow(void);
140 
getLegacyNative(void)141     EGLNativeWindowType getLegacyNative(void)
142     {
143         return m_window.getHandle();
144     }
145     virtual IVec2 getSurfaceSize(void) const;
getScreenSize(void) const146     virtual IVec2 getScreenSize(void) const
147     {
148         return getSurfaceSize();
149     }
150     virtual void processEvents(void);
151     virtual void setSurfaceSize(IVec2 size);
152     virtual void setVisibility(eglu::WindowParams::Visibility visibility);
153     virtual void readScreenPixels(tcu::TextureLevel *dst) const;
154 
155 private:
156     win32::Window m_window;
157     eglu::WindowParams::Visibility m_curVisibility;
158     uint64_t m_setVisibleTime; //!< Time window was set visible.
159 };
160 
161 // NativeDisplay
162 
NativeDisplay(void)163 NativeDisplay::NativeDisplay(void)
164     : eglu::NativeDisplay(DISPLAY_CAPABILITIES)
165     , m_deviceContext((HDC)EGL_DEFAULT_DISPLAY)
166     , m_library("libEGL.dll")
167 {
168 }
169 
170 // NativePixmap
171 
NativePixmap(NativeDisplay * nativeDisplay,int width,int height,int bitDepth)172 NativePixmap::NativePixmap(NativeDisplay *nativeDisplay, int width, int height, int bitDepth)
173     : eglu::NativePixmap(BITMAP_CAPABILITIES)
174     , m_bitmap(DE_NULL)
175 {
176     const HDC deviceCtx = nativeDisplay->getDeviceContext();
177     BITMAPINFO bitmapInfo;
178 
179     memset(&bitmapInfo, 0, sizeof(bitmapInfo));
180 
181     if (bitDepth != 24 && bitDepth != 32)
182         throw NotSupportedError("Unsupported pixmap bit depth", DE_NULL, __FILE__, __LINE__);
183 
184     bitmapInfo.bmiHeader.biSize          = sizeof(bitmapInfo);
185     bitmapInfo.bmiHeader.biWidth         = width;
186     bitmapInfo.bmiHeader.biHeight        = height;
187     bitmapInfo.bmiHeader.biPlanes        = 1;
188     bitmapInfo.bmiHeader.biBitCount      = bitDepth;
189     bitmapInfo.bmiHeader.biCompression   = BI_RGB;
190     bitmapInfo.bmiHeader.biSizeImage     = 0;
191     bitmapInfo.bmiHeader.biXPelsPerMeter = 1;
192     bitmapInfo.bmiHeader.biYPelsPerMeter = 1;
193     bitmapInfo.bmiHeader.biClrUsed       = 0;
194     bitmapInfo.bmiHeader.biClrImportant  = 0;
195 
196     void *bitmapPtr = DE_NULL;
197     m_bitmap        = CreateDIBSection(deviceCtx, &bitmapInfo, DIB_RGB_COLORS, &bitmapPtr, NULL, 0);
198 
199     if (!m_bitmap)
200         throw ResourceError("Failed to create bitmap", DE_NULL, __FILE__, __LINE__);
201 }
202 
~NativePixmap(void)203 NativePixmap::~NativePixmap(void)
204 {
205     DeleteObject(m_bitmap);
206 }
207 
208 // NativePixmapFactory
209 
NativePixmapFactory(void)210 NativePixmapFactory::NativePixmapFactory(void)
211     : eglu::NativePixmapFactory("bitmap", "Win32 Bitmap", BITMAP_CAPABILITIES)
212 {
213 }
214 
createPixmap(eglu::NativeDisplay * nativeDisplay,EGLDisplay display,EGLConfig config,const EGLAttrib * attribList,int width,int height) const215 eglu::NativePixmap *NativePixmapFactory::createPixmap(eglu::NativeDisplay *nativeDisplay, EGLDisplay display,
216                                                       EGLConfig config, const EGLAttrib *attribList, int width,
217                                                       int height) const
218 {
219     const Library &egl = nativeDisplay->getLibrary();
220     int redBits        = 0;
221     int greenBits      = 0;
222     int blueBits       = 0;
223     int alphaBits      = 0;
224     int bitSum         = 0;
225 
226     DE_ASSERT(display != EGL_NO_DISPLAY);
227 
228     egl.getConfigAttrib(display, config, EGL_RED_SIZE, &redBits);
229     egl.getConfigAttrib(display, config, EGL_GREEN_SIZE, &greenBits);
230     egl.getConfigAttrib(display, config, EGL_BLUE_SIZE, &blueBits);
231     egl.getConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaBits);
232     EGLU_CHECK_MSG(egl, "eglGetConfigAttrib()");
233 
234     bitSum = redBits + greenBits + blueBits + alphaBits;
235 
236     return new NativePixmap(dynamic_cast<NativeDisplay *>(nativeDisplay), width, height, bitSum);
237 }
238 
createPixmap(eglu::NativeDisplay * nativeDisplay,int width,int height) const239 eglu::NativePixmap *NativePixmapFactory::createPixmap(eglu::NativeDisplay *nativeDisplay, int width, int height) const
240 {
241     const int defaultDepth = 32;
242     return new NativePixmap(dynamic_cast<NativeDisplay *>(nativeDisplay), width, height, defaultDepth);
243 }
244 
245 // NativeWindowFactory
246 
NativeWindowFactory(HINSTANCE instance)247 NativeWindowFactory::NativeWindowFactory(HINSTANCE instance)
248     : eglu::NativeWindowFactory("window", "Win32 Window", WINDOW_CAPABILITIES)
249     , m_instance(instance)
250 {
251 }
252 
createWindow(eglu::NativeDisplay * nativeDisplay,const eglu::WindowParams & params) const253 eglu::NativeWindow *NativeWindowFactory::createWindow(eglu::NativeDisplay *nativeDisplay,
254                                                       const eglu::WindowParams &params) const
255 {
256     return new NativeWindow(dynamic_cast<NativeDisplay *>(nativeDisplay), m_instance, params);
257 }
258 
259 // NativeWindow
260 
NativeWindow(NativeDisplay * nativeDisplay,HINSTANCE instance,const eglu::WindowParams & params)261 NativeWindow::NativeWindow(NativeDisplay *nativeDisplay, HINSTANCE instance, const eglu::WindowParams &params)
262     : eglu::NativeWindow(WINDOW_CAPABILITIES)
263     , m_window(instance, params.width == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_WIDTH : params.width,
264                params.height == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_HEIGHT : params.height)
265     , m_curVisibility(eglu::WindowParams::VISIBILITY_HIDDEN)
266     , m_setVisibleTime(0)
267 {
268     if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE)
269         setVisibility(params.visibility);
270 }
271 
setVisibility(eglu::WindowParams::Visibility visibility)272 void NativeWindow::setVisibility(eglu::WindowParams::Visibility visibility)
273 {
274     switch (visibility)
275     {
276     case eglu::WindowParams::VISIBILITY_HIDDEN:
277         m_window.setVisible(false);
278         m_curVisibility = visibility;
279         break;
280 
281     case eglu::WindowParams::VISIBILITY_VISIBLE:
282     case eglu::WindowParams::VISIBILITY_FULLSCREEN:
283         // \todo [2014-03-12 pyry] Implement FULLSCREEN, or at least SW_MAXIMIZE.
284         m_window.setVisible(true);
285         m_curVisibility  = eglu::WindowParams::VISIBILITY_VISIBLE;
286         m_setVisibleTime = deGetMicroseconds();
287         break;
288 
289     default:
290         DE_ASSERT(false);
291     }
292 }
293 
~NativeWindow(void)294 NativeWindow::~NativeWindow(void)
295 {
296 }
297 
getSurfaceSize(void) const298 IVec2 NativeWindow::getSurfaceSize(void) const
299 {
300     return m_window.getSize();
301 }
302 
processEvents(void)303 void NativeWindow::processEvents(void)
304 {
305     m_window.processEvents();
306 }
307 
setSurfaceSize(IVec2 size)308 void NativeWindow::setSurfaceSize(IVec2 size)
309 {
310     m_window.setSize(size.x(), size.y());
311 }
312 
readScreenPixels(tcu::TextureLevel * dst) const313 void NativeWindow::readScreenPixels(tcu::TextureLevel *dst) const
314 {
315     HDC windowDC      = DE_NULL;
316     HDC screenDC      = DE_NULL;
317     HDC tmpDC         = DE_NULL;
318     HBITMAP tmpBitmap = DE_NULL;
319     RECT rect;
320 
321     TCU_CHECK_INTERNAL(m_curVisibility != eglu::WindowParams::VISIBILITY_HIDDEN);
322 
323     // Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait
324     // for a while before issuing screenshot if window was just made visible.
325     {
326         const int64_t timeSinceVisibleUs = (int64_t)(deGetMicroseconds() - m_setVisibleTime);
327 
328         if (timeSinceVisibleUs < (int64_t)WAIT_WINDOW_VISIBLE_MS * 1000)
329             deSleep(WAIT_WINDOW_VISIBLE_MS - (uint32_t)(timeSinceVisibleUs / 1000));
330     }
331 
332     TCU_CHECK(GetClientRect(m_window.getHandle(), &rect));
333 
334     try
335     {
336         const int width  = rect.right - rect.left;
337         const int height = rect.bottom - rect.top;
338         BITMAPINFOHEADER bitmapInfo;
339 
340         deMemset(&bitmapInfo, 0, sizeof(bitmapInfo));
341 
342         screenDC = GetDC(DE_NULL);
343         TCU_CHECK(screenDC);
344 
345         windowDC = GetDC(m_window.getHandle());
346         TCU_CHECK(windowDC);
347 
348         tmpDC = CreateCompatibleDC(screenDC);
349         TCU_CHECK(tmpDC != DE_NULL);
350 
351         MapWindowPoints(m_window.getHandle(), DE_NULL, (LPPOINT)&rect, 2);
352 
353         tmpBitmap = CreateCompatibleBitmap(screenDC, width, height);
354         TCU_CHECK(tmpBitmap != DE_NULL);
355 
356         TCU_CHECK(SelectObject(tmpDC, tmpBitmap) != DE_NULL);
357 
358         TCU_CHECK(BitBlt(tmpDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY));
359 
360         bitmapInfo.biSize          = sizeof(BITMAPINFOHEADER);
361         bitmapInfo.biWidth         = width;
362         bitmapInfo.biHeight        = -height;
363         bitmapInfo.biPlanes        = 1;
364         bitmapInfo.biBitCount      = 32;
365         bitmapInfo.biCompression   = BI_RGB;
366         bitmapInfo.biSizeImage     = 0;
367         bitmapInfo.biXPelsPerMeter = 0;
368         bitmapInfo.biYPelsPerMeter = 0;
369         bitmapInfo.biClrUsed       = 0;
370         bitmapInfo.biClrImportant  = 0;
371 
372         dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8), width, height);
373 
374         TCU_CHECK(GetDIBits(screenDC, tmpBitmap, 0, height, dst->getAccess().getDataPtr(), (BITMAPINFO *)&bitmapInfo,
375                             DIB_RGB_COLORS));
376 
377         DeleteObject(tmpBitmap);
378         tmpBitmap = DE_NULL;
379 
380         ReleaseDC(DE_NULL, screenDC);
381         screenDC = DE_NULL;
382 
383         ReleaseDC(m_window.getHandle(), windowDC);
384         windowDC = DE_NULL;
385 
386         DeleteDC(tmpDC);
387         tmpDC = DE_NULL;
388     }
389     catch (...)
390     {
391         if (screenDC)
392             ReleaseDC(DE_NULL, screenDC);
393 
394         if (windowDC)
395             ReleaseDC(m_window.getHandle(), windowDC);
396 
397         if (tmpBitmap)
398             DeleteObject(tmpBitmap);
399 
400         if (tmpDC)
401             DeleteDC(tmpDC);
402 
403         throw;
404     }
405 }
406 
407 } // namespace
408 
EGLNativeDisplayFactory(HINSTANCE instance)409 EGLNativeDisplayFactory::EGLNativeDisplayFactory(HINSTANCE instance)
410     : eglu::NativeDisplayFactory("win32", "Native Win32 Display", DISPLAY_CAPABILITIES)
411     , m_instance(instance)
412 {
413     m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(m_instance));
414     m_nativePixmapRegistry.registerFactory(new NativePixmapFactory());
415 }
416 
~EGLNativeDisplayFactory(void)417 EGLNativeDisplayFactory::~EGLNativeDisplayFactory(void)
418 {
419 }
420 
createDisplay(const EGLAttrib * attribList) const421 eglu::NativeDisplay *EGLNativeDisplayFactory::createDisplay(const EGLAttrib *attribList) const
422 {
423     DE_UNREF(attribList);
424     return new NativeDisplay();
425 }
426 
427 } // namespace win32
428 } // namespace tcu
429