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 WGL Utilities.
22 *//*--------------------------------------------------------------------*/
23
24#include "tcuWGL.hpp"
25#include "tcuWin32Window.hpp"
26#include "deDynamicLibrary.hpp"
27#include "deMemory.h"
28#include "deStringUtil.hpp"
29#include "tcuFormatUtil.hpp"
30#include "gluRenderConfig.hpp"
31
32#include <WinGDI.h>
33
34// WGL_ARB_pixel_format
35#define WGL_NUMBER_PIXEL_FORMATS_ARB				0x2000
36#define WGL_DRAW_TO_WINDOW_ARB						0x2001
37#define WGL_DRAW_TO_BITMAP_ARB						0x2002
38#define WGL_ACCELERATION_ARB						0x2003
39#define WGL_NEED_PALETTE_ARB						0x2004
40#define WGL_NEED_SYSTEM_PALETTE_ARB					0x2005
41#define WGL_SWAP_LAYER_BUFFERS_ARB					0x2006
42#define WGL_SWAP_METHOD_ARB							0x2007
43#define WGL_NUMBER_OVERLAYS_ARB						0x2008
44#define WGL_NUMBER_UNDERLAYS_ARB					0x2009
45#define WGL_TRANSPARENT_ARB							0x200A
46#define WGL_TRANSPARENT_RED_VALUE_ARB				0x2037
47#define WGL_TRANSPARENT_GREEN_VALUE_ARB				0x2038
48#define WGL_TRANSPARENT_BLUE_VALUE_ARB				0x2039
49#define WGL_TRANSPARENT_ALPHA_VALUE_ARB				0x203A
50#define WGL_TRANSPARENT_INDEX_VALUE_ARB				0x203B
51#define WGL_SHARE_DEPTH_ARB							0x200C
52#define WGL_SHARE_STENCIL_ARB						0x200D
53#define WGL_SHARE_ACCUM_ARB							0x200E
54#define WGL_SUPPORT_GDI_ARB							0x200F
55#define WGL_SUPPORT_OPENGL_ARB						0x2010
56#define WGL_DOUBLE_BUFFER_ARB						0x2011
57#define WGL_STEREO_ARB								0x2012
58#define WGL_PIXEL_TYPE_ARB							0x2013
59#define WGL_COLOR_BITS_ARB							0x2014
60#define WGL_RED_BITS_ARB							0x2015
61#define WGL_RED_SHIFT_ARB							0x2016
62#define WGL_GREEN_BITS_ARB							0x2017
63#define WGL_GREEN_SHIFT_ARB							0x2018
64#define WGL_BLUE_BITS_ARB							0x2019
65#define WGL_BLUE_SHIFT_ARB							0x201A
66#define WGL_ALPHA_BITS_ARB							0x201B
67#define WGL_ALPHA_SHIFT_ARB							0x201C
68#define WGL_ACCUM_BITS_ARB							0x201D
69#define WGL_ACCUM_RED_BITS_ARB						0x201E
70#define WGL_ACCUM_GREEN_BITS_ARB					0x201F
71#define WGL_ACCUM_BLUE_BITS_ARB						0x2020
72#define WGL_ACCUM_ALPHA_BITS_ARB					0x2021
73#define WGL_DEPTH_BITS_ARB							0x2022
74#define WGL_STENCIL_BITS_ARB						0x2023
75#define WGL_AUX_BUFFERS_ARB							0x2024
76
77#define WGL_NO_ACCELERATION_ARB						0x2025
78#define WGL_GENERIC_ACCELERATION_ARB				0x2026
79#define WGL_FULL_ACCELERATION_ARB					0x2027
80
81#define WGL_TYPE_RGBA_ARB							0x202B
82#define WGL_TYPE_COLORINDEX_ARB						0x202C
83
84// WGL_ARB_color_buffer_float
85#define WGL_TYPE_RGBA_FLOAT_ARB						0x21A0
86
87// WGL_EXT_pixel_type_packed_float
88#define WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT			0x20A8
89
90// WGL_ARB_multisample
91#define WGL_SAMPLE_BUFFERS_ARB						0x2041
92#define WGL_SAMPLES_ARB								0x2042
93
94// WGL_ARB_create_context
95#define WGL_CONTEXT_MAJOR_VERSION_ARB				0x2091
96#define WGL_CONTEXT_MINOR_VERSION_ARB				0x2092
97#define WGL_CONTEXT_LAYER_PLANE_ARB					0x2093
98#define WGL_CONTEXT_FLAGS_ARB						0x2094
99#define WGL_CONTEXT_PROFILE_MASK_ARB				0x9126
100#define WGL_CONTEXT_DEBUG_BIT_ARB					0x0001
101#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB		0x0002
102#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB			0x00000001
103#define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB	0x00000002
104#define WGL_CONTEXT_ES_PROFILE_BIT_EXT				0x00000004
105
106// WGL_ARB_create_context_robustness
107#define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB			0x0004
108#define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB	0x8256
109#define WGL_NO_RESET_NOTIFICATION_ARB				0x8261
110#define WGL_LOSE_CONTEXT_ON_RESET_ARB				0x8252
111
112DE_BEGIN_EXTERN_C
113
114// WGL core
115typedef HGLRC	(WINAPI* wglCreateContextFunc)				(HDC hdc);
116typedef BOOL	(WINAPI* wglDeleteContextFunc)				(HGLRC hglrc);
117typedef BOOL	(WINAPI* wglMakeCurrentFunc)				(HDC hdc, HGLRC hglrc);
118typedef PROC	(WINAPI* wglGetProcAddressFunc)				(LPCSTR lpszProc);
119typedef BOOL	(WINAPI* wglSwapLayerBuffersFunc)			(HDC dhc, UINT fuPlanes);
120
121// WGL_ARB_pixel_format
122typedef BOOL	(WINAPI* wglGetPixelFormatAttribivARBFunc)	(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);
123typedef BOOL	(WINAPI* wglGetPixelFormatAttribfvARBFunc)	(HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, FLOAT *pfValues);
124typedef BOOL	(WINAPI* wglChoosePixelFormatARBFunc)		(HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, int *piFormats, UINT *nNumFormats);
125
126// WGL_ARB_create_context
127typedef HGLRC	(WINAPI* wglCreateContextAttribsARBFunc)	(HDC hdc, HGLRC hshareContext, const int* attribList);
128
129DE_END_EXTERN_C
130
131namespace tcu
132{
133namespace wgl
134{
135
136// Functions
137
138struct Functions
139{
140	// Core
141	wglCreateContextFunc				createContext;
142	wglDeleteContextFunc				deleteContext;
143	wglMakeCurrentFunc					makeCurrent;
144	wglGetProcAddressFunc				getProcAddress;
145	wglSwapLayerBuffersFunc				swapLayerBuffers;
146
147	// WGL_ARB_pixel_format
148	wglGetPixelFormatAttribivARBFunc	getPixelFormatAttribivARB;
149	wglGetPixelFormatAttribfvARBFunc	getPixelFormatAttribfvARB;
150	wglChoosePixelFormatARBFunc			choosePixelFormatARB;
151
152	// WGL_ARB_create_context
153	wglCreateContextAttribsARBFunc		createContextAttribsARB;
154
155	Functions (void)
156		: createContext				(DE_NULL)
157		, deleteContext				(DE_NULL)
158		, makeCurrent				(DE_NULL)
159		, getProcAddress			(DE_NULL)
160		, swapLayerBuffers			(DE_NULL)
161		, getPixelFormatAttribivARB	(DE_NULL)
162		, getPixelFormatAttribfvARB	(DE_NULL)
163		, choosePixelFormatARB		(DE_NULL)
164		, createContextAttribsARB	(DE_NULL)
165	{
166	}
167};
168
169// Library
170
171class Library
172{
173public:
174								Library			(HINSTANCE instance);
175								~Library		(void);
176
177	const Functions&			getFunctions	(void) const	{ return m_functions;	}
178	const de::DynamicLibrary&	getGLLibrary	(void) const	{ return m_library;		}
179
180private:
181	de::DynamicLibrary			m_library;
182	Functions					m_functions;
183};
184
185Library::Library (HINSTANCE instance)
186	: m_library("opengl32.dll")
187{
188	// Temporary 1x1 window for creating context
189	Win32Window tmpWindow(instance, 1, 1);
190
191	// Load WGL core.
192	m_functions.createContext		= (wglCreateContextFunc)		m_library.getFunction("wglCreateContext");
193	m_functions.deleteContext		= (wglDeleteContextFunc)		m_library.getFunction("wglDeleteContext");
194	m_functions.getProcAddress		= (wglGetProcAddressFunc)		m_library.getFunction("wglGetProcAddress");
195	m_functions.makeCurrent			= (wglMakeCurrentFunc)			m_library.getFunction("wglMakeCurrent");
196	m_functions.swapLayerBuffers	= (wglSwapLayerBuffersFunc)		m_library.getFunction("wglSwapLayerBuffers");
197
198	if (!m_functions.createContext		||
199		!m_functions.deleteContext		||
200		!m_functions.getProcAddress		||
201		!m_functions.makeCurrent		||
202		!m_functions.swapLayerBuffers)
203		throw ResourceError("Failed to load core WGL functions");
204
205	{
206		PIXELFORMATDESCRIPTOR pixelFormatDesc;
207		deMemset(&pixelFormatDesc, 0, sizeof(pixelFormatDesc));
208
209		pixelFormatDesc.nSize			= sizeof(pixelFormatDesc);
210		pixelFormatDesc.nVersion		= 1;
211		pixelFormatDesc.dwFlags			= PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
212		pixelFormatDesc.iPixelType		= PFD_TYPE_RGBA;
213		pixelFormatDesc.iLayerType		= PFD_MAIN_PLANE;
214
215		int pixelFormat = ChoosePixelFormat(tmpWindow.getDeviceContext(), &pixelFormatDesc);
216		if (!SetPixelFormat(tmpWindow.getDeviceContext(), pixelFormat, &pixelFormatDesc))
217			throw ResourceError("Failed to set pixel format for temporary context creation");
218	}
219
220	// Create temporary context for loading extension functions.
221	HGLRC tmpCtx = m_functions.createContext(tmpWindow.getDeviceContext());
222	if (!tmpCtx || !m_functions.makeCurrent(tmpWindow.getDeviceContext(), tmpCtx))
223	{
224		if (tmpCtx)
225			m_functions.deleteContext(tmpCtx);
226		throw ResourceError("Failed to create temporary WGL context");
227	}
228
229	// WGL_ARB_pixel_format
230	m_functions.getPixelFormatAttribivARB	= (wglGetPixelFormatAttribivARBFunc)m_functions.getProcAddress("wglGetPixelFormatAttribivARB");
231	m_functions.getPixelFormatAttribfvARB	= (wglGetPixelFormatAttribfvARBFunc)m_functions.getProcAddress("wglGetPixelFormatAttribfvARB");
232	m_functions.choosePixelFormatARB		= (wglChoosePixelFormatARBFunc)m_functions.getProcAddress("wglChoosePixelFormatARB");
233
234	// WGL_ARB_create_context
235	m_functions.createContextAttribsARB		= (wglCreateContextAttribsARBFunc)m_functions.getProcAddress("wglCreateContextAttribsARB");
236
237	m_functions.makeCurrent(tmpWindow.getDeviceContext(), NULL);
238	m_functions.deleteContext(tmpCtx);
239
240	if (!m_functions.getPixelFormatAttribivARB	||
241		!m_functions.getPixelFormatAttribfvARB	||
242		!m_functions.choosePixelFormatARB		||
243		!m_functions.createContextAttribsARB)
244		throw ResourceError("Failed to load WGL extension functions");
245}
246
247Library::~Library (void)
248{
249}
250
251// Core
252
253Core::Core (HINSTANCE instance)
254	: m_library(new Library(instance))
255{
256}
257
258Core::~Core (void)
259{
260	delete m_library;
261}
262
263std::vector<int> Core::getPixelFormats (HDC deviceCtx) const
264{
265	const Functions& wgl = m_library->getFunctions();
266
267	int attribs[] = { WGL_NUMBER_PIXEL_FORMATS_ARB };
268	int values[DE_LENGTH_OF_ARRAY(attribs)];
269
270	if (!wgl.getPixelFormatAttribivARB(deviceCtx, 0, 0, DE_LENGTH_OF_ARRAY(attribs), &attribs[0], &values[0]))
271		throw ResourceError("Failed to query number of WGL pixel formats");
272
273	// \todo [2013-04-14 pyry] Do we need to filter values at all?
274	std::vector<int> pixelFormats(values[0]);
275	for (int i = 0; i < values[0]; i++)
276		pixelFormats[i] = i+1;
277
278	return pixelFormats;
279}
280
281static PixelFormatInfo::Acceleration translateAcceleration (int accel)
282{
283	switch (accel)
284	{
285		case WGL_NO_ACCELERATION_ARB:		return PixelFormatInfo::ACCELERATION_NONE;
286		case WGL_GENERIC_ACCELERATION_ARB:	return PixelFormatInfo::ACCELERATION_GENERIC;
287		case WGL_FULL_ACCELERATION_ARB:		return PixelFormatInfo::ACCELERATION_FULL;
288		default:							return PixelFormatInfo::ACCELERATION_UNKNOWN;
289	}
290}
291
292static PixelFormatInfo::PixelType translatePixelType (int type)
293{
294	switch (type)
295	{
296		case WGL_TYPE_RGBA_ARB:					return PixelFormatInfo::PIXELTYPE_RGBA;
297		case WGL_TYPE_RGBA_FLOAT_ARB:			return PixelFormatInfo::PIXELTYPE_RGBA_FLOAT;
298		case WGL_TYPE_RGBA_UNSIGNED_FLOAT_EXT:	return PixelFormatInfo::PIXELTYPE_RGBA_UNSIGNED_FLOAT;
299		case WGL_TYPE_COLORINDEX_ARB:			return PixelFormatInfo::PIXELTYPE_COLOR_INDEX;
300		default:								return PixelFormatInfo::PIXELTYPE_UNKNOWN;
301	}
302}
303
304PixelFormatInfo Core::getPixelFormatInfo (HDC deviceCtx, int pixelFormat) const
305{
306	const Functions& wgl = m_library->getFunctions();
307
308	int attribs	[14];
309	int values	[DE_LENGTH_OF_ARRAY(attribs)];
310	attribs[0]	= WGL_DRAW_TO_WINDOW_ARB;
311	attribs[1]	= WGL_DRAW_TO_BITMAP_ARB;
312	attribs[2]	= WGL_ACCELERATION_ARB;
313	attribs[3]	= WGL_SUPPORT_OPENGL_ARB;
314	attribs[4]	= WGL_DOUBLE_BUFFER_ARB;
315	attribs[5]	= WGL_PIXEL_TYPE_ARB;
316	attribs[6]	= WGL_RED_BITS_ARB;
317	attribs[7]	= WGL_GREEN_BITS_ARB;
318	attribs[8]	= WGL_BLUE_BITS_ARB;
319	attribs[9]	= WGL_ALPHA_BITS_ARB;
320	attribs[10]	= WGL_DEPTH_BITS_ARB;
321	attribs[11]	= WGL_STENCIL_BITS_ARB;
322	attribs[12]	= WGL_SAMPLE_BUFFERS_ARB;
323	attribs[13]	= WGL_SAMPLES_ARB;
324
325	deMemset(&values[0], 0, sizeof(values));
326	if (!wgl.getPixelFormatAttribivARB(deviceCtx, pixelFormat, 0, DE_LENGTH_OF_ARRAY(attribs), &attribs[0], &values[0]))
327		throw ResourceError("Pixel format query failed");
328
329	// Translate values.
330	PixelFormatInfo info;
331
332	info.pixelFormat	= pixelFormat;
333	info.surfaceTypes	|= (values[0] ? PixelFormatInfo::SURFACE_WINDOW : 0);
334	info.surfaceTypes	|= (values[1] ? PixelFormatInfo::SURFACE_PIXMAP : 0);
335	info.acceleration	= translateAcceleration(values[2]);
336	info.supportOpenGL	= values[3] != 0;
337	info.doubleBuffer	= values[4] != 0;
338	info.pixelType		= translatePixelType(values[5]);
339	info.redBits		= values[6];
340	info.greenBits		= values[7];
341	info.blueBits		= values[8];
342	info.alphaBits		= values[9];
343	info.depthBits		= values[10];
344	info.stencilBits	= values[11];
345	info.sampleBuffers	= values[12];
346	info.samples		= values[13];
347
348	return info;
349}
350
351// Context
352
353Context::Context (const Core* core, HDC deviceCtx, glu::ContextType ctxType, int pixelFormat)
354	: m_core		(core)
355	, m_deviceCtx	(deviceCtx)
356	, m_context		(0)
357{
358	const Functions& wgl = core->getLibrary()->getFunctions();
359
360	// Map context type & flags.
361	int	profileBit	= 0;
362	int	flags		= 0;
363
364	switch (ctxType.getProfile())
365	{
366		case glu::PROFILE_CORE:
367			profileBit = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
368			break;
369
370		case glu::PROFILE_ES:
371			profileBit = WGL_CONTEXT_ES_PROFILE_BIT_EXT;
372			break;
373
374		case glu::PROFILE_COMPATIBILITY:
375			profileBit = WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
376			break;
377
378		default:
379			throw NotSupportedError("Unsupported context type for WGL");
380	}
381
382	if ((ctxType.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0)
383		flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
384
385	if ((ctxType.getFlags() & glu::CONTEXT_DEBUG) != 0)
386		flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
387
388	if ((ctxType.getFlags() & glu::CONTEXT_ROBUST) != 0)
389		flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
390
391	const int attribList[] =
392	{
393		WGL_CONTEXT_MAJOR_VERSION_ARB,	ctxType.getMajorVersion(),
394		WGL_CONTEXT_MINOR_VERSION_ARB,	ctxType.getMinorVersion(),
395		WGL_CONTEXT_PROFILE_MASK_ARB,	profileBit,
396		WGL_CONTEXT_FLAGS_ARB,			flags,
397		0
398	};
399
400	// Set pixel format
401	{
402		PIXELFORMATDESCRIPTOR pixelFormatDesc;
403		deMemset(&pixelFormatDesc, 0, sizeof(pixelFormatDesc));
404
405		if (!DescribePixelFormat(deviceCtx, pixelFormat, sizeof(pixelFormatDesc), &pixelFormatDesc))
406			throw ResourceError("DescribePixelFormat() failed");
407
408		if (!SetPixelFormat(deviceCtx, pixelFormat, &pixelFormatDesc))
409			throw ResourceError("Failed to set pixel format");
410	}
411
412	// Create context
413	m_context = wgl.createContextAttribsARB(deviceCtx, NULL, attribList);
414
415	if (!m_context)
416		throw ResourceError("Failed to create WGL context");
417
418	if (!wgl.makeCurrent(deviceCtx, m_context))
419	{
420		wgl.deleteContext(m_context);
421		throw ResourceError("wglMakeCurrent() failed");
422	}
423}
424
425Context::~Context (void)
426{
427	const Functions& wgl = m_core->getLibrary()->getFunctions();
428
429	wgl.makeCurrent(m_deviceCtx, NULL);
430	wgl.deleteContext(m_context);
431}
432
433FunctionPtr Context::getGLFunction (const char* name) const
434{
435	FunctionPtr ptr = DE_NULL;
436
437	// Try first with wglGeProcAddress()
438	ptr = (FunctionPtr)m_core->getLibrary()->getFunctions().getProcAddress(name);
439
440	// Fall-back to dynlib
441	if (!ptr)
442		ptr = (FunctionPtr)m_core->getLibrary()->getGLLibrary().getFunction(name);
443
444	return ptr;
445}
446
447void Context::swapBuffers (void) const
448{
449	const Functions& wgl = m_core->getLibrary()->getFunctions();
450	if (!wgl.swapLayerBuffers(m_deviceCtx, WGL_SWAP_MAIN_PLANE))
451		throw ResourceError("wglSwapBuffers() failed");
452}
453
454int choosePixelFormat (const Core& wgl, HDC deviceCtx, const glu::RenderConfig& config)
455{
456	std::vector<int> pixelFormats = wgl.getPixelFormats(deviceCtx);
457
458	for (std::vector<int>::const_iterator fmtIter = pixelFormats.begin(); fmtIter != pixelFormats.end(); ++fmtIter)
459	{
460		PixelFormatInfo info = wgl.getPixelFormatInfo(deviceCtx, *fmtIter);
461
462		// Base rules: Must be OpenGL-compatible, RGBA, double-buffered, and window-renderable
463		if (!info.supportOpenGL											||
464			!(info.pixelType == wgl::PixelFormatInfo::PIXELTYPE_RGBA)	||
465			!info.doubleBuffer											||
466			!(info.surfaceTypes & wgl::PixelFormatInfo::SURFACE_WINDOW))
467			continue;
468
469		if (config.redBits != glu::RenderConfig::DONT_CARE &&
470			config.redBits != info.redBits)
471			continue;
472
473		if (config.greenBits != glu::RenderConfig::DONT_CARE &&
474			config.greenBits != info.greenBits)
475			continue;
476
477		if (config.blueBits != glu::RenderConfig::DONT_CARE &&
478			config.blueBits != info.blueBits)
479			continue;
480
481		if (config.alphaBits != glu::RenderConfig::DONT_CARE &&
482			config.alphaBits != info.alphaBits)
483			continue;
484
485		if (config.depthBits != glu::RenderConfig::DONT_CARE &&
486			config.depthBits != info.depthBits)
487			continue;
488
489		if (config.stencilBits != glu::RenderConfig::DONT_CARE &&
490			config.stencilBits != info.stencilBits)
491			continue;
492
493		if (config.numSamples != glu::RenderConfig::DONT_CARE &&
494			config.numSamples != info.samples)
495			continue;
496
497		// Passed all tests - select this.
498		return info.pixelFormat;
499	}
500
501	return -1;
502}
503
504} // wgl
505} // tcu
506