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