• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
~NativeDisplay(void)71 	virtual							~NativeDisplay			(void) {}
72 
getLegacyNative(void)73 	virtual EGLNativeDisplayType	getLegacyNative			(void)			{ return m_deviceContext;	}
getLibrary(void) const74 	const eglw::Library&			getLibrary				(void) const	{ return m_library;			}
75 
getDeviceContext(void)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);
~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 
getLegacyNative(void)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);
~NativeWindowFactory(void)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 
getLegacyNative(void)123 	EGLNativeWindowType				getLegacyNative			(void) { return m_window.getHandle(); }
124 	virtual IVec2					getSurfaceSize			(void) const;
getScreenSize(void) const125 	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 
NativeDisplay(void)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 
NativePixmap(NativeDisplay * nativeDisplay,int width,int height,int bitDepth)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 
~NativePixmap(void)179 NativePixmap::~NativePixmap (void)
180 {
181 	DeleteObject(m_bitmap);
182 }
183 
184 // NativePixmapFactory
185 
NativePixmapFactory(void)186 NativePixmapFactory::NativePixmapFactory (void)
187 	: eglu::NativePixmapFactory	("bitmap", "Win32 Bitmap", BITMAP_CAPABILITIES)
188 {
189 }
190 
createPixmap(eglu::NativeDisplay * nativeDisplay,EGLDisplay display,EGLConfig config,const EGLAttrib * attribList,int width,int height) const191 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 
createPixmap(eglu::NativeDisplay * nativeDisplay,int width,int height) const213 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 
NativeWindowFactory(HINSTANCE instance)221 NativeWindowFactory::NativeWindowFactory (HINSTANCE instance)
222 	: eglu::NativeWindowFactory	("window", "Win32 Window", WINDOW_CAPABILITIES)
223 	, m_instance				(instance)
224 {
225 }
226 
createWindow(eglu::NativeDisplay * nativeDisplay,const eglu::WindowParams & params) const227 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 
NativeWindow(NativeDisplay * nativeDisplay,HINSTANCE instance,const eglu::WindowParams & 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)
241 {
242 	if (params.visibility != eglu::WindowParams::VISIBILITY_DONT_CARE)
243 		setVisibility(params.visibility);
244 }
245 
setVisibility(eglu::WindowParams::Visibility visibility)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 
~NativeWindow(void)268 NativeWindow::~NativeWindow (void)
269 {
270 }
271 
getSurfaceSize(void) const272 IVec2 NativeWindow::getSurfaceSize (void) const
273 {
274 	return m_window.getSize();
275 }
276 
processEvents(void)277 void NativeWindow::processEvents (void)
278 {
279 	m_window.processEvents();
280 }
281 
setSurfaceSize(IVec2 size)282 void NativeWindow::setSurfaceSize (IVec2 size)
283 {
284 	m_window.setSize(size.x(), size.y());
285 }
286 
readScreenPixels(tcu::TextureLevel * dst) const287 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 
EGLNativeDisplayFactory(HINSTANCE instance)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 
~EGLNativeDisplayFactory(void)391 EGLNativeDisplayFactory::~EGLNativeDisplayFactory (void)
392 {
393 }
394 
createDisplay(const EGLAttrib * attribList) const395 eglu::NativeDisplay* EGLNativeDisplayFactory::createDisplay (const EGLAttrib* attribList) const
396 {
397 	DE_UNREF(attribList);
398 	return new NativeDisplay();
399 }
400 
401 } // win32
402 } // tcu
403