1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program OpenGL ES Utilities
3 * ------------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief OpenGL ES 3plus wrapper context.
22 *//*--------------------------------------------------------------------*/
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"
56 Context (const glu::RenderContext& ctx);
59 void addExtension (const char* name);
61 const glw::Functions& gl; //!< GL 4.3 core context functions.
67 string shadingLanguageVersion;
69 vector<string> extensionList;
70 bool primitiveRestartEnabled;
75 const glu::GLSLVersion nativeGLSLVersion;
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)
86 , defaultVAOBound (false)
87 , nativeGLSLVersion (glu::getContextTypeGLSLVersion(ctx.getType()))
89 const de::UniquePtr<glu::ContextInfo> ctxInfo(glu::ContextInfo::create(ctx));
91 gl.genVertexArrays(1, &defaultVAO);
92 if (gl.getError() != GL_NO_ERROR || defaultVAO == 0)
93 throw tcu::InternalError("Failed to allocate VAO for emulation");
95 gl.bindVertexArray(defaultVAO);
96 if (gl.getError() != GL_NO_ERROR)
97 throw tcu::InternalError("Failed to bind default VAO");
98 defaultVAOBound = true;
100 gl.enable(GL_PROGRAM_POINT_SIZE);
101 gl.getError(); // supress potential errors, feature is not critical
103 gl.enable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
104 gl.getError(); // suppress
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");
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"))
118 addExtension("GL_KHR_blend_equation_advanced");
120 if (ctxInfo->isExtensionSupported("GL_NV_blend_equation_advanced_coherent") ||
121 ctxInfo->isExtensionSupported("GL_KHR_blend_equation_advanced_coherent"))
123 addExtension("GL_KHR_blend_equation_advanced_coherent");
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");
142 Context::~Context (void)
145 gl.deleteVertexArrays(1, &defaultVAO);
148 void Context::addExtension (const char* name)
150 if (!extensions.empty())
154 extensionList.push_back(name);
157 static de::ThreadLocal tls_context;
159 void setCurrentContext (Context* context)
161 tls_context.set(context);
164 inline Context* getCurrentContext (void)
166 return (Context*)tls_context.get();
169 static GLW_APICALL void GLW_APIENTRY getIntegerv (deUint32 pname, deInt32* params)
171 Context* context = getCurrentContext();
175 if (pname == GL_NUM_EXTENSIONS && params)
176 *params = (deInt32)context->extensionList.size();
178 context->gl.getIntegerv(pname, params);
182 static GLW_APICALL const glw::GLubyte* GLW_APIENTRY getString (deUint32 name)
184 Context* context = getCurrentContext();
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);
202 static GLW_APICALL const glw::GLubyte* GLW_APIENTRY getStringi (deUint32 name, deUint32 index)
204 Context* context = getCurrentContext();
208 if (name == GL_EXTENSIONS)
210 if ((size_t)index < context->extensionList.size())
211 return (const glw::GLubyte*)context->extensionList[index].c_str();
213 return context->gl.getStringi(name, ~0u);
216 return context->gl.getStringi(name, index);
222 static GLW_APICALL void GLW_APIENTRY enable (deUint32 cap)
224 Context* context = getCurrentContext();
228 if (cap == GL_PRIMITIVE_RESTART_FIXED_INDEX)
230 context->primitiveRestartEnabled = true;
231 // \todo [2013-09-30 pyry] Call to glPrimitiveRestartIndex() is required prior to all draw calls!
234 context->gl.enable(cap);
238 static GLW_APICALL void GLW_APIENTRY disable (deUint32 cap)
240 Context* context = getCurrentContext();
244 if (cap == GL_PRIMITIVE_RESTART_FIXED_INDEX)
245 context->primitiveRestartEnabled = false;
247 context->gl.disable(cap);
251 static GLW_APICALL void GLW_APIENTRY bindVertexArray (deUint32 array)
253 Context* context = getCurrentContext();
257 context->gl.bindVertexArray(array == 0 ? context->defaultVAO : array);
258 context->defaultVAOBound = (array == 0);
262 static GLW_APICALL void GLW_APIENTRY hint (deUint32 target, deUint32 mode)
264 Context* context = getCurrentContext();
268 if (target != GL_GENERATE_MIPMAP_HINT)
269 context->gl.hint(target, mode);
270 // \todo [2013-09-30 pyry] Verify mode.
274 static void translateShaderSource (deUint32 shaderType, std::ostream& dst, const std::string& src, const std::vector<std::string>& filteredExtensions, GLSLVersion version)
276 bool foundVersion = false;
277 std::istringstream istr (src);
280 bool preprocessorSection = true;
282 while (std::getline(istr, line, '\n'))
284 if (preprocessorSection && !line.empty() && line[0] != '#')
286 preprocessorSection = false;
288 // ARB_separate_shader_objects requires gl_PerVertex to be explicitly declared
289 if (shaderType == GL_VERTEX_SHADER)
291 dst << "out gl_PerVertex {\n"
292 << " vec4 gl_Position;\n"
293 << " float gl_PointSize;\n"
294 << " float gl_ClipDistance[];\n"
296 << "#line " << (srcLineNdx + 1) << "\n";
298 else if (shaderType == GL_TESS_CONTROL_SHADER)
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"
309 << "#line " << (srcLineNdx + 1) << "\n";
311 else if (shaderType == GL_TESS_EVALUATION_SHADER)
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"
322 << "#line " << (srcLineNdx + 1) << "\n";
324 else if (shaderType == GL_GEOMETRY_SHADER)
326 dst << "in gl_PerVertex {\n"
327 << " highp vec4 gl_Position;\n"
328 << " highp float gl_PointSize;\n"
330 << "out gl_PerVertex {\n"
331 << " highp vec4 gl_Position;\n"
332 << " highp float gl_PointSize;\n"
334 << "#line " << (srcLineNdx + 1) << "\n";
337 // GL_EXT_primitive_bounding_box tessellation no-op fallback
338 if (shaderType == GL_TESS_CONTROL_SHADER)
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";
346 if (line == "#version 310 es" || line == "#version 320 es")
349 dst << glu::getGLSLVersionDeclaration(version) << "\n";
351 else if (line == "#version 300 es")
354 dst << "#version 330\n";
356 else if (line.substr(0, 10) == "precision ")
358 const size_t precPos = 10;
359 const size_t precEndPos = line.find(' ', precPos);
360 const size_t endPos = line.find(';');
362 if (precEndPos != std::string::npos && endPos != std::string::npos && endPos > precEndPos+1)
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";
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
380 else if (line.substr(0, 11) == "#extension ")
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);
386 if (extNameEndPos != std::string::npos && behaviorPos != std::string::npos)
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";
393 if (filteredExtension && validBehavior)
394 dst << "// "; // Filter out extension
398 else if (line.substr(0, 21) == "layout(blend_support_")
399 dst << "// " << line << "\n";
406 DE_ASSERT(foundVersion);
407 DE_UNREF(foundVersion);
410 static std::string translateShaderSources (deUint32 shaderType, deInt32 count, const char* const* strings, const int* length, const std::vector<std::string>& filteredExtensions, GLSLVersion version)
412 std::ostringstream srcIn;
413 std::ostringstream srcOut;
415 for (int ndx = 0; ndx < count; ndx++)
417 const int len = length && length[ndx] >= 0 ? length[ndx] : (int)strlen(strings[ndx]);
418 srcIn << std::string(strings[ndx], strings[ndx] + len);
421 translateShaderSource(shaderType, srcOut, srcIn.str(), filteredExtensions, version);
426 static GLW_APICALL void GLW_APIENTRY shaderSource (deUint32 shader, deInt32 count, const char* const* strings, const int* length)
428 Context* context = getCurrentContext();
432 if (count > 0 && strings)
434 deInt32 shaderType = GL_NONE;
435 context->gl.getShaderiv(shader, GL_SHADER_TYPE, &shaderType);
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);
443 context->gl.shaderSource(shader, count, strings, length);
447 static GLW_APICALL void GLW_APIENTRY bindFramebuffer (deUint32 target, deUint32 framebuffer)
449 Context* context = getCurrentContext();
453 context->gl.bindFramebuffer(target, framebuffer);
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);
461 static GLW_APICALL void GLW_APIENTRY blendBarrierKHR (void)
463 Context* context = getCurrentContext();
467 // \todo [2014-03-18 pyry] Use BlendBarrierNV() if supported
468 context->gl.finish();
472 static GLW_APICALL deUint32 GLW_APIENTRY createShaderProgramv (deUint32 type, deInt32 count, const char* const* strings)
474 Context* context = getCurrentContext();
478 if (count > 0 && strings)
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);
485 return context->gl.createShaderProgramv(type, count, strings);
490 static GLW_APICALL void GLW_APIENTRY dummyPrimitiveBoundingBox (float minX, float minY, float minZ, float minW, float maxX, float maxY, float maxZ, float maxW)
492 // dummy no-op. No-op is a valid implementation. States queries are not emulated.
503 static void initFunctions (glw::Functions* dst, const glw::Functions& src)
505 // Functions directly passed to GL context.
506 #include "gluES3PlusWrapperFuncs.inl"
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;
516 dst->shaderSource = shaderSource;
517 dst->createShaderProgramv = createShaderProgramv;
518 dst->bindFramebuffer = bindFramebuffer;
520 // Extension functions
524 class ExtFuncLoader : public glw::FunctionLoader
527 ExtFuncLoader (const map<string, glw::GenericFuncType>& extFuncs)
528 : m_extFuncs(extFuncs)
532 glw::GenericFuncType get (const char* name) const
534 map<string, glw::GenericFuncType>::const_iterator pos = m_extFuncs.find(name);
535 return pos != m_extFuncs.end() ? pos->second : DE_NULL;
539 const map<string, glw::GenericFuncType>& m_extFuncs;
542 map<string, glw::GenericFuncType> extFuncMap;
543 const ExtFuncLoader extFuncLoader (extFuncMap);
545 // OES_sample_shading
546 extFuncMap["glMinSampleShadingOES"] = (glw::GenericFuncType)src.minSampleShading;
548 // OES_texture_storage_multisample_2d_array
549 extFuncMap["glTexStorage3DMultisampleOES"] = (glw::GenericFuncType)src.texStorage3DMultisample;
551 // KHR_blend_equation_advanced
552 extFuncMap["glBlendBarrierKHR"] = (glw::GenericFuncType)blendBarrierKHR;
554 // EXT_tessellation_shader
555 extFuncMap["glPatchParameteriEXT"] = (glw::GenericFuncType)src.patchParameteri;
557 // EXT_geometry_shader
558 extFuncMap["glFramebufferTextureEXT"] = (glw::GenericFuncType)src.framebufferTexture;
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;
573 // GL_EXT_primitive_bounding_box (dummy no-op)
574 extFuncMap["glPrimitiveBoundingBoxEXT"] = (glw::GenericFuncType)dummyPrimitiveBoundingBox;
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;
586 // GL_EXT_texture_buffer
587 extFuncMap["glTexBufferEXT"] = (glw::GenericFuncType)src.texBuffer;
588 extFuncMap["glTexBufferRangeEXT"] = (glw::GenericFuncType)src.texBufferRange;
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;
602 dst->getIntegerv(GL_NUM_EXTENSIONS, &numExts);
606 vector<const char*> extStr(numExts);
608 for (int ndx = 0; ndx < numExts; ndx++)
609 extStr[ndx] = (const char*)dst->getStringi(GL_EXTENSIONS, ndx);
611 glw::initExtensionsES(dst, &extFuncLoader, (int)extStr.size(), &extStr[0]);
619 ES3PlusWrapperContext::ES3PlusWrapperContext (const ContextFactory& factory, const RenderConfig& config, const tcu::CommandLine& cmdLine)
620 : m_context (DE_NULL)
621 , m_wrapperCtx (DE_NULL)
623 // Flags that are valid for both core & es context. Currently only excludes CONTEXT_FORWARD_COMPATIBLE
624 const ContextFlags validContextFlags = CONTEXT_ROBUST | CONTEXT_DEBUG;
626 static const ContextType wrappableNativeTypes[] =
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),
632 if (config.type.getAPI() != ApiType::es(3,2))
633 throw tcu::NotSupportedError("Unsupported context type (ES3.2 wrapper supports only ES3.2)");
635 // try to create any wrappable context
637 for (int nativeCtxNdx = 0; nativeCtxNdx < DE_LENGTH_OF_ARRAY(wrappableNativeTypes); ++nativeCtxNdx)
639 glu::ContextType nativeContext = wrappableNativeTypes[nativeCtxNdx];
643 glu::RenderConfig nativeConfig = config;
644 nativeConfig.type = nativeContext;
646 m_context = factory.createContext(nativeConfig, cmdLine);
647 m_wrapperCtx = new es3plus::Context(*m_context);
649 es3plus::setCurrentContext(m_wrapperCtx);
650 es3plus::initFunctions(&m_functions, m_context->getFunctions());
655 es3plus::setCurrentContext(DE_NULL);
660 m_wrapperCtx = DE_NULL;
663 // throw only if all tries failed (that is, this was the last potential target)
664 if (nativeCtxNdx + 1 == DE_LENGTH_OF_ARRAY(wrappableNativeTypes))
672 ES3PlusWrapperContext::~ES3PlusWrapperContext (void)
678 ContextType ES3PlusWrapperContext::getType (void) const
680 return ContextType(ApiType::es(3,2), m_context->getType().getFlags());