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 "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 
     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 
    119 Context::~Context (void)
    120 {
    121 	if (defaultVAO)
    122 		gl.deleteVertexArrays(1, &defaultVAO);
    123 }
    124 
    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 
    136 void setCurrentContext (Context* context)
    137 {
    138 	tls_context.set(context);
    139 }
    140 
    141 inline Context* getCurrentContext (void)
    142 {
    143 	return (Context*)tls_context.get();
    144 }
    145 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    556 ES3PlusWrapperContext::~ES3PlusWrapperContext (void)
    557 {
    558 	delete m_wrapperCtx;
    559 	delete m_context;
    560 }
    561 
    562 ContextType ES3PlusWrapperContext::getType (void) const
    563 {
    564 	return ContextType(ApiType::es(3,1), m_context->getType().getFlags());
    565 }
    566 
    567 } // glu
    568