Home | History | Annotate | Download | only in win32
      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		= 500	//!< Time to wait before issuing screenshot after changing window visibility (hack for DWM)
     55 };
     56 
     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);
     66 
     67 class NativeDisplay : public eglu::NativeDisplay
     68 {
     69 public:
     70 									NativeDisplay			(void);
     71 	virtual							~NativeDisplay			(void) {}
     72 
     73 	virtual EGLNativeDisplayType	getLegacyNative			(void)			{ return m_deviceContext;	}
     74 	const eglw::Library&			getLibrary				(void) const	{ return m_library;			}
     75 
     76 	HDC								getDeviceContext		(void)			{ return m_deviceContext;	}
     77 
     78 private:
     79 	HDC								m_deviceContext;
     80 	eglw::DefaultLibrary			m_library;
     81 };
     82 
     83 class NativePixmapFactory : public eglu::NativePixmapFactory
     84 {
     85 public:
     86 								NativePixmapFactory		(void);
     87 								~NativePixmapFactory	(void) {}
     88 
     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;
     91 };
     92 
     93 class NativePixmap : public eglu::NativePixmap
     94 {
     95 public:
     96 								NativePixmap			(NativeDisplay* nativeDisplay, int width, int height, int bitDepth);
     97 	virtual						~NativePixmap			(void);
     98 
     99 	EGLNativePixmapType			getLegacyNative			(void) { return m_bitmap; }
    100 
    101 private:
    102 	HBITMAP						m_bitmap;
    103 };
    104 
    105 class NativeWindowFactory : public eglu::NativeWindowFactory
    106 {
    107 public:
    108 								NativeWindowFactory		(HINSTANCE instance);
    109 	virtual						~NativeWindowFactory	(void) {}
    110 
    111 	virtual eglu::NativeWindow*	createWindow			(eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const;
    112 
    113 private:
    114 	const HINSTANCE				m_instance;
    115 };
    116 
    117 class NativeWindow : public eglu::NativeWindow
    118 {
    119 public:
    120 									NativeWindow			(NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params);
    121 	virtual							~NativeWindow			(void);
    122 
    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;
    130 
    131 private:
    132 	win32::Window					m_window;
    133 	eglu::WindowParams::Visibility	m_curVisibility;
    134 	deUint64						m_setVisibleTime;		//!< Time window was set visible.
    135 };
    136 
    137 // NativeDisplay
    138 
    139 NativeDisplay::NativeDisplay (void)
    140 	: eglu::NativeDisplay	(DISPLAY_CAPABILITIES)
    141 	, m_deviceContext		((HDC)EGL_DEFAULT_DISPLAY)
    142 	, m_library				("libEGL.dll")
    143 {
    144 }
    145 
    146 // NativePixmap
    147 
    148 NativePixmap::NativePixmap (NativeDisplay* nativeDisplay, int width, int height, int bitDepth)
    149 	: eglu::NativePixmap	(BITMAP_CAPABILITIES)
    150 	, m_bitmap				(DE_NULL)
    151 {
    152 	const HDC		deviceCtx	= nativeDisplay->getDeviceContext();
    153 	BITMAPINFO		bitmapInfo;
    154 
    155 	memset(&bitmapInfo, 0, sizeof(bitmapInfo));
    156 
    157 	if (bitDepth != 24 && bitDepth != 32)
    158 		throw NotSupportedError("Unsupported pixmap bit depth", DE_NULL, __FILE__, __LINE__);
    159 
    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;
    171 
    172 	void* bitmapPtr = DE_NULL;
    173 	m_bitmap = CreateDIBSection(deviceCtx, &bitmapInfo, DIB_RGB_COLORS, &bitmapPtr, NULL, 0);
    174 
    175 	if (!m_bitmap)
    176 		throw ResourceError("Failed to create bitmap", DE_NULL, __FILE__, __LINE__);
    177 }
    178 
    179 NativePixmap::~NativePixmap (void)
    180 {
    181 	DeleteObject(m_bitmap);
    182 }
    183 
    184 // NativePixmapFactory
    185 
    186 NativePixmapFactory::NativePixmapFactory (void)
    187 	: eglu::NativePixmapFactory	("bitmap", "Win32 Bitmap", BITMAP_CAPABILITIES)
    188 {
    189 }
    190 
    191 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const
    192 {
    193 	const Library&	egl			= nativeDisplay->getLibrary();
    194 	int				redBits		= 0;
    195 	int				greenBits	= 0;
    196 	int				blueBits	= 0;
    197 	int				alphaBits	= 0;
    198 	int				bitSum		= 0;
    199 
    200 	DE_ASSERT(display != EGL_NO_DISPLAY);
    201 
    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()");
    207 
    208 	bitSum = redBits+greenBits+blueBits+alphaBits;
    209 
    210 	return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, bitSum);
    211 }
    212 
    213 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, int width, int height) const
    214 {
    215 	const int defaultDepth = 32;
    216 	return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, defaultDepth);
    217 }
    218 
    219 // NativeWindowFactory
    220 
    221 NativeWindowFactory::NativeWindowFactory (HINSTANCE instance)
    222 	: eglu::NativeWindowFactory	("window", "Win32 Window", WINDOW_CAPABILITIES)
    223 	, m_instance				(instance)
    224 {
    225 }
    226 
    227 eglu::NativeWindow* NativeWindowFactory::createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const
    228 {
    229 	return new NativeWindow(dynamic_cast<NativeDisplay*>(nativeDisplay), m_instance, params);
    230 }
    231 
    232 // NativeWindow
    233 
    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)
    241 {
    242 	if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE)
    243 		setVisibility(params.visibility);
    244 }
    245 
    246 void NativeWindow::setVisibility (eglu::WindowParams::Visibility visibility)
    247 {
    248 	switch (visibility)
    249 	{
    250 		case eglu::WindowParams::VISIBILITY_HIDDEN:
    251 			m_window.setVisible(false);
    252 			m_curVisibility		= visibility;
    253 			break;
    254 
    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();
    261 			break;
    262 
    263 		default:
    264 			DE_ASSERT(DE_FALSE);
    265 	}
    266 }
    267 
    268 NativeWindow::~NativeWindow (void)
    269 {
    270 }
    271 
    272 IVec2 NativeWindow::getSurfaceSize (void) const
    273 {
    274 	return m_window.getSize();
    275 }
    276 
    277 void NativeWindow::processEvents (void)
    278 {
    279 	m_window.processEvents();
    280 }
    281 
    282 void NativeWindow::setSurfaceSize (IVec2 size)
    283 {
    284 	m_window.setSize(size.x(), size.y());
    285 }
    286 
    287 void NativeWindow::readScreenPixels (tcu::TextureLevel* dst) const
    288 {
    289 	HDC			windowDC	= DE_NULL;
    290 	HDC			screenDC	= DE_NULL;
    291 	HDC			tmpDC		= DE_NULL;
    292 	HBITMAP		tmpBitmap	= DE_NULL;
    293 	RECT		rect;
    294 
    295 	TCU_CHECK_INTERNAL(m_curVisibility != eglu::WindowParams::VISIBILITY_HIDDEN);
    296 
    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.
    299 	{
    300 		const deInt64 timeSinceVisibleUs = (deInt64)(deGetMicroseconds()-m_setVisibleTime);
    301 
    302 		if (timeSinceVisibleUs < (deInt64)WAIT_WINDOW_VISIBLE_MS*1000)
    303 			deSleep(WAIT_WINDOW_VISIBLE_MS - (deUint32)(timeSinceVisibleUs/1000));
    304 	}
    305 
    306 	TCU_CHECK(GetClientRect(m_window.getHandle(), &rect));
    307 
    308 	try
    309 	{
    310 		const int			width		= rect.right - rect.left;
    311 		const int			height		= rect.bottom - rect.top;
    312 		BITMAPINFOHEADER	bitmapInfo;
    313 
    314 		deMemset(&bitmapInfo, 0, sizeof(bitmapInfo));
    315 
    316 		screenDC = GetDC(DE_NULL);
    317 		TCU_CHECK(screenDC);
    318 
    319 		windowDC = GetDC(m_window.getHandle());
    320 		TCU_CHECK(windowDC);
    321 
    322 		tmpDC = CreateCompatibleDC(screenDC);
    323 		TCU_CHECK(tmpDC != DE_NULL);
    324 
    325 		MapWindowPoints(m_window.getHandle(), DE_NULL, (LPPOINT)&rect, 2);
    326 
    327 		tmpBitmap = CreateCompatibleBitmap(screenDC, width, height);
    328 		TCU_CHECK(tmpBitmap != DE_NULL);
    329 
    330 		TCU_CHECK(SelectObject(tmpDC, tmpBitmap) != DE_NULL);
    331 
    332 		TCU_CHECK(BitBlt(tmpDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY));
    333 
    334 
    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;
    346 
    347 		dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8), width, height);
    348 
    349 		TCU_CHECK(GetDIBits(screenDC, tmpBitmap, 0, height, dst->getAccess().getDataPtr(), (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS));
    350 
    351 		DeleteObject(tmpBitmap);
    352 		tmpBitmap = DE_NULL;
    353 
    354 		ReleaseDC(DE_NULL, screenDC);
    355 		screenDC = DE_NULL;
    356 
    357 		ReleaseDC(m_window.getHandle(), windowDC);
    358 		windowDC = DE_NULL;
    359 
    360 		DeleteDC(tmpDC);
    361 		tmpDC = DE_NULL;
    362 	}
    363 	catch (...)
    364 	{
    365 		if (screenDC)
    366 			ReleaseDC(DE_NULL, screenDC);
    367 
    368 		if (windowDC)
    369 			ReleaseDC(m_window.getHandle(), windowDC);
    370 
    371 		if (tmpBitmap)
    372 			DeleteObject(tmpBitmap);
    373 
    374 		if (tmpDC)
    375 			DeleteDC(tmpDC);
    376 
    377 		throw;
    378 	}
    379 }
    380 
    381 } // anonymous
    382 
    383 EGLNativeDisplayFactory::EGLNativeDisplayFactory (HINSTANCE instance)
    384 	: eglu::NativeDisplayFactory	("win32", "Native Win32 Display", DISPLAY_CAPABILITIES)
    385 	, m_instance					(instance)
    386 {
    387 	m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(m_instance));
    388 	m_nativePixmapRegistry.registerFactory(new NativePixmapFactory());
    389 }
    390 
    391 EGLNativeDisplayFactory::~EGLNativeDisplayFactory (void)
    392 {
    393 }
    394 
    395 eglu::NativeDisplay* EGLNativeDisplayFactory::createDisplay (const EGLAttrib* attribList) const
    396 {
    397 	DE_UNREF(attribList);
    398 	return new NativeDisplay();
    399 }
    400 
    401 } // win32
    402 } // tcu
    403