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 
     34 namespace tcu
     35 {
     36 namespace
     37 {
     38 
     39 enum
     40 {
     41 	DEFAULT_SURFACE_WIDTH		= 400,
     42 	DEFAULT_SURFACE_HEIGHT		= 300,
     43 	WAIT_WINDOW_VISIBLE_MS		= 500	//!< Time to wait before issuing screenshot after changing window visibility (hack for DWM)
     44 };
     45 
     46 static const eglu::NativeDisplay::Capability	DISPLAY_CAPABILITIES	= eglu::NativeDisplay::CAPABILITY_GET_DISPLAY_LEGACY;
     47 static const eglu::NativePixmap::Capability		BITMAP_CAPABILITIES		= eglu::NativePixmap::CAPABILITY_CREATE_SURFACE_LEGACY;
     48 static const eglu::NativeWindow::Capability		WINDOW_CAPABILITIES		= (eglu::NativeWindow::Capability)
     49 																		   (eglu::NativeWindow::CAPABILITY_CREATE_SURFACE_LEGACY	|
     50 																		    eglu::NativeWindow::CAPABILITY_GET_SURFACE_SIZE			|
     51 																		    eglu::NativeWindow::CAPABILITY_GET_SCREEN_SIZE			|
     52 																			eglu::NativeWindow::CAPABILITY_READ_SCREEN_PIXELS		|
     53 																		    eglu::NativeWindow::CAPABILITY_SET_SURFACE_SIZE			|
     54 																			eglu::NativeWindow::CAPABILITY_CHANGE_VISIBILITY);
     55 
     56 class NativeDisplay : public eglu::NativeDisplay
     57 {
     58 public:
     59 									NativeDisplay			(void);
     60 	virtual							~NativeDisplay			(void) {}
     61 
     62 	virtual EGLNativeDisplayType	getLegacyNative			(void) { return m_deviceContext; }
     63 
     64 	HDC								getDeviceContext		(void) { return m_deviceContext; }
     65 
     66 private:
     67 	HDC								m_deviceContext;
     68 };
     69 
     70 class NativePixmapFactory : public eglu::NativePixmapFactory
     71 {
     72 public:
     73 								NativePixmapFactory		(void);
     74 								~NativePixmapFactory	(void) {}
     75 
     76 	virtual eglu::NativePixmap*	createPixmap			(eglu::NativeDisplay* nativeDisplay, int width, int height) const;
     77 	virtual eglu::NativePixmap*	createPixmap			(eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const;
     78 };
     79 
     80 class NativePixmap : public eglu::NativePixmap
     81 {
     82 public:
     83 								NativePixmap			(NativeDisplay* nativeDisplay, int width, int height, int bitDepth);
     84 	virtual						~NativePixmap			(void);
     85 
     86 	EGLNativePixmapType			getLegacyNative			(void) { return m_bitmap; }
     87 
     88 private:
     89 	HBITMAP						m_bitmap;
     90 };
     91 
     92 class NativeWindowFactory : public eglu::NativeWindowFactory
     93 {
     94 public:
     95 								NativeWindowFactory		(HINSTANCE instance);
     96 	virtual						~NativeWindowFactory	(void) {}
     97 
     98 	virtual eglu::NativeWindow*	createWindow			(eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const;
     99 
    100 private:
    101 	const HINSTANCE				m_instance;
    102 };
    103 
    104 class NativeWindow : public eglu::NativeWindow
    105 {
    106 public:
    107 									NativeWindow			(NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params);
    108 	virtual							~NativeWindow			(void);
    109 
    110 	EGLNativeWindowType				getLegacyNative			(void) { return m_window.getHandle(); }
    111 	virtual IVec2					getSurfaceSize			(void) const;
    112 	virtual IVec2					getScreenSize			(void) const { return getSurfaceSize(); }
    113 	virtual void					processEvents			(void);
    114 	virtual void					setSurfaceSize			(IVec2 size);
    115 	virtual void					setVisibility			(eglu::WindowParams::Visibility visibility);
    116 	virtual void					readScreenPixels		(tcu::TextureLevel* dst) const;
    117 
    118 private:
    119 	Win32Window						m_window;
    120 	eglu::WindowParams::Visibility	m_curVisibility;
    121 	deUint64						m_setVisibleTime;		//!< Time window was set visible.
    122 };
    123 
    124 // NativeDisplay
    125 
    126 NativeDisplay::NativeDisplay (void)
    127 	: eglu::NativeDisplay	(DISPLAY_CAPABILITIES)
    128 	, m_deviceContext		(EGL_DEFAULT_DISPLAY)
    129 {
    130 }
    131 
    132 // NativePixmap
    133 
    134 NativePixmap::NativePixmap (NativeDisplay* nativeDisplay, int width, int height, int bitDepth)
    135 	: eglu::NativePixmap	(BITMAP_CAPABILITIES)
    136 	, m_bitmap				(DE_NULL)
    137 {
    138 	const HDC		deviceCtx	= nativeDisplay->getDeviceContext();
    139 	BITMAPINFO		bitmapInfo;
    140 
    141 	memset(&bitmapInfo, 0, sizeof(bitmapInfo));
    142 
    143 	if (bitDepth != 24 && bitDepth != 32)
    144 		throw NotSupportedError("Unsupported pixmap bit depth", DE_NULL, __FILE__, __LINE__);
    145 
    146 	bitmapInfo.bmiHeader.biSize				= sizeof(bitmapInfo);
    147 	bitmapInfo.bmiHeader.biWidth			= width;
    148 	bitmapInfo.bmiHeader.biHeight			= height;
    149 	bitmapInfo.bmiHeader.biPlanes			= 1;
    150 	bitmapInfo.bmiHeader.biBitCount			= bitDepth;
    151 	bitmapInfo.bmiHeader.biCompression		= BI_RGB;
    152 	bitmapInfo.bmiHeader.biSizeImage		= 0;
    153 	bitmapInfo.bmiHeader.biXPelsPerMeter	= 1;
    154 	bitmapInfo.bmiHeader.biYPelsPerMeter	= 1;
    155 	bitmapInfo.bmiHeader.biClrUsed			= 0;
    156 	bitmapInfo.bmiHeader.biClrImportant		= 0;
    157 
    158 	void* bitmapPtr = DE_NULL;
    159 	m_bitmap = CreateDIBSection(deviceCtx, &bitmapInfo, DIB_RGB_COLORS, &bitmapPtr, NULL, 0);
    160 
    161 	if (!m_bitmap)
    162 		throw ResourceError("Failed to create bitmap", DE_NULL, __FILE__, __LINE__);
    163 }
    164 
    165 NativePixmap::~NativePixmap (void)
    166 {
    167 	DeleteObject(m_bitmap);
    168 }
    169 
    170 // NativePixmapFactory
    171 
    172 NativePixmapFactory::NativePixmapFactory (void)
    173 	: eglu::NativePixmapFactory	("bitmap", "Win32 Bitmap", BITMAP_CAPABILITIES)
    174 {
    175 }
    176 
    177 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, EGLDisplay display, EGLConfig config, const EGLAttrib* attribList, int width, int height) const
    178 {
    179 	int	redBits		= 0;
    180 	int	greenBits	= 0;
    181 	int	blueBits	= 0;
    182 	int	alphaBits	= 0;
    183 	int	bitSum		= 0;
    184 
    185 	DE_ASSERT(display != EGL_NO_DISPLAY);
    186 
    187 	EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, EGL_RED_SIZE,	&redBits));
    188 	EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, EGL_GREEN_SIZE,	&greenBits));
    189 	EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, EGL_BLUE_SIZE,	&blueBits));
    190 	EGLU_CHECK_CALL(eglGetConfigAttrib(display, config, EGL_ALPHA_SIZE,	&alphaBits));
    191 	bitSum = redBits+greenBits+blueBits+alphaBits;
    192 
    193 	return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, bitSum);
    194 }
    195 
    196 eglu::NativePixmap* NativePixmapFactory::createPixmap (eglu::NativeDisplay* nativeDisplay, int width, int height) const
    197 {
    198 	const int defaultDepth = 32;
    199 	return new NativePixmap(dynamic_cast<NativeDisplay*>(nativeDisplay), width, height, defaultDepth);
    200 }
    201 
    202 // NativeWindowFactory
    203 
    204 NativeWindowFactory::NativeWindowFactory (HINSTANCE instance)
    205 	: eglu::NativeWindowFactory	("window", "Win32 Window", WINDOW_CAPABILITIES)
    206 	, m_instance				(instance)
    207 {
    208 }
    209 
    210 eglu::NativeWindow* NativeWindowFactory::createWindow (eglu::NativeDisplay* nativeDisplay, const eglu::WindowParams& params) const
    211 {
    212 	return new NativeWindow(dynamic_cast<NativeDisplay*>(nativeDisplay), m_instance, params);
    213 }
    214 
    215 // NativeWindow
    216 
    217 NativeWindow::NativeWindow (NativeDisplay* nativeDisplay, HINSTANCE instance, const eglu::WindowParams& params)
    218 	: eglu::NativeWindow	(WINDOW_CAPABILITIES)
    219 	, m_window				(instance,
    220 							 params.width	== eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_WIDTH	: params.width,
    221 							 params.height	== eglu::WindowParams::SIZE_DONT_CARE ? DEFAULT_SURFACE_HEIGHT	: params.height)
    222 	, m_curVisibility		(eglu::WindowParams::VISIBILITY_HIDDEN)
    223 	, m_setVisibleTime		(0)
    224 {
    225 	if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE)
    226 		setVisibility(params.visibility);
    227 }
    228 
    229 void NativeWindow::setVisibility (eglu::WindowParams::Visibility visibility)
    230 {
    231 	switch (visibility)
    232 	{
    233 		case eglu::WindowParams::VISIBILITY_HIDDEN:
    234 			m_window.setVisible(false);
    235 			m_curVisibility		= visibility;
    236 			break;
    237 
    238 		case eglu::WindowParams::VISIBILITY_VISIBLE:
    239 		case eglu::WindowParams::VISIBILITY_FULLSCREEN:
    240 			// \todo [2014-03-12 pyry] Implement FULLSCREEN, or at least SW_MAXIMIZE.
    241 			m_window.setVisible(true);
    242 			m_curVisibility		= eglu::WindowParams::VISIBILITY_VISIBLE;
    243 			m_setVisibleTime	= deGetMicroseconds();
    244 			break;
    245 
    246 		default:
    247 			DE_ASSERT(DE_FALSE);
    248 	}
    249 }
    250 
    251 NativeWindow::~NativeWindow (void)
    252 {
    253 }
    254 
    255 IVec2 NativeWindow::getSurfaceSize (void) const
    256 {
    257 	return m_window.getSize();
    258 }
    259 
    260 void NativeWindow::processEvents (void)
    261 {
    262 	m_window.processEvents();
    263 }
    264 
    265 void NativeWindow::setSurfaceSize (IVec2 size)
    266 {
    267 	m_window.setSize(size.x(), size.y());
    268 }
    269 
    270 void NativeWindow::readScreenPixels (tcu::TextureLevel* dst) const
    271 {
    272 	HDC			windowDC	= DE_NULL;
    273 	HDC			screenDC	= DE_NULL;
    274 	HDC			tmpDC		= DE_NULL;
    275 	HBITMAP		tmpBitmap	= DE_NULL;
    276 	RECT		rect;
    277 
    278 	TCU_CHECK_INTERNAL(m_curVisibility != eglu::WindowParams::VISIBILITY_HIDDEN);
    279 
    280 	// Hack for DWM: There is no way to wait for DWM animations to finish, so we just have to wait
    281 	// for a while before issuing screenshot if window was just made visible.
    282 	{
    283 		const deInt64 timeSinceVisibleUs = (deInt64)(deGetMicroseconds()-m_setVisibleTime);
    284 
    285 		if (timeSinceVisibleUs < (deInt64)WAIT_WINDOW_VISIBLE_MS*1000)
    286 			deSleep(WAIT_WINDOW_VISIBLE_MS - (deUint32)(timeSinceVisibleUs/1000));
    287 	}
    288 
    289 	TCU_CHECK(GetClientRect(m_window.getHandle(), &rect));
    290 
    291 	try
    292 	{
    293 		const int			width		= rect.right - rect.left;
    294 		const int			height		= rect.bottom - rect.top;
    295 		BITMAPINFOHEADER	bitmapInfo;
    296 
    297 		deMemset(&bitmapInfo, 0, sizeof(bitmapInfo));
    298 
    299 		screenDC = GetDC(DE_NULL);
    300 		TCU_CHECK(screenDC);
    301 
    302 		windowDC = GetDC(m_window.getHandle());
    303 		TCU_CHECK(windowDC);
    304 
    305 		tmpDC = CreateCompatibleDC(screenDC);
    306 		TCU_CHECK(tmpDC != DE_NULL);
    307 
    308 		MapWindowPoints(m_window.getHandle(), DE_NULL, (LPPOINT)&rect, 2);
    309 
    310 		tmpBitmap = CreateCompatibleBitmap(screenDC, width, height);
    311 		TCU_CHECK(tmpBitmap != DE_NULL);
    312 
    313 		TCU_CHECK(SelectObject(tmpDC, tmpBitmap) != DE_NULL);
    314 
    315 		TCU_CHECK(BitBlt(tmpDC, 0, 0, width, height, screenDC, rect.left, rect.top, SRCCOPY));
    316 
    317 
    318 		bitmapInfo.biSize			= sizeof(BITMAPINFOHEADER);
    319 		bitmapInfo.biWidth			= width;
    320 		bitmapInfo.biHeight			= -height;
    321 		bitmapInfo.biPlanes			= 1;
    322 		bitmapInfo.biBitCount		= 32;
    323 		bitmapInfo.biCompression	= BI_RGB;
    324 		bitmapInfo.biSizeImage		= 0;
    325 		bitmapInfo.biXPelsPerMeter	= 0;
    326 		bitmapInfo.biYPelsPerMeter	= 0;
    327 		bitmapInfo.biClrUsed		= 0;
    328 		bitmapInfo.biClrImportant	= 0;
    329 
    330 		dst->setStorage(TextureFormat(TextureFormat::BGRA, TextureFormat::UNORM_INT8), width, height);
    331 
    332 		TCU_CHECK(GetDIBits(screenDC, tmpBitmap, 0, height, dst->getAccess().getDataPtr(), (BITMAPINFO*)&bitmapInfo, DIB_RGB_COLORS));
    333 
    334 		DeleteObject(tmpBitmap);
    335 		tmpBitmap = DE_NULL;
    336 
    337 		ReleaseDC(DE_NULL, screenDC);
    338 		screenDC = DE_NULL;
    339 
    340 		ReleaseDC(m_window.getHandle(), windowDC);
    341 		windowDC = DE_NULL;
    342 
    343 		DeleteDC(tmpDC);
    344 		tmpDC = DE_NULL;
    345 	}
    346 	catch (...)
    347 	{
    348 		if (screenDC)
    349 			ReleaseDC(DE_NULL, screenDC);
    350 
    351 		if (windowDC)
    352 			ReleaseDC(m_window.getHandle(), windowDC);
    353 
    354 		if (tmpBitmap)
    355 			DeleteObject(tmpBitmap);
    356 
    357 		if (tmpDC)
    358 			DeleteDC(tmpDC);
    359 
    360 		throw;
    361 	}
    362 }
    363 
    364 } // anonymous
    365 
    366 Win32EGLNativeDisplayFactory::Win32EGLNativeDisplayFactory (HINSTANCE instance)
    367 	: eglu::NativeDisplayFactory	("win32", "Native Win32 Display", DISPLAY_CAPABILITIES)
    368 	, m_instance					(instance)
    369 {
    370 	m_nativeWindowRegistry.registerFactory(new NativeWindowFactory(m_instance));
    371 	m_nativePixmapRegistry.registerFactory(new NativePixmapFactory());
    372 }
    373 
    374 Win32EGLNativeDisplayFactory::~Win32EGLNativeDisplayFactory (void)
    375 {
    376 }
    377 
    378 eglu::NativeDisplay* Win32EGLNativeDisplayFactory::createDisplay (const EGLAttrib* attribList) const
    379 {
    380 	DE_UNREF(attribList);
    381 	return new NativeDisplay();
    382 }
    383 
    384 } // tcu
    385