• 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 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 
50 using std::string;
51 using 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 
93 namespace eglu
94 {
95 
96 namespace
97 {
98 
99 enum
100 {
101 	DEFAULT_OFFSCREEN_WIDTH		= 512,
102 	DEFAULT_OFFSCREEN_HEIGHT	= 512
103 };
104 
105 class GetProcFuncLoader : public glw::FunctionLoader
106 {
107 public:
get(const char * name) const108 	glw::GenericFuncType get (const char* name) const
109 	{
110 		return (glw::GenericFuncType)eglGetProcAddress(name);
111 	}
112 };
113 
114 class DynamicFuncLoader : public glw::FunctionLoader
115 {
116 public:
DynamicFuncLoader(de::DynamicLibrary * library)117 	DynamicFuncLoader	(de::DynamicLibrary* library)
118 		: m_library(library)
119 	{
120 	}
121 
get(const char * name) const122 	glw::GenericFuncType get (const char* name) const
123 	{
124 		return (glw::GenericFuncType)m_library->getFunction(name);
125 	}
126 
127 private:
128 	de::DynamicLibrary*	m_library;
129 };
130 
131 class RenderContext : public GLRenderContext
132 {
133 public:
134 										RenderContext			(const NativeDisplayFactory* displayFactory, const NativeWindowFactory* windowFactory, const NativePixmapFactory* pixmapFactory, const glu::RenderConfig& config);
135 	virtual								~RenderContext			(void);
136 
getType(void) const137 	virtual glu::ContextType			getType					(void) const { return m_renderConfig.type;	}
getFunctions(void) const138 	virtual const glw::Functions&		getFunctions			(void) const { return m_glFunctions;		}
getRenderTarget(void) const139 	virtual const tcu::RenderTarget&	getRenderTarget			(void) const { return m_glRenderTarget;		}
140 	virtual void						postIterate				(void);
141 
getEGLDisplay(void) const142 	virtual EGLDisplay					getEGLDisplay			(void) const { return m_eglDisplay;			}
getEGLContext(void) const143 	virtual EGLContext					getEGLContext			(void) const { return m_eglContext;			}
144 
145 private:
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 
RenderContext(const NativeDisplayFactory * displayFactory,const NativeWindowFactory * windowFactory,const NativePixmapFactory * pixmapFactory,const glu::RenderConfig & config)166 RenderContext::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 
~RenderContext(void)192 RenderContext::~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 
configMatches(EGLDisplay display,EGLConfig eglConfig,const glu::RenderConfig & renderConfig)209 bool 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 
chooseConfig(EGLDisplay display,const glu::RenderConfig & config)290 EGLConfig 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 
getNativeWindowVisibility(glu::RenderConfig::Visibility visibility)303 static 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 
318 typedef std::pair<NativeWindow*, EGLSurface> WindowSurfacePair;
319 typedef std::pair<NativePixmap*, EGLSurface> PixmapSurfacePair;
320 
createWindow(NativeDisplay * nativeDisplay,const NativeWindowFactory * windowFactory,EGLDisplay eglDisplay,EGLConfig eglConfig,const glu::RenderConfig & config)321 WindowSurfacePair 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 
createPixmap(NativeDisplay * nativeDisplay,const NativePixmapFactory * pixmapFactory,EGLDisplay eglDisplay,EGLConfig eglConfig,const glu::RenderConfig & config)345 PixmapSurfacePair 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 
createPBuffer(EGLDisplay display,EGLConfig eglConfig,const glu::RenderConfig & config)368 EGLSurface 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 
isClientExtensionSupported(EGLDisplay display,const std::string & extName)386 bool 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 
createContext(EGLDisplay display,EGLContext eglConfig,const glu::RenderConfig & config)392 EGLContext 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 
create(const NativeDisplayFactory * displayFactory,const NativeWindowFactory * windowFactory,const NativePixmapFactory * pixmapFactory,const glu::RenderConfig & config)471 void 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 
destroy(void)611 void 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 
postIterate(void)641 void 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 
GLContextFactory(const NativeDisplayFactoryRegistry & displayFactoryRegistry)733 GLContextFactory::GLContextFactory (const NativeDisplayFactoryRegistry& displayFactoryRegistry)
734 	: glu::ContextFactory		("egl", "EGL OpenGL Context")
735 	, m_displayFactoryRegistry	(displayFactoryRegistry)
736 {
737 }
738 
739 namespace
740 {
741 
742 template<typename Factory>
selectFactory(const tcu::FactoryRegistry<Factory> & registry,const char * objectTypeName,const char * cmdLineArg)743 const 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 
createContext(const glu::RenderConfig & config,const tcu::CommandLine & cmdLine) const769 glu::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