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 40namespace glu 41{ 42 43namespace es3plus 44{ 45 46using std::vector; 47using std::string; 48 49class Context 50{ 51public: 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 72Context::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 119Context::~Context (void) 120{ 121 if (defaultVAO) 122 gl.deleteVertexArrays(1, &defaultVAO); 123} 124 125void Context::addExtension (const char* name) 126{ 127 if (!extensions.empty()) 128 extensions += " "; 129 extensions += name; 130 131 extensionList.push_back(name); 132} 133 134static de::ThreadLocal tls_context; 135 136void setCurrentContext (Context* context) 137{ 138 tls_context.set(context); 139} 140 141inline Context* getCurrentContext (void) 142{ 143 return (Context*)tls_context.get(); 144} 145 146static 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 159static 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 179static 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 199static 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 215static 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 228static 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 239static 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 251static 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 334static 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 350static 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 371static 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 385static 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 396static 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 414static 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 503ES3PlusWrapperContext::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 556ES3PlusWrapperContext::~ES3PlusWrapperContext (void) 557{ 558 delete m_wrapperCtx; 559 delete m_context; 560} 561 562ContextType ES3PlusWrapperContext::getType (void) const 563{ 564 return ContextType(ApiType::es(3,1), m_context->getType().getFlags()); 565} 566 567} // glu 568