Home | History | Annotate | Download | only in opengl
      1 /*-------------------------------------------------------------------------
      2  * drawElements Quality Program OpenGL ES Utilities
      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 OpenGL ES 3plus wrapper context.
     22  *//*--------------------------------------------------------------------*/
     23 
     24 #include "gluES3PlusWrapperContext.hpp"
     25 #include "gluRenderContext.hpp"
     26 #include "gluRenderConfig.hpp"
     27 #include "glwInitFunctions.hpp"
     28 #include "glwFunctionLoader.hpp"
     29 #include "gluContextFactory.hpp"
     30 #include "gluContextInfo.hpp"
     31 #include "gluShaderUtil.hpp"
     32 #include "deThreadLocal.hpp"
     33 #include "deSTLUtil.hpp"
     34 #include "deUniquePtr.hpp"
     35 #include "glwEnums.hpp"
     36 
     37 #include <sstream>
     38 #include <vector>
     39 #include <string>
     40 #include <cstring>
     41 #include <algorithm>
     42 #include <map>
     43 
     44 namespace glu
     45 {
     46 
     47 namespace es3plus
     48 {
     49 
     50 using std::vector;
     51 using std::string;
     52 
     53 class Context
     54 {
     55 public:
     56 								Context			(const glu::RenderContext& ctx);
     57 								~Context		(void);
     58 
     59 	void						addExtension	(const char* name);
     60 
     61 	const glw::Functions&		gl;			//!< GL 4.3 core context functions.
     62 
     63 	// Wrapper state.
     64 	string						vendor;
     65 	string						version;
     66 	string						renderer;
     67 	string						shadingLanguageVersion;
     68 	string						extensions;
     69 	vector<string>				extensionList;
     70 	bool						primitiveRestartEnabled;
     71 
     72 	deUint32					defaultVAO;
     73 	bool						defaultVAOBound;
     74 
     75 	const glu::GLSLVersion		nativeGLSLVersion;
     76 };
     77 
     78 Context::Context (const glu::RenderContext& ctx)
     79 	: gl						(ctx.getFunctions())
     80 	, vendor					("drawElements")
     81 	, version					("OpenGL ES 3.2")
     82 	, renderer					((const char*)gl.getString(GL_RENDERER))
     83 	, shadingLanguageVersion	("OpenGL ES GLSL ES 3.2")
     84 	, primitiveRestartEnabled	(false)
     85 	, defaultVAO				(0)
     86 	, defaultVAOBound			(false)
     87 	, nativeGLSLVersion			(glu::getContextTypeGLSLVersion(ctx.getType()))
     88 {
     89 	const de::UniquePtr<glu::ContextInfo> ctxInfo(glu::ContextInfo::create(ctx));
     90 
     91 	gl.genVertexArrays(1, &defaultVAO);
     92 	if (gl.getError() != GL_NO_ERROR || defaultVAO == 0)
     93 		throw tcu::InternalError("Failed to allocate VAO for emulation");
     94 
     95 	gl.bindVertexArray(defaultVAO);
     96 	if (gl.getError() != GL_NO_ERROR)
     97 		throw tcu::InternalError("Failed to bind default VAO");
     98 	defaultVAOBound = true;
     99 
    100 	gl.enable(GL_PROGRAM_POINT_SIZE);
    101 	gl.getError(); // supress potential errors, feature is not critical
    102 
    103 	gl.enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
    104 	gl.getError(); // suppress
    105 
    106 	// Extensions
    107 	addExtension("GL_OES_texture_stencil8");
    108 	addExtension("GL_OES_sample_shading");
    109 	addExtension("GL_OES_sample_variables");
    110 	addExtension("GL_OES_shader_multisample_interpolation");
    111 	addExtension("GL_OES_shader_image_atomic");
    112 	addExtension("GL_OES_texture_storage_multisample_2d_array");
    113 
    114 	// Enable only if base ctx supports these or compatible GL_NV_blend_equation_advanced ext
    115 	if (ctxInfo->isExtensionSupported("GL_NV_blend_equation_advanced") ||
    116 		ctxInfo->isExtensionSupported("GL_KHR_blend_equation_advanced"))
    117 	{
    118 		addExtension("GL_KHR_blend_equation_advanced");
    119 	}
    120 	if (ctxInfo->isExtensionSupported("GL_NV_blend_equation_advanced_coherent") ||
    121 		ctxInfo->isExtensionSupported("GL_KHR_blend_equation_advanced_coherent"))
    122 	{
    123 		addExtension("GL_KHR_blend_equation_advanced_coherent");
    124 	}
    125 
    126 	addExtension("GL_EXT_shader_io_blocks");
    127 	addExtension("GL_EXT_geometry_shader");
    128 	addExtension("GL_EXT_geometry_point_size");
    129 	addExtension("GL_EXT_tessellation_shader");
    130 	addExtension("GL_EXT_tessellation_point_size");
    131 	addExtension("GL_EXT_gpu_shader5");
    132 	addExtension("GL_KHR_debug");
    133 	addExtension("GL_EXT_texture_cube_map_array");
    134 	addExtension("GL_EXT_shader_implicit_conversions");
    135 	addExtension("GL_EXT_primitive_bounding_box");
    136 	addExtension("GL_EXT_texture_sRGB_decode");
    137 	addExtension("GL_EXT_texture_border_clamp");
    138 	addExtension("GL_EXT_texture_buffer");
    139 	addExtension("GL_EXT_draw_buffers_indexed");
    140 }
    141 
    142 Context::~Context (void)
    143 {
    144 	if (defaultVAO)
    145 		gl.deleteVertexArrays(1, &defaultVAO);
    146 }
    147 
    148 void Context::addExtension (const char* name)
    149 {
    150 	if (!extensions.empty())
    151 		extensions += " ";
    152 	extensions += name;
    153 
    154 	extensionList.push_back(name);
    155 }
    156 
    157 static de::ThreadLocal tls_context;
    158 
    159 void setCurrentContext (Context* context)
    160 {
    161 	tls_context.set(context);
    162 }
    163 
    164 inline Context* getCurrentContext (void)
    165 {
    166 	return (Context*)tls_context.get();
    167 }
    168 
    169 static GLW_APICALL void GLW_APIENTRY getIntegerv (deUint32 pname, deInt32* params)
    170 {
    171 	Context* context = getCurrentContext();
    172 
    173 	if (context)
    174 	{
    175 		if (pname == GL_NUM_EXTENSIONS && params)
    176 			*params = (deInt32)context->extensionList.size();
    177 		else
    178 			context->gl.getIntegerv(pname, params);
    179 	}
    180 }
    181 
    182 static GLW_APICALL const glw::GLubyte* GLW_APIENTRY getString (deUint32 name)
    183 {
    184 	Context* context = getCurrentContext();
    185 
    186 	if (context)
    187 	{
    188 		switch (name)
    189 		{
    190 			case GL_VENDOR:						return (const glw::GLubyte*)context->vendor.c_str();
    191 			case GL_VERSION:					return (const glw::GLubyte*)context->version.c_str();
    192 			case GL_RENDERER:					return (const glw::GLubyte*)context->renderer.c_str();
    193 			case GL_SHADING_LANGUAGE_VERSION:	return (const glw::GLubyte*)context->shadingLanguageVersion.c_str();
    194 			case GL_EXTENSIONS:					return (const glw::GLubyte*)context->extensions.c_str();
    195 			default:							return context->gl.getString(name);
    196 		}
    197 	}
    198 	else
    199 		return DE_NULL;
    200 }
    201 
    202 static GLW_APICALL const glw::GLubyte* GLW_APIENTRY getStringi (deUint32 name, deUint32 index)
    203 {
    204 	Context* context = getCurrentContext();
    205 
    206 	if (context)
    207 	{
    208 		if (name == GL_EXTENSIONS)
    209 		{
    210 			if ((size_t)index < context->extensionList.size())
    211 				return (const glw::GLubyte*)context->extensionList[index].c_str();
    212 			else
    213 				return context->gl.getStringi(name, ~0u);
    214 		}
    215 		else
    216 			return context->gl.getStringi(name, index);
    217 	}
    218 	else
    219 		return DE_NULL;
    220 }
    221 
    222 static GLW_APICALL void GLW_APIENTRY enable (deUint32 cap)
    223 {
    224 	Context* context = getCurrentContext();
    225 
    226 	if (context)
    227 	{
    228 		if (cap == GL_PRIMITIVE_RESTART_FIXED_INDEX)
    229 		{
    230 			context->primitiveRestartEnabled = true;
    231 			// \todo [2013-09-30 pyry] Call to glPrimitiveRestartIndex() is required prior to all draw calls!
    232 		}
    233 		else
    234 			context->gl.enable(cap);
    235 	}
    236 }
    237 
    238 static GLW_APICALL void GLW_APIENTRY disable (deUint32 cap)
    239 {
    240 	Context* context = getCurrentContext();
    241 
    242 	if (context)
    243 	{
    244 		if (cap == GL_PRIMITIVE_RESTART_FIXED_INDEX)
    245 			context->primitiveRestartEnabled = false;
    246 		else
    247 			context->gl.disable(cap);
    248 	}
    249 }
    250 
    251 static GLW_APICALL void GLW_APIENTRY bindVertexArray (deUint32 array)
    252 {
    253 	Context* context = getCurrentContext();
    254 
    255 	if (context)
    256 	{
    257 		context->gl.bindVertexArray(array == 0 ? context->defaultVAO : array);
    258 		context->defaultVAOBound = (array == 0);
    259 	}
    260 }
    261 
    262 static GLW_APICALL void GLW_APIENTRY hint (deUint32 target, deUint32 mode)
    263 {
    264 	Context* context = getCurrentContext();
    265 
    266 	if (context)
    267 	{
    268 		if (target != GL_GENERATE_MIPMAP_HINT)
    269 			context->gl.hint(target, mode);
    270 		// \todo [2013-09-30 pyry] Verify mode.
    271 	}
    272 }
    273 
    274 static void translateShaderSource (deUint32 shaderType, std::ostream& dst, const std::string& src, const std::vector<std::string>& filteredExtensions, GLSLVersion version)
    275 {
    276 	bool				foundVersion		= false;
    277 	std::istringstream	istr				(src);
    278 	std::string			line;
    279 	int					srcLineNdx			= 1;
    280 	bool				preprocessorSection	= true;
    281 
    282 	while (std::getline(istr, line, '\n'))
    283 	{
    284 		if (preprocessorSection && !line.empty() && line[0] != '#')
    285 		{
    286 			preprocessorSection = false;
    287 
    288 			// ARB_separate_shader_objects requires gl_PerVertex to be explicitly declared
    289 			if (shaderType == GL_VERTEX_SHADER)
    290 			{
    291 				dst << "out gl_PerVertex {\n"
    292 					<< "    vec4 gl_Position;\n"
    293 					<< "    float gl_PointSize;\n"
    294 					<< "    float gl_ClipDistance[];\n"
    295 					<< "};\n"
    296 					<< "#line " << (srcLineNdx + 1) << "\n";
    297 			}
    298 			else if (shaderType == GL_TESS_CONTROL_SHADER)
    299 			{
    300 				dst << "#extension GL_ARB_tessellation_shader : enable\n"
    301 					<< "in gl_PerVertex {\n"
    302 					<< "	highp vec4 gl_Position;\n"
    303 					<< "	highp float gl_PointSize;\n"
    304 					<< "} gl_in[gl_MaxPatchVertices];\n"
    305 					<< "out gl_PerVertex {\n"
    306 					<< "	highp vec4 gl_Position;\n"
    307 					<< "	highp float gl_PointSize;\n"
    308 					<< "} gl_out[];\n"
    309 					<< "#line " << (srcLineNdx + 1) << "\n";
    310 			}
    311 			else if (shaderType == GL_TESS_EVALUATION_SHADER)
    312 			{
    313 				dst << "#extension GL_ARB_tessellation_shader : enable\n"
    314 					<< "in gl_PerVertex {\n"
    315 					<< "	highp vec4 gl_Position;\n"
    316 					<< "	highp float gl_PointSize;\n"
    317 					<< "} gl_in[gl_MaxPatchVertices];\n"
    318 					<< "out gl_PerVertex {\n"
    319 					<< "	highp vec4 gl_Position;\n"
    320 					<< "	highp float gl_PointSize;\n"
    321 					<< "};\n"
    322 					<< "#line " << (srcLineNdx + 1) << "\n";
    323 			}
    324 			else if (shaderType == GL_GEOMETRY_SHADER)
    325 			{
    326 				dst << "in gl_PerVertex {\n"
    327 					<< "	highp vec4 gl_Position;\n"
    328 					<< "	highp float gl_PointSize;\n"
    329 					<< "} gl_in[];\n"
    330 					<< "out gl_PerVertex {\n"
    331 					<< "	highp vec4 gl_Position;\n"
    332 					<< "	highp float gl_PointSize;\n"
    333 					<< "};\n"
    334 					<< "#line " << (srcLineNdx + 1) << "\n";
    335 			}
    336 
    337 			// GL_EXT_primitive_bounding_box tessellation no-op fallback
    338 			if (shaderType == GL_TESS_CONTROL_SHADER)
    339 			{
    340 				dst << "#define gl_BoundingBoxEXT _dummy_unused_output_for_primitive_bbox\n"
    341 					<< "patch out vec4 _dummy_unused_output_for_primitive_bbox[2];\n"
    342 					<< "#line " << (srcLineNdx + 1) << "\n";
    343 			}
    344 		}
    345 
    346 		if (line == "#version 310 es" || line == "#version 320 es")
    347 		{
    348 			foundVersion = true;
    349 			dst << glu::getGLSLVersionDeclaration(version) << "\n";
    350 		}
    351 		else if (line == "#version 300 es")
    352 		{
    353 			foundVersion = true;
    354 			dst << "#version 330\n";
    355 		}
    356 		else if (line.substr(0, 10) == "precision ")
    357 		{
    358 			const size_t	precPos		= 10;
    359 			const size_t	precEndPos	= line.find(' ', precPos);
    360 			const size_t	endPos		= line.find(';');
    361 
    362 			if (precEndPos != std::string::npos && endPos != std::string::npos && endPos > precEndPos+1)
    363 			{
    364 				const size_t		typePos		= precEndPos+1;
    365 				const std::string	precision	= line.substr(precPos, precEndPos-precPos);
    366 				const std::string	type		= line.substr(typePos, endPos-typePos);
    367 				const bool			precOk		= precision == "lowp" || precision == "mediump" || precision == "highp";
    368 
    369 				if (precOk &&
    370 					(type == "image2D" || type == "uimage2D" || type == "iimage2D" ||
    371 					 type == "imageCube" || type == "uimageCube" || type == "iimageCube" ||
    372 					 type == "image3D" || type == "iimage3D" || type == "uimage3D" ||
    373 					 type == "image2DArray" || type == "iimage2DArray" || type == "uimage2DArray" ||
    374 					 type == "imageCubeArray" || type == "iimageCubeArray" || type == "uimageCubeArray"))
    375 					dst << "// "; // Filter out statement
    376 			}
    377 
    378 			dst << line << "\n";
    379 		}
    380 		else if (line.substr(0, 11) == "#extension ")
    381 		{
    382 			const size_t	extNamePos		= 11;
    383 			const size_t	extNameEndPos	= line.find_first_of(" :", extNamePos);
    384 			const size_t	behaviorPos		= line.find_first_not_of(" :", extNameEndPos);
    385 
    386 			if (extNameEndPos != std::string::npos && behaviorPos != std::string::npos)
    387 			{
    388 				const std::string	extName				= line.substr(extNamePos, extNameEndPos-extNamePos);
    389 				const std::string	behavior			= line.substr(behaviorPos);
    390 				const bool			filteredExtension	= de::contains(filteredExtensions.begin(), filteredExtensions.end(), extName);
    391 				const bool			validBehavior		= behavior == "require" || behavior == "enable" || behavior == "warn" || behavior == "disable";
    392 
    393 				if (filteredExtension && validBehavior)
    394 					dst << "// "; // Filter out extension
    395 			}
    396 			dst << line << "\n";
    397 		}
    398 		else if (line.substr(0, 21) == "layout(blend_support_")
    399 			dst << "// " << line << "\n";
    400 		else
    401 			dst << line << "\n";
    402 
    403 		srcLineNdx += 1;
    404 	}
    405 
    406 	DE_ASSERT(foundVersion);
    407 	DE_UNREF(foundVersion);
    408 }
    409 
    410 static std::string translateShaderSources (deUint32 shaderType, deInt32 count, const char* const* strings, const int* length, const std::vector<std::string>& filteredExtensions, GLSLVersion version)
    411 {
    412 	std::ostringstream	srcIn;
    413 	std::ostringstream	srcOut;
    414 
    415 	for (int ndx = 0; ndx < count; ndx++)
    416 	{
    417 		const int len = length && length[ndx] >= 0 ? length[ndx] : (int)strlen(strings[ndx]);
    418 		srcIn << std::string(strings[ndx], strings[ndx] + len);
    419 	}
    420 
    421 	translateShaderSource(shaderType, srcOut, srcIn.str(), filteredExtensions, version);
    422 
    423 	return srcOut.str();
    424 }
    425 
    426 static GLW_APICALL void GLW_APIENTRY shaderSource (deUint32 shader, deInt32 count, const char* const* strings, const int* length)
    427 {
    428 	Context* context = getCurrentContext();
    429 
    430 	if (context)
    431 	{
    432 		if (count > 0 && strings)
    433 		{
    434 			deInt32				shaderType = GL_NONE;
    435 			context->gl.getShaderiv(shader, GL_SHADER_TYPE, &shaderType);
    436 			{
    437 				const std::string	translatedSrc	= translateShaderSources(shaderType, count, strings, length, context->extensionList, context->nativeGLSLVersion);
    438 				const char*			srcPtr			= translatedSrc.c_str();
    439 				context->gl.shaderSource(shader, 1, &srcPtr, DE_NULL);
    440 			}
    441 		}
    442 		else
    443 			context->gl.shaderSource(shader, count, strings, length);
    444 	}
    445 }
    446 
    447 static GLW_APICALL void GLW_APIENTRY bindFramebuffer (deUint32 target, deUint32 framebuffer)
    448 {
    449 	Context* context = getCurrentContext();
    450 
    451 	if (context)
    452 	{
    453 		context->gl.bindFramebuffer(target, framebuffer);
    454 
    455 		// Emulate ES behavior where sRGB conversion is only controlled by color buffer format.
    456 		if (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER || target == GL_READ_FRAMEBUFFER)
    457 			((framebuffer != 0) ? context->gl.enable : context->gl.disable)(GL_FRAMEBUFFER_SRGB);
    458 	}
    459 }
    460 
    461 static GLW_APICALL void GLW_APIENTRY blendBarrierKHR (void)
    462 {
    463 	Context* context = getCurrentContext();
    464 
    465 	if (context)
    466 	{
    467 		// \todo [2014-03-18 pyry] Use BlendBarrierNV() if supported
    468 		context->gl.finish();
    469 	}
    470 }
    471 
    472 static GLW_APICALL deUint32 GLW_APIENTRY createShaderProgramv (deUint32 type, deInt32 count, const char* const* strings)
    473 {
    474 	Context* context = getCurrentContext();
    475 
    476 	if (context)
    477 	{
    478 		if (count > 0 && strings)
    479 		{
    480 			const std::string	translatedSrc	= translateShaderSources(type, count, strings, DE_NULL, context->extensionList, context->nativeGLSLVersion);
    481 			const char*			srcPtr			= translatedSrc.c_str();
    482 			return context->gl.createShaderProgramv(type, 1, &srcPtr);
    483 		}
    484 		else
    485 			return context->gl.createShaderProgramv(type, count, strings);
    486 	}
    487 	return 0;
    488 }
    489 
    490 static GLW_APICALL void GLW_APIENTRY dummyPrimitiveBoundingBox (float minX, float minY, float minZ, float minW, float maxX, float maxY, float maxZ, float maxW)
    491 {
    492 	// dummy no-op. No-op is a valid implementation. States queries are not emulated.
    493 	DE_UNREF(minX);
    494 	DE_UNREF(minY);
    495 	DE_UNREF(minZ);
    496 	DE_UNREF(minW);
    497 	DE_UNREF(maxX);
    498 	DE_UNREF(maxY);
    499 	DE_UNREF(maxZ);
    500 	DE_UNREF(maxW);
    501 }
    502 
    503 static void initFunctions (glw::Functions* dst, const glw::Functions& src)
    504 {
    505 	// Functions directly passed to GL context.
    506 #include "gluES3PlusWrapperFuncs.inl"
    507 
    508 	// Wrapped functions.
    509 	dst->bindVertexArray		= bindVertexArray;
    510 	dst->disable				= disable;
    511 	dst->enable					= enable;
    512 	dst->getIntegerv			= getIntegerv;
    513 	dst->getString				= getString;
    514 	dst->getStringi				= getStringi;
    515 	dst->hint					= hint;
    516 	dst->shaderSource			= shaderSource;
    517 	dst->createShaderProgramv	= createShaderProgramv;
    518 	dst->bindFramebuffer		= bindFramebuffer;
    519 
    520 	// Extension functions
    521 	{
    522 		using std::map;
    523 
    524 		class ExtFuncLoader : public glw::FunctionLoader
    525 		{
    526 		public:
    527 			ExtFuncLoader (const map<string, glw::GenericFuncType>& extFuncs)
    528 				: m_extFuncs(extFuncs)
    529 			{
    530 			}
    531 
    532 			glw::GenericFuncType get (const char* name) const
    533 			{
    534 				map<string, glw::GenericFuncType>::const_iterator pos = m_extFuncs.find(name);
    535 				return pos != m_extFuncs.end() ? pos->second : DE_NULL;
    536 			}
    537 
    538 		private:
    539 			const map<string, glw::GenericFuncType>& m_extFuncs;
    540 		};
    541 
    542 		map<string, glw::GenericFuncType>	extFuncMap;
    543 		const ExtFuncLoader					extFuncLoader	(extFuncMap);
    544 
    545 		// OES_sample_shading
    546 		extFuncMap["glMinSampleShadingOES"]			= (glw::GenericFuncType)src.minSampleShading;
    547 
    548 		// OES_texture_storage_multisample_2d_array
    549 		extFuncMap["glTexStorage3DMultisampleOES"]	= (glw::GenericFuncType)src.texStorage3DMultisample;
    550 
    551 		// KHR_blend_equation_advanced
    552 		extFuncMap["glBlendBarrierKHR"]				= (glw::GenericFuncType)blendBarrierKHR;
    553 
    554 		// EXT_tessellation_shader
    555 		extFuncMap["glPatchParameteriEXT"]			= (glw::GenericFuncType)src.patchParameteri;
    556 
    557 		// EXT_geometry_shader
    558 		extFuncMap["glFramebufferTextureEXT"]		= (glw::GenericFuncType)src.framebufferTexture;
    559 
    560 		// KHR_debug
    561 		extFuncMap["glDebugMessageControlKHR"]		= (glw::GenericFuncType)src.debugMessageControl;
    562 		extFuncMap["glDebugMessageInsertKHR"]		= (glw::GenericFuncType)src.debugMessageInsert;
    563 		extFuncMap["glDebugMessageCallbackKHR"]		= (glw::GenericFuncType)src.debugMessageCallback;
    564 		extFuncMap["glGetDebugMessageLogKHR"]		= (glw::GenericFuncType)src.getDebugMessageLog;
    565 		extFuncMap["glGetPointervKHR"] 				= (glw::GenericFuncType)src.getPointerv;
    566 		extFuncMap["glPushDebugGroupKHR"]			= (glw::GenericFuncType)src.pushDebugGroup;
    567 		extFuncMap["glPopDebugGroupKHR"] 			= (glw::GenericFuncType)src.popDebugGroup;
    568 		extFuncMap["glObjectLabelKHR"] 				= (glw::GenericFuncType)src.objectLabel;
    569 		extFuncMap["glGetObjectLabelKHR"]			= (glw::GenericFuncType)src.getObjectLabel;
    570 		extFuncMap["glObjectPtrLabelKHR"]			= (glw::GenericFuncType)src.objectPtrLabel;
    571 		extFuncMap["glGetObjectPtrLabelKHR"]		= (glw::GenericFuncType)src.getObjectPtrLabel;
    572 
    573 		// GL_EXT_primitive_bounding_box (dummy no-op)
    574 		extFuncMap["glPrimitiveBoundingBoxEXT"]		= (glw::GenericFuncType)dummyPrimitiveBoundingBox;
    575 
    576 		// GL_EXT_texture_border_clamp
    577 		extFuncMap["glTexParameterIivEXT"]			= (glw::GenericFuncType)src.texParameterIiv;
    578 		extFuncMap["glTexParameterIuivEXT"]			= (glw::GenericFuncType)src.texParameterIuiv;
    579 		extFuncMap["glGetTexParameterIivEXT"]		= (glw::GenericFuncType)src.getTexParameterIiv;
    580 		extFuncMap["glGetTexParameterIuivEXT"]		= (glw::GenericFuncType)src.getTexParameterIuiv;
    581 		extFuncMap["glSamplerParameterIivEXT"]		= (glw::GenericFuncType)src.samplerParameterIiv;
    582 		extFuncMap["glSamplerParameterIuivEXT"]		= (glw::GenericFuncType)src.samplerParameterIuiv;
    583 		extFuncMap["glGetSamplerParameterIivEXT"]	= (glw::GenericFuncType)src.getSamplerParameterIiv;
    584 		extFuncMap["glGetSamplerParameterIuivEXT"]	= (glw::GenericFuncType)src.getSamplerParameterIuiv;
    585 
    586 		// GL_EXT_texture_buffer
    587 		extFuncMap["glTexBufferEXT"]				= (glw::GenericFuncType)src.texBuffer;
    588 		extFuncMap["glTexBufferRangeEXT"]			= (glw::GenericFuncType)src.texBufferRange;
    589 
    590 		// GL_EXT_draw_buffers_indexed
    591 		extFuncMap["glEnableiEXT"]					= (glw::GenericFuncType)src.enablei;
    592 		extFuncMap["glDisableiEXT"]					= (glw::GenericFuncType)src.disablei;
    593 		extFuncMap["glBlendEquationiEXT"]			= (glw::GenericFuncType)src.blendEquationi;
    594 		extFuncMap["glBlendEquationSeparateiEXT"]	= (glw::GenericFuncType)src.blendEquationSeparatei;
    595 		extFuncMap["glBlendFunciEXT"]				= (glw::GenericFuncType)src.blendFunci;
    596 		extFuncMap["glBlendFuncSeparateiEXT"]		= (glw::GenericFuncType)src.blendFuncSeparatei;
    597 		extFuncMap["glColorMaskiEXT"]				= (glw::GenericFuncType)src.colorMaski;
    598 		extFuncMap["glIsEnablediEXT"]				= (glw::GenericFuncType)src.isEnabledi;
    599 
    600 		{
    601 			int	numExts	= 0;
    602 			dst->getIntegerv(GL_NUM_EXTENSIONS, &numExts);
    603 
    604 			if (numExts > 0)
    605 			{
    606 				vector<const char*> extStr(numExts);
    607 
    608 				for (int ndx = 0; ndx < numExts; ndx++)
    609 					extStr[ndx] = (const char*)dst->getStringi(GL_EXTENSIONS, ndx);
    610 
    611 				glw::initExtensionsES(dst, &extFuncLoader, (int)extStr.size(), &extStr[0]);
    612 			}
    613 		}
    614 	}
    615 }
    616 
    617 } // es3plus
    618 
    619 ES3PlusWrapperContext::ES3PlusWrapperContext (const ContextFactory& factory, const RenderConfig& config, const tcu::CommandLine& cmdLine)
    620 	: m_context		(DE_NULL)
    621 	, m_wrapperCtx	(DE_NULL)
    622 {
    623 	// Flags that are valid for both core & es context. Currently only excludes CONTEXT_FORWARD_COMPATIBLE
    624 	const ContextFlags validContextFlags = CONTEXT_ROBUST | CONTEXT_DEBUG;
    625 
    626 	static const ContextType wrappableNativeTypes[] =
    627 	{
    628 		ContextType(ApiType::core(4,4), config.type.getFlags() & validContextFlags),	// !< higher in the list, preferred
    629 		ContextType(ApiType::core(4,3), config.type.getFlags() & validContextFlags),
    630 	};
    631 
    632 	if (config.type.getAPI() != ApiType::es(3,2))
    633 		throw tcu::NotSupportedError("Unsupported context type (ES3.2 wrapper supports only ES3.2)");
    634 
    635 	// try to create any wrappable context
    636 
    637 	for (int nativeCtxNdx = 0; nativeCtxNdx < DE_LENGTH_OF_ARRAY(wrappableNativeTypes); ++nativeCtxNdx)
    638 	{
    639 		glu::ContextType nativeContext = wrappableNativeTypes[nativeCtxNdx];
    640 
    641 		try
    642 		{
    643 			glu::RenderConfig nativeConfig = config;
    644 			nativeConfig.type = nativeContext;
    645 
    646 			m_context		= factory.createContext(nativeConfig, cmdLine);
    647 			m_wrapperCtx	= new es3plus::Context(*m_context);
    648 
    649 			es3plus::setCurrentContext(m_wrapperCtx);
    650 			es3plus::initFunctions(&m_functions, m_context->getFunctions());
    651 			break;
    652 		}
    653 		catch (...)
    654 		{
    655 			es3plus::setCurrentContext(DE_NULL);
    656 
    657 			delete m_wrapperCtx;
    658 			delete m_context;
    659 
    660 			m_wrapperCtx = DE_NULL;
    661 			m_context = DE_NULL;
    662 
    663 			// throw only if all tries failed (that is, this was the last potential target)
    664 			if (nativeCtxNdx + 1 == DE_LENGTH_OF_ARRAY(wrappableNativeTypes))
    665 				throw;
    666 			else
    667 				continue;
    668 		}
    669 	}
    670 }
    671 
    672 ES3PlusWrapperContext::~ES3PlusWrapperContext (void)
    673 {
    674 	delete m_wrapperCtx;
    675 	delete m_context;
    676 }
    677 
    678 ContextType ES3PlusWrapperContext::getType (void) const
    679 {
    680 	return ContextType(ApiType::es(3,2), m_context->getType().getFlags());
    681 }
    682 
    683 } // glu
    684