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