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
44namespace glu
45{
46
47namespace es3plus
48{
49
50using std::vector;
51using std::string;
52
53class Context
54{
55public:
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
78Context::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
142Context::~Context (void)
143{
144	if (defaultVAO)
145		gl.deleteVertexArrays(1, &defaultVAO);
146}
147
148void Context::addExtension (const char* name)
149{
150	if (!extensions.empty())
151		extensions += " ";
152	extensions += name;
153
154	extensionList.push_back(name);
155}
156
157static de::ThreadLocal tls_context;
158
159void setCurrentContext (Context* context)
160{
161	tls_context.set(context);
162}
163
164inline Context* getCurrentContext (void)
165{
166	return (Context*)tls_context.get();
167}
168
169static 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
182static 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
202static 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
222static 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
238static 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
251static 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
262static 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
274static 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
410static 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
426static 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
447static 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
461static 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
472static 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
490static 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
503static 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
619ES3PlusWrapperContext::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
672ES3PlusWrapperContext::~ES3PlusWrapperContext (void)
673{
674	delete m_wrapperCtx;
675	delete m_context;
676}
677
678ContextType ES3PlusWrapperContext::getType (void) const
679{
680	return ContextType(ApiType::es(3,2), m_context->getType().getFlags());
681}
682
683} // glu
684