1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Tester Core
3 * ----------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Win32 EGL native display factory
22 *//*--------------------------------------------------------------------*/
24 #include "tcuWin32EGLNativeDisplayFactory.hpp"
26 #include "egluDefs.hpp"
27 #include "tcuWin32Window.hpp"
28 #include "tcuWin32API.h"
29 #include "tcuTexture.hpp"
33 #include "eglwLibrary.hpp"
34 #include "eglwEnums.hpp"
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));
52 DEFAULT_SURFACE_WIDTH = 400,
53 DEFAULT_SURFACE_HEIGHT = 300,
54 WAIT_WINDOW_VISIBLE_MS = 500 //!< Time to wait before issuing screenshot after changing window visibility (hack for DWM)
57 static const eglu::NativeDisplay::Capability DISPLAY_CAPABILITIES = eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY;
58 static const eglu::NativePixmap::Capability BITMAP_CAPABILITIES = eglu::NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY;
59 static const eglu::NativeWindow::Capability WINDOW_CAPABILITIES = (eglu::NativeWindow::Capability)
60 (eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY |
61 eglu::NativeWindow::CAPABILITY_GET_SURFACE_SIZE |
62 eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE |
63 eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS |
64 eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE |
65 eglu::NativeWindow::CAPABILITY_CHANGE_VISIBILITY);
67 class NativeDisplay : public eglu::NativeDisplay
71 virtual ~NativeDisplay (void) {}
73 virtual EGLNativeDisplayType getLegacyNative (void) { return m_deviceContext; }
74 const eglw::Library& getLibrary (void) const { return m_library; }
76 HDC getDeviceContext (void) { return m_deviceContext; }
80 eglw::DefaultLibrary m_library;
83 class NativePixmapFactory : public eglu::NativePixmapFactory
86 NativePixmapFactory (void);
87 ~NativePixmapFactory (void) {}
89 virtual eglu::NativePixmap* createPixmap (eglu::NativeDisplay* nativeDisplay, int width, int height) const;
90 virtual eglu::NativePixmap* createPixmap (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const;
93 class NativePixmap : public eglu::NativePixmap
96 NativePixmap (NativeDisplay* nativeDisplay, int width, int height, int bitDepth);
97 virtual ~NativePixmap (void);
99 EGLNativePixmapType getLegacyNative (void) { return m_bitmap; }
105 class NativeWindowFactory : public eglu::NativeWindowFactory
108 NativeWindowFactory (HINSTANCE instance);
109 virtual ~NativeWindowFactory (void) {}
111 virtual eglu::NativeWindow* createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const;
114 const HINSTANCE m_instance;
117 class NativeWindow : public eglu::NativeWindow
120 NativeWindow (NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params);
121 virtual ~NativeWindow (void);
123 EGLNativeWindowType getLegacyNative (void) { return m_window.getHandle(); }
124 virtual IVec2 getSurfaceSize (void) const;
125 virtual IVec2 getScreenSize (void) const { return getSurfaceSize(); }
126 virtual void processEvents (void);
127 virtual void setSurfaceSize (IVec2 size);
128 virtual void setVisibility (eglu::WindowParams::Visibility visibility);
129 virtual void readScreenPixels (tcu::TextureLevel* dst) const;
132 win32::Window m_window;
133 eglu::WindowParams::Visibility m_curVisibility;
134 deUint64 m_setVisibleTime; //!< Time window was set visible.
139 NativeDisplay::NativeDisplay (void)
140 : eglu::NativeDisplay (DISPLAY_CAPABILITIES)
141 , m_deviceContext ((HDC)EGL_DEFAULT_DISPLAY)
142 , m_library ("libEGL.dll")
148 NativePixmap::NativePixmap (NativeDisplay* nativeDisplay, int width, int height, int bitDepth)
149 : eglu::NativePixmap (BITMAP_CAPABILITIES)
152 const HDC deviceCtx = nativeDisplay->getDeviceContext();
153 BITMAPINFO bitmapInfo;
155 memset(&bitmapInfo, 0, sizeof(bitmapInfo));
157 if (bitDepth != 24 && bitDepth != 32)
158 throw NotSupportedError("Unsupported pixmap bit depth", DE_NULL, __FILE__, __LINE__);
160 bitmapInfo.bmiHeader.biSize = sizeof(bitmapInfo);
161 bitmapInfo.bmiHeader.biWidth = width;
162 bitmapInfo.bmiHeader.biHeight = height;
163 bitmapInfo.bmiHeader.biPlanes = 1;
164 bitmapInfo.bmiHeader.biBitCount = bitDepth;
165 bitmapInfo.bmiHeader.biCompression = BI_RGB;
166 bitmapInfo.bmiHeader.biSizeImage = 0;
167 bitmapInfo.bmiHeader.biXPelsPerMeter = 1;
168 bitmapInfo.bmiHeader.biYPelsPerMeter = 1;
169 bitmapInfo.bmiHeader.biClrUsed = 0;
170 bitmapInfo.bmiHeader.biClrImportant = 0;
172 void* bitmapPtr = DE_NULL;
173 m_bitmap = CreateDIBSection(deviceCtx, &bitmapInfo, DIB_RGB_COLORS, &bitmapPtr, NULL, 0);
176 throw ResourceError("Failed to create bitmap", DE_NULL, __FILE__, __LINE__);
179 NativePixmap::~NativePixmap (void)
181 DeleteObject(m_bitmap);
184 // NativePixmapFactory
186 NativePixmapFactory::NativePixmapFactory (void)
187 : eglu::NativePixmapFactory ("bitmap", "Win32 Bitmap", BITMAP_CAPABILITIES)
191 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const
193 const Library& egl = nativeDisplay->getLibrary();
200 DE_ASSERT(display != EGL_NO_DISPLAY);
202 egl.getConfigAttrib(display, config, EGL_RED_SIZE, &redBits);
203 egl.getConfigAttrib(display, config, EGL_GREEN_SIZE, &greenBits);
204 egl.getConfigAttrib(display, config, EGL_BLUE_SIZE, &blueBits);
205 egl.getConfigAttrib(display, config, EGL_ALPHA_SIZE, &alphaBits);
206 EGLU_CHECK_MSG(egl, "eglGetConfigAttrib()");
208 bitSum = redBits+greenBits+blueBits+alphaBits;
210 return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, bitSum);
213 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, int width, int height) const
215 const int defaultDepth = 32;
216 return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, defaultDepth);
219 // NativeWindowFactory
221 NativeWindowFactory::NativeWindowFactory (HINSTANCE instance)
222 : eglu::NativeWindowFactory ("window", "Win32 Window", WINDOW_CAPABILITIES)
223 , m_instance (instance)
227 eglu::NativeWindow* NativeWindowFactory::createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const
229 return new NativeWindow(dynamic_cast<NativeDisplay*>(nativeDisplay), m_instance, params);
234 NativeWindow::NativeWindow (NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params)
235 : eglu::NativeWindow (WINDOW_CAPABILITIES)
236 , m_window (instance,
237 params.width == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_WIDTH : params.width,
238 params.height == eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_HEIGHT : params.height)
239 , m_curVisibility (eglu::WindowParams::VISIBILITY_HIDDEN)
240 , m_setVisibleTime (0)
242 if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE)
243 setVisibility(params.visibility);
246 void NativeWindow::setVisibility (eglu::WindowParams::Visibility visibility)
250 case eglu::WindowParams::VISIBILITY_HIDDEN:
251 m_window.setVisible(false);
252 m_curVisibility = visibility;
255 case eglu::WindowParams::VISIBILITY_VISIBLE:
256 case eglu::WindowParams::VISIBILITY_FULLSCREEN:
257 // \todo [2014-03-12 pyry] Implement FULLSCREEN, or at least SW_MAXIMIZE.
258 m_window.setVisible(true);
259 m_curVisibility = eglu::WindowParams::VISIBILITY_VISIBLE;
260 m_setVisibleTime = deGetMicroseconds();
268 NativeWindow::~NativeWindow (void)
272 IVec2 NativeWindow::getSurfaceSize (void) const
274 return m_window.getSize();
277 void NativeWindow::processEvents (void)
279 m_window.processEvents();
282 void NativeWindow::setSurfaceSize (IVec2 size)
284 m_window.setSize(size.x(), size.y());
287 void NativeWindow::readScreenPixels (tcu::TextureLevel* dst) const
289 HDC windowDC = DE_NULL;
290 HDC screenDC = DE_NULL;
292 HBITMAP tmpBitmap = DE_NULL;
295 TCU_CHECK_INTERNAL(m_curVisibility != eglu::WindowParams::VISIBILITY_HIDDEN);
297 // Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait
298 // for a while before issuing screenshot if window was just made visible.
300 const deInt64 timeSinceVisibleUs = (deInt64)(deGetMicroseconds()-m_setVisibleTime);
302 if (timeSinceVisibleUs < (deInt64)WAIT_WINDOW_VISIBLE_MS*1000)
303 deSleep(WAIT_WINDOW_VISIBLE_MS - (deUint32)(timeSinceVisibleUs/1000));
306 TCU_CHECK(GetClientRect(m_window.getHandle(), &rect));
310 const int width = rect.right - rect.left;
311 const int height = rect.bottom - rect.top;
312 BITMAPINFOHEADER bitmapInfo;
314 deMemset(&bitmapInfo, 0, sizeof(bitmapInfo));
316 screenDC = GetDC(DE_NULL);
319 windowDC = GetDC(m_window.getHandle());
322 tmpDC = CreateCompatibleDC(screenDC);
323 TCU_CHECK(tmpDC != DE_NULL);
325 MapWindowPoints(m_window.getHandle(), DE_NULL, (LPPOINT)&rect, 2);
327 tmpBitmap = CreateCompatibleBitmap(screenDC, width, height);
328 TCU_CHECK(tmpBitmap != DE_NULL);
330 TCU_CHECK(SelectObject(tmpDC, tmpBitmap) != DE_NULL);
332 TCU_CHECK(BitBlt(tmpDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY));
335 bitmapInfo.biSize = sizeof(BITMAPINFOHEADER);
336 bitmapInfo.biWidth = width;
337 bitmapInfo.biHeight = -height;
338 bitmapInfo.biPlanes = 1;
339 bitmapInfo.biBitCount = 32;
340 bitmapInfo.biCompression = BI_RGB;
341 bitmapInfo.biSizeImage = 0;
342 bitmapInfo.biXPelsPerMeter = 0;
343 bitmapInfo.biYPelsPerMeter = 0;
344 bitmapInfo.biClrUsed = 0;
345 bitmapInfo.biClrImportant = 0;
347 dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8), width, height);
349 TCU_CHECK(GetDIBits(screenDC, tmpBitmap, 0, height, dst->getAccess().getDataPtr(), (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS));
351 DeleteObject(tmpBitmap);
354 ReleaseDC(DE_NULL, screenDC);
357 ReleaseDC(m_window.getHandle(), windowDC);
366 ReleaseDC(DE_NULL, screenDC);
369 ReleaseDC(m_window.getHandle(), windowDC);
372 DeleteObject(tmpBitmap);
383 EGLNativeDisplayFactory::EGLNativeDisplayFactory (HINSTANCE instance)
384 : eglu::NativeDisplayFactory ("win32", "Native Win32 Display", DISPLAY_CAPABILITIES)
385 , m_instance (instance)
387 m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(m_instance));
388 m_nativePixmapRegistry.registerFactory(new NativePixmapFactory());
391 EGLNativeDisplayFactory::~EGLNativeDisplayFactory (void)
395 eglu::NativeDisplay* EGLNativeDisplayFactory::createDisplay (const EGLAttrib* attribList) const
397 DE_UNREF(attribList);
398 return new NativeDisplay();