Home | History | Annotate | Download | only in egl
      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:
    108 	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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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>
    743 const Factory* selectFactory (const tcu::FactoryRegistry<Factory>& registry, const char* objectTypeName, const char* cmdLineArg)
    744 {
    745 	if (cmdLineArg[0] != 0)
    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 
    769 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