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 GL context factory using EGL.
22 *//*--------------------------------------------------------------------*/
23
24#include "egluGLContextFactory.hpp"
25
26#include "tcuRenderTarget.hpp"
27#include "tcuPlatform.hpp"
28#include "tcuCommandLine.hpp"
29
30#include "gluDefs.hpp"
31
32#include "egluDefs.hpp"
33#include "egluHeaderWrapper.hpp"
34#include "egluUtil.hpp"
35#include "egluNativeWindow.hpp"
36#include "egluNativePixmap.hpp"
37#include "egluStrUtil.hpp"
38
39#include "glwInitFunctions.hpp"
40#include "glwInitES20Direct.hpp"
41#include "glwInitES30Direct.hpp"
42
43#include "deDynamicLibrary.hpp"
44#include "deSTLUtil.hpp"
45
46#include <string>
47#include <string>
48#include <sstream>
49
50using std::string;
51using std::vector;
52
53#if !defined(EGL_KHR_create_context)
54	#define EGL_KHR_create_context 1
55	#define EGL_CONTEXT_MAJOR_VERSION_KHR						0x3098
56	#define EGL_CONTEXT_MINOR_VERSION_KHR						0x30FB
57	#define EGL_CONTEXT_FLAGS_KHR								0x30FC
58	#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR					0x30FD
59	#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR	0x31BD
60	#define EGL_NO_RESET_NOTIFICATION_KHR						0x31BE
61	#define EGL_LOSE_CONTEXT_ON_RESET_KHR						0x31BF
62	#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR					0x00000001
63	#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR		0x00000002
64	#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR			0x00000004
65	#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR				0x00000001
66	#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR	0x00000002
67	#define EGL_OPENGL_ES3_BIT_KHR								0x00000040
68#endif // EGL_KHR_create_context
69
70// \todo [2014-03-12 pyry] Use command line arguments for libraries?
71
72// Default library names
73#if !defined(DEQP_GLES2_LIBRARY_PATH)
74#	if (DE_OS == DE_OS_WIN32)
75#		define DEQP_GLES2_LIBRARY_PATH "libGLESv2.dll"
76#	else
77#		define DEQP_GLES2_LIBRARY_PATH "libGLESv2.so"
78#	endif
79#endif
80
81#if !defined(DEQP_GLES3_LIBRARY_PATH)
82#	define DEQP_GLES3_LIBRARY_PATH DEQP_GLES2_LIBRARY_PATH
83#endif
84
85#if !defined(DEQP_OPENGL_LIBRARY_PATH)
86#	if (DE_OS == DE_OS_WIN32)
87#		define DEQP_OPENGL_LIBRARY_PATH "opengl32.dll"
88#	else
89#		define DEQP_OPENGL_LIBRARY_PATH "libGL.so"
90#	endif
91#endif
92
93namespace eglu
94{
95
96namespace
97{
98
99enum
100{
101	DEFAULT_OFFSCREEN_WIDTH		= 512,
102	DEFAULT_OFFSCREEN_HEIGHT	= 512
103};
104
105class GetProcFuncLoader : public glw::FunctionLoader
106{
107public:
108	glw::GenericFuncType get (const char* name) const
109	{
110		return (glw::GenericFuncType)eglGetProcAddress(name);
111	}
112};
113
114class DynamicFuncLoader : public glw::FunctionLoader
115{
116public:
117	DynamicFuncLoader	(de::DynamicLibrary* library)
118		: m_library(library)
119	{
120	}
121
122	glw::GenericFuncType get (const char* name) const
123	{
124		return (glw::GenericFuncType)m_library->getFunction(name);
125	}
126
127private:
128	de::DynamicLibrary*	m_library;
129};
130
131class RenderContext : public GLRenderContext
132{
133public:
134										RenderContext			(const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config);
135	virtual								~RenderContext			(void);
136
137	virtual glu::ContextType			getType					(void) const { return m_renderConfig.type;	}
138	virtual const glw::Functions&		getFunctions			(void) const { return m_glFunctions;		}
139	virtual const tcu::RenderTarget&	getRenderTarget			(void) const { return m_glRenderTarget;		}
140	virtual void						postIterate				(void);
141
142	virtual EGLDisplay					getEGLDisplay			(void) const { return m_eglDisplay;			}
143	virtual EGLContext					getEGLContext			(void) const { return m_eglContext;			}
144
145private:
146	void								create					(const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config);
147	void								destroy					(void);
148
149	const glu::RenderConfig				m_renderConfig;
150	const NativeWindowFactory* const	m_nativeWindowFactory;	// Stored in case window must be re-created
151
152	NativeDisplay*						m_display;
153	NativeWindow*						m_window;
154	NativePixmap*						m_pixmap;
155
156	EGLDisplay							m_eglDisplay;
157	EGLConfig							m_eglConfig;
158	EGLSurface							m_eglSurface;
159	EGLContext							m_eglContext;
160
161	tcu::RenderTarget					m_glRenderTarget;
162	de::DynamicLibrary*					m_dynamicGLLibrary;
163	glw::Functions						m_glFunctions;
164};
165
166RenderContext::RenderContext (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config)
167	: m_renderConfig		(config)
168	, m_nativeWindowFactory	(windowFactory)
169	, m_display				(DE_NULL)
170	, m_window				(DE_NULL)
171	, m_pixmap				(DE_NULL)
172
173	, m_eglDisplay			(EGL_NO_DISPLAY)
174	, m_eglSurface			(EGL_NO_SURFACE)
175	, m_eglContext			(EGL_NO_CONTEXT)
176
177	, m_dynamicGLLibrary	(DE_NULL)
178{
179	DE_ASSERT(displayFactory);
180
181	try
182	{
183		create(displayFactory, windowFactory, pixmapFactory, config);
184	}
185	catch (...)
186	{
187		destroy();
188		throw;
189	}
190}
191
192RenderContext::~RenderContext(void)
193{
194	try
195	{
196		destroy();
197	}
198	catch (...)
199	{
200		// destroy() calls EGL functions that are checked and may throw exceptions
201	}
202
203	delete m_window;
204	delete m_pixmap;
205	delete m_display;
206	delete m_dynamicGLLibrary;
207}
208
209bool configMatches (EGLDisplay display, EGLConfig eglConfig, const glu::RenderConfig& renderConfig)
210{
211	// \todo [2014-03-12 pyry] Check other attributes like double-buffer bit.
212
213	{
214		EGLint		renderableType		= 0;
215		EGLint		requiredRenderable	= 0;
216
217		if (glu::isContextTypeES(renderConfig.type))
218		{
219			if (renderConfig.type.getMajorVersion() == 2)
220				requiredRenderable = EGL_OPENGL_ES2_BIT;
221			else if (renderConfig.type.getMajorVersion() == 3)
222				requiredRenderable = EGL_OPENGL_ES3_BIT_KHR;
223			else
224				throw tcu::NotSupportedError("Unsupported OpenGL ES version");
225		}
226		else
227		{
228			DE_ASSERT(glu::isContextTypeGLCore(renderConfig.type) || glu::isContextTypeGLCompatibility(renderConfig.type));
229			requiredRenderable = EGL_OPENGL_BIT;
230		}
231
232		EGLU_CHECK_CALL(eglGetConfigAttrib(display, eglConfig, EGL_RENDERABLE_TYPE, &renderableType));
233
234		if ((renderableType & requiredRenderable) == 0)
235			return false;
236	}
237
238	if (renderConfig.surfaceType != (glu::RenderConfig::SurfaceType)glu::RenderConfig::DONT_CARE)
239	{
240		EGLint		surfaceType		= 0;
241		EGLint		requiredSurface	= 0;
242
243		switch (renderConfig.surfaceType)
244		{
245			case glu::RenderConfig::SURFACETYPE_WINDOW:				requiredSurface = EGL_WINDOW_BIT;	break;
246			case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:	requiredSurface = EGL_PIXMAP_BIT;	break;
247			case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:	requiredSurface = EGL_PBUFFER_BIT;	break;
248			default:
249				DE_ASSERT(false);
250		}
251
252		EGLU_CHECK_CALL(eglGetConfigAttrib(display, eglConfig, EGL_SURFACE_TYPE, &surfaceType));
253
254		if ((surfaceType & requiredSurface) == 0)
255			return false;
256	}
257
258	{
259		static const struct
260		{
261			int	glu::RenderConfig::*field;
262			EGLint attrib;
263		} s_attribs[] =
264		{
265			{ &glu::RenderConfig::id,			EGL_CONFIG_ID		},
266			{ &glu::RenderConfig::redBits,		EGL_RED_SIZE		},
267			{ &glu::RenderConfig::greenBits,	EGL_GREEN_SIZE		},
268			{ &glu::RenderConfig::blueBits,		EGL_BLUE_SIZE		},
269			{ &glu::RenderConfig::alphaBits,	EGL_ALPHA_SIZE		},
270			{ &glu::RenderConfig::depthBits,	EGL_DEPTH_SIZE		},
271			{ &glu::RenderConfig::stencilBits,	EGL_STENCIL_SIZE	},
272			{ &glu::RenderConfig::numSamples,	EGL_SAMPLES			},
273		};
274
275		for (int attribNdx = 0; attribNdx < DE_LENGTH_OF_ARRAY(s_attribs); attribNdx++)
276		{
277			if (renderConfig.*s_attribs[attribNdx].field != glu::RenderConfig::DONT_CARE)
278			{
279				EGLint value = 0;
280				EGLU_CHECK_CALL(eglGetConfigAttrib(display, eglConfig, s_attribs[attribNdx].attrib, &value));
281				if (value != renderConfig.*s_attribs[attribNdx].field)
282					return false;
283			}
284		}
285	}
286
287	return true;
288}
289
290EGLConfig chooseConfig (EGLDisplay display, const glu::RenderConfig& config)
291{
292	const std::vector<EGLConfig> configs = eglu::getConfigs(display);
293
294	for (vector<EGLConfig>::const_iterator iter = configs.begin(); iter != configs.end(); ++iter)
295	{
296		if (configMatches(display, *iter, config))
297			return *iter;
298	}
299
300	throw tcu::NotSupportedError("Matching EGL config not found", DE_NULL, __FILE__, __LINE__);
301}
302
303static WindowParams::Visibility getNativeWindowVisibility (glu::RenderConfig::Visibility visibility)
304{
305	using glu::RenderConfig;
306
307	switch (visibility)
308	{
309		case RenderConfig::VISIBILITY_HIDDEN:		return WindowParams::VISIBILITY_HIDDEN;
310		case RenderConfig::VISIBILITY_VISIBLE:		return WindowParams::VISIBILITY_VISIBLE;
311		case RenderConfig::VISIBILITY_FULLSCREEN:	return WindowParams::VISIBILITY_FULLSCREEN;
312		default:
313			DE_ASSERT(visibility == (RenderConfig::Visibility)RenderConfig::DONT_CARE);
314			return WindowParams::VISIBILITY_DONT_CARE;
315	}
316}
317
318typedef std::pair<NativeWindow*, EGLSurface> WindowSurfacePair;
319typedef std::pair<NativePixmap*, EGLSurface> PixmapSurfacePair;
320
321WindowSurfacePair createWindow (NativeDisplay* nativeDisplay, const NativeWindowFactory* windowFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config)
322{
323	const int						width			= (config.width		== glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE	: config.width);
324	const int						height			= (config.height	== glu::RenderConfig::DONT_CARE ? WindowParams::SIZE_DONT_CARE	: config.height);
325	const WindowParams::Visibility	visibility		= getNativeWindowVisibility(config.windowVisibility);
326	NativeWindow*					nativeWindow	= DE_NULL;
327	EGLSurface						surface			= EGL_NO_SURFACE;
328	const EGLAttrib					attribList[]	= { EGL_NONE };
329
330	nativeWindow = windowFactory->createWindow(nativeDisplay, eglDisplay, eglConfig, &attribList[0], WindowParams(width, height, visibility));
331
332	try
333	{
334		surface = eglu::createWindowSurface(*nativeDisplay, *nativeWindow, eglDisplay, eglConfig, attribList);
335	}
336	catch (...)
337	{
338		delete nativeWindow;
339		throw;
340	}
341
342	return WindowSurfacePair(nativeWindow, surface);
343}
344
345PixmapSurfacePair createPixmap (NativeDisplay* nativeDisplay, const NativePixmapFactory* pixmapFactory, EGLDisplay eglDisplay, EGLConfig eglConfig, const glu::RenderConfig& config)
346{
347	const int			width			= (config.width		== glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH	: config.width);
348	const int			height			= (config.height	== glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT	: config.height);
349	NativePixmap*		nativePixmap	= DE_NULL;
350	EGLSurface			surface			= EGL_NO_SURFACE;
351	const EGLAttrib		attribList[]	= { EGL_NONE };
352
353	nativePixmap = pixmapFactory->createPixmap(nativeDisplay, eglDisplay, eglConfig, &attribList[0], width, height);
354
355	try
356	{
357		surface = eglu::createPixmapSurface(*nativeDisplay, *nativePixmap, eglDisplay, eglConfig, attribList);
358	}
359	catch (...)
360	{
361		delete nativePixmap;
362		throw;
363	}
364
365	return PixmapSurfacePair(nativePixmap, surface);
366}
367
368EGLSurface createPBuffer (EGLDisplay display, EGLConfig eglConfig, const glu::RenderConfig& config)
369{
370	const int		width			= (config.width		== glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_WIDTH	: config.width);
371	const int		height			= (config.height	== glu::RenderConfig::DONT_CARE ? DEFAULT_OFFSCREEN_HEIGHT	: config.height);
372	EGLSurface		surface;
373	const EGLint	attribList[]	=
374	{
375		EGL_WIDTH,	width,
376		EGL_HEIGHT,	height,
377		EGL_NONE
378	};
379
380	surface = eglCreatePbufferSurface(display, eglConfig, &(attribList[0]));
381	EGLU_CHECK_MSG("eglCreatePbufferSurface()");
382
383	return surface;
384}
385
386bool isClientExtensionSupported (EGLDisplay display, const std::string& extName)
387{
388	const vector<string> exts = getClientExtensions(display);
389	return de::contains(exts.begin(), exts.end(), extName);
390}
391
392EGLContext createContext (EGLDisplay display, EGLContext eglConfig, const glu::RenderConfig& config)
393{
394	const bool			khrCreateContextSupported	= isClientExtensionSupported(display, "EGL_KHR_create_context");
395	EGLContext			context						= EGL_NO_CONTEXT;
396	EGLenum				api							= EGL_NONE;
397	vector<EGLint>		attribList;
398
399	if (glu::isContextTypeES(config.type))
400	{
401		api = EGL_OPENGL_ES_API;
402
403		if (config.type.getMajorVersion() <= 2)
404		{
405			attribList.push_back(EGL_CONTEXT_CLIENT_VERSION);
406			attribList.push_back(config.type.getMajorVersion());
407		}
408		else
409		{
410			if (!khrCreateContextSupported)
411				throw tcu::NotSupportedError("EGL_KHR_create_context is required for OpenGL ES 3.0 and newer", DE_NULL, __FILE__, __LINE__);
412
413			attribList.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
414			attribList.push_back(config.type.getMajorVersion());
415			attribList.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
416			attribList.push_back(config.type.getMinorVersion());
417		}
418	}
419	else
420	{
421		DE_ASSERT(glu::isContextTypeGLCore(config.type) || glu::isContextTypeGLCompatibility(config.type));
422
423		if (!khrCreateContextSupported)
424			throw tcu::NotSupportedError("EGL_KHR_create_context is required for OpenGL context creation", DE_NULL, __FILE__, __LINE__);
425
426		api = EGL_OPENGL_API;
427
428		attribList.push_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
429		attribList.push_back(config.type.getMajorVersion());
430		attribList.push_back(EGL_CONTEXT_MINOR_VERSION_KHR);
431		attribList.push_back(config.type.getMinorVersion());
432		attribList.push_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
433		attribList.push_back(glu::isContextTypeGLCore(config.type) ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR
434																   : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
435	}
436
437	if (config.type.getFlags() != glu::ContextFlags(0))
438	{
439		EGLint flags = 0;
440
441		if (!khrCreateContextSupported)
442			throw tcu::NotSupportedError("EGL_KHR_create_context is required for creating robust/debug/forward-compatible contexts");
443
444		if ((config.type.getFlags() & glu::CONTEXT_DEBUG) != 0)
445			flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
446
447		if ((config.type.getFlags() & glu::CONTEXT_ROBUST) != 0)
448			flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
449
450		if ((config.type.getFlags() & glu::CONTEXT_FORWARD_COMPATIBLE) != 0)
451		{
452			if (!glu::isContextTypeGLCore(config.type))
453				throw tcu::NotSupportedError("Only OpenGL core contexts can be forward-compatible");
454
455			flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
456		}
457
458		attribList.push_back(EGL_CONTEXT_FLAGS_KHR);
459		attribList.push_back(flags);
460	}
461
462	attribList.push_back(EGL_NONE);
463
464	EGLU_CHECK_CALL(eglBindAPI(api));
465	context = eglCreateContext(display, eglConfig, EGL_NO_CONTEXT, &(attribList[0]));
466	EGLU_CHECK_MSG("eglCreateContext()");
467
468	return context;
469}
470
471void RenderContext::create (const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config)
472{
473	glu::RenderConfig::SurfaceType	surfaceType	= config.surfaceType;
474
475	DE_ASSERT(displayFactory);
476
477	m_display		= displayFactory->createDisplay();
478	m_eglDisplay	= eglu::getDisplay(*m_display);
479
480	{
481		EGLint major = 0;
482		EGLint minor = 0;
483		EGLU_CHECK_CALL(eglInitialize(m_eglDisplay, &major, &minor));
484	}
485
486	m_eglConfig	= chooseConfig(m_eglDisplay, config);
487
488	if (surfaceType == glu::RenderConfig::SURFACETYPE_DONT_CARE)
489	{
490		// Choose based on what selected configuration supports
491		const EGLint supportedTypes = eglu::getConfigAttribInt(m_eglDisplay, m_eglConfig, EGL_SURFACE_TYPE);
492
493		if ((supportedTypes & EGL_WINDOW_BIT) != 0)
494			surfaceType = glu::RenderConfig::SURFACETYPE_WINDOW;
495		else if ((supportedTypes & EGL_PBUFFER_BIT) != 0)
496			surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC;
497		else if ((supportedTypes & EGL_PIXMAP_BIT) != 0)
498			surfaceType = glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE;
499		else
500			throw tcu::NotSupportedError("Selected EGL config doesn't support any surface types", DE_NULL, __FILE__, __LINE__);
501	}
502
503	switch (surfaceType)
504	{
505		case glu::RenderConfig::SURFACETYPE_WINDOW:
506		{
507			if (windowFactory)
508			{
509				const WindowSurfacePair windowSurface = createWindow(m_display, windowFactory, m_eglDisplay, m_eglConfig, config);
510				m_window		= windowSurface.first;
511				m_eglSurface	= windowSurface.second;
512			}
513			else
514				throw tcu::NotSupportedError("EGL platform doesn't support windows", DE_NULL, __FILE__, __LINE__);
515			break;
516		}
517
518		case glu::RenderConfig::SURFACETYPE_OFFSCREEN_NATIVE:
519		{
520			if (pixmapFactory)
521			{
522				const PixmapSurfacePair pixmapSurface = createPixmap(m_display, pixmapFactory, m_eglDisplay, m_eglConfig, config);
523				m_pixmap		= pixmapSurface.first;
524				m_eglSurface	= pixmapSurface.second;
525			}
526			else
527				throw tcu::NotSupportedError("EGL platform doesn't support pixmaps", DE_NULL, __FILE__, __LINE__);
528			break;
529		}
530
531		case glu::RenderConfig::SURFACETYPE_OFFSCREEN_GENERIC:
532			m_eglSurface = createPBuffer(m_eglDisplay, m_eglConfig, config);
533			break;
534
535		default:
536			throw tcu::InternalError("Invalid surface type");
537	}
538
539	m_eglContext = createContext(m_eglDisplay, m_eglConfig, config);
540
541	EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
542
543	// Init core functions
544
545	if (isClientExtensionSupported(m_eglDisplay, "EGL_KHR_get_all_proc_addresses"))
546	{
547		// Use eglGetProcAddress() for core functions
548		GetProcFuncLoader funcLoader;
549		glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI());
550	}
551#if !defined(DEQP_GLES2_RUNTIME_LOAD)
552	else if (config.type.getAPI() == glu::ApiType::es(2,0))
553	{
554		glw::initES20Direct(&m_glFunctions);
555	}
556#endif
557#if !defined(DEQP_GLES3_RUNTIME_LOAD)
558	else if (config.type.getAPI() == glu::ApiType::es(3,0))
559	{
560		glw::initES30Direct(&m_glFunctions);
561	}
562#endif
563	else
564	{
565		const char* libraryPath = DE_NULL;
566
567		if (glu::isContextTypeES(config.type))
568		{
569			if (config.type.getMinorVersion() <= 2)
570				libraryPath = DEQP_GLES2_LIBRARY_PATH;
571			else
572				libraryPath = DEQP_GLES3_LIBRARY_PATH;
573		}
574		else
575			libraryPath = DEQP_OPENGL_LIBRARY_PATH;
576
577		m_dynamicGLLibrary = new de::DynamicLibrary(libraryPath);
578
579		DynamicFuncLoader funcLoader(m_dynamicGLLibrary);
580		glu::initCoreFunctions(&m_glFunctions, &funcLoader, config.type.getAPI());
581	}
582
583	// Init extension functions
584	{
585		GetProcFuncLoader extLoader;
586		glu::initExtensionFunctions(&m_glFunctions, &extLoader, config.type.getAPI());
587	}
588
589	{
590		EGLint				width, height, depthBits, stencilBits, numSamples;
591		tcu::PixelFormat	pixelFmt;
592
593		eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH, &width);
594		eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT, &height);
595
596		eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_RED_SIZE,		&pixelFmt.redBits);
597		eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_GREEN_SIZE,	&pixelFmt.greenBits);
598		eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_BLUE_SIZE,	&pixelFmt.blueBits);
599		eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_ALPHA_SIZE,	&pixelFmt.alphaBits);
600
601		eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_DEPTH_SIZE,	&depthBits);
602		eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_STENCIL_SIZE,	&stencilBits);
603		eglGetConfigAttrib(m_eglDisplay, m_eglConfig, EGL_SAMPLES,		&numSamples);
604
605		EGLU_CHECK_MSG("Failed to query config attributes");
606
607		m_glRenderTarget = tcu::RenderTarget(width, height, pixelFmt, depthBits, stencilBits, numSamples);
608	}
609}
610
611void RenderContext::destroy (void)
612{
613	if (m_eglDisplay != EGL_NO_DISPLAY)
614	{
615		EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
616
617		if (m_eglSurface != EGL_NO_SURFACE)
618			EGLU_CHECK_CALL(eglDestroySurface(m_eglDisplay, m_eglSurface));
619
620		if (m_eglContext != EGL_NO_CONTEXT)
621			EGLU_CHECK_CALL(eglDestroyContext(m_eglDisplay, m_eglContext));
622
623		EGLU_CHECK_CALL(eglTerminate(m_eglDisplay));
624
625		m_eglDisplay	= EGL_NO_DISPLAY;
626		m_eglSurface	= EGL_NO_SURFACE;
627		m_eglContext	= EGL_NO_CONTEXT;
628	}
629
630	delete m_window;
631	delete m_pixmap;
632	delete m_display;
633	delete m_dynamicGLLibrary;
634
635	m_window			= DE_NULL;
636	m_pixmap			= DE_NULL;
637	m_display			= DE_NULL;
638	m_dynamicGLLibrary	= DE_NULL;
639}
640
641void RenderContext::postIterate (void)
642{
643	if (m_window)
644	{
645		EGLBoolean	swapOk		= eglSwapBuffers(m_eglDisplay, m_eglSurface);
646		EGLint		error		= eglGetError();
647		const bool	badWindow	= error == EGL_BAD_SURFACE || error == EGL_BAD_NATIVE_WINDOW;
648
649		if (!swapOk && !badWindow)
650			throw tcu::ResourceError(string("eglSwapBuffers() failed: ") + getErrorStr(error).toString());
651
652		try
653		{
654			m_window->processEvents();
655		}
656		catch (const WindowDestroyedError&)
657		{
658			tcu::print("Warning: Window destroyed, recreating...\n");
659
660			EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
661			EGLU_CHECK_CALL(eglDestroySurface(m_eglDisplay, m_eglSurface));
662			m_eglSurface = EGL_NO_SURFACE;
663
664			delete m_window;
665			m_window = DE_NULL;
666
667			try
668			{
669				WindowSurfacePair windowSurface = createWindow(m_display, m_nativeWindowFactory, m_eglDisplay, m_eglConfig, m_renderConfig);
670				m_window		= windowSurface.first;
671				m_eglSurface	= windowSurface.second;
672
673				EGLU_CHECK_CALL(eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext));
674
675				swapOk	= EGL_TRUE;
676				error	= EGL_SUCCESS;
677			}
678			catch (const std::exception& e)
679			{
680				if (m_eglSurface)
681				{
682					eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
683					eglDestroySurface(m_eglDisplay, m_eglSurface);
684					m_eglSurface = EGL_NO_SURFACE;
685				}
686
687				delete m_window;
688				m_window = DE_NULL;
689
690				throw tcu::ResourceError(string("Failed to re-create window: ") + e.what());
691			}
692		}
693
694		if (!swapOk)
695		{
696			DE_ASSERT(badWindow);
697			throw tcu::ResourceError(string("eglSwapBuffers() failed: ") + getErrorStr(error).toString());
698		}
699
700		// Refresh dimensions
701		{
702			int	newWidth	= 0;
703			int	newHeight	= 0;
704
705			eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_WIDTH,	&newWidth);
706			eglQuerySurface(m_eglDisplay, m_eglSurface, EGL_HEIGHT,	&newHeight);
707			EGLU_CHECK_MSG("Failed to query window size");
708
709			if (newWidth	!= m_glRenderTarget.getWidth() ||
710				newHeight	!= m_glRenderTarget.getHeight())
711			{
712				tcu::print("Warning: Window size changed (%dx%d -> %dx%d), test results might be invalid!\n",
713						   m_glRenderTarget.getWidth(), m_glRenderTarget.getHeight(), newWidth, newHeight);
714
715				m_glRenderTarget = tcu::RenderTarget(newWidth, newHeight,
716													 m_glRenderTarget.getPixelFormat(),
717													 m_glRenderTarget.getDepthBits(),
718													 m_glRenderTarget.getStencilBits(),
719													 m_glRenderTarget.getNumSamples());
720			}
721		}
722	}
723	else
724	{
725		// \todo [2014-05-02 mika] Should we call flush or finish? Old platform uses finish() but flush() is closer to the behaviour of eglSwapBuffers()
726		m_glFunctions.flush();
727		GLU_EXPECT_NO_ERROR(m_glFunctions.getError(), "glFlush()");
728	}
729}
730
731} // anonymous
732
733GLContextFactory::GLContextFactory (const NativeDisplayFactoryRegistry& displayFactoryRegistry)
734	: glu::ContextFactory		("egl", "EGL OpenGL Context")
735	, m_displayFactoryRegistry	(displayFactoryRegistry)
736{
737}
738
739namespace
740{
741
742template<typename Factory>
743const Factory* selectFactory (const tcu::FactoryRegistry<Factory>& registry, const char* objectTypeName, const char* cmdLineArg)
744{
745	if (cmdLineArg)
746	{
747		const Factory* factory = registry.getFactoryByName(cmdLineArg);
748
749		if (factory)
750			return factory;
751		else
752		{
753			tcu::print("ERROR: Unknown or unsupported EGL %s type '%s'", objectTypeName, cmdLineArg);
754			tcu::print("Available EGL %s types:\n", objectTypeName);
755			for (size_t ndx = 0; ndx < registry.getFactoryCount(); ndx++)
756				tcu::print("  %s: %s\n", registry.getFactoryByIndex(ndx)->getName(), registry.getFactoryByIndex(ndx)->getDescription());
757
758			throw tcu::NotSupportedError((string("Unsupported or unknown EGL ") + objectTypeName + " type '" + cmdLineArg + "'").c_str(), DE_NULL, __FILE__, __LINE__);
759		}
760	}
761	else if (!registry.empty())
762		return registry.getDefaultFactory();
763	else
764		return DE_NULL;
765}
766
767} // anonymous
768
769glu::RenderContext* GLContextFactory::createContext (const glu::RenderConfig& config, const tcu::CommandLine& cmdLine) const
770{
771	const NativeDisplayFactory* displayFactory = selectFactory(m_displayFactoryRegistry, "display", cmdLine.getEGLDisplayType());
772
773	if (displayFactory)
774	{
775		// \note windowFactory & pixmapFactory are not mandatory
776		const NativeWindowFactory*	windowFactory	= selectFactory(displayFactory->getNativeWindowRegistry(), "window", cmdLine.getEGLWindowType());
777		const NativePixmapFactory*	pixmapFactory	= selectFactory(displayFactory->getNativePixmapRegistry(), "pixmap", cmdLine.getEGLPixmapType());
778
779		return new RenderContext(displayFactory, windowFactory, pixmapFactory, config);
780	}
781	else
782		throw tcu::NotSupportedError("No EGL displays available", DE_NULL, __FILE__, __LINE__);
783}
784
785} // eglu
786