• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // Shader.cpp: Implements the gl::Shader class and its  derived classes
8 // VertexShader and FragmentShader. Implements GL shader objects and related
9 // functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84.
10 
11 #include "libANGLE/Shader.h"
12 
13 #include <functional>
14 #include <sstream>
15 
16 #include "GLSLANG/ShaderLang.h"
17 #include "common/utilities.h"
18 #include "libANGLE/Caps.h"
19 #include "libANGLE/Compiler.h"
20 #include "libANGLE/Constants.h"
21 #include "libANGLE/Context.h"
22 #include "libANGLE/ResourceManager.h"
23 #include "libANGLE/renderer/GLImplFactory.h"
24 #include "libANGLE/renderer/ShaderImpl.h"
25 #include "platform/FrontendFeatures.h"
26 
27 namespace gl
28 {
29 
30 namespace
31 {
32 template <typename VarT>
GetActiveShaderVariables(const std::vector<VarT> * variableList)33 std::vector<VarT> GetActiveShaderVariables(const std::vector<VarT> *variableList)
34 {
35     ASSERT(variableList);
36     std::vector<VarT> result;
37     for (size_t varIndex = 0; varIndex < variableList->size(); varIndex++)
38     {
39         const VarT &var = variableList->at(varIndex);
40         if (var.active)
41         {
42             result.push_back(var);
43         }
44     }
45     return result;
46 }
47 
48 template <typename VarT>
GetShaderVariables(const std::vector<VarT> * variableList)49 const std::vector<VarT> &GetShaderVariables(const std::vector<VarT> *variableList)
50 {
51     ASSERT(variableList);
52     return *variableList;
53 }
54 
55 }  // anonymous namespace
56 
57 // true if varying x has a higher priority in packing than y
CompareShaderVar(const sh::ShaderVariable & x,const sh::ShaderVariable & y)58 bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y)
59 {
60     if (x.type == y.type)
61     {
62         return x.getArraySizeProduct() > y.getArraySizeProduct();
63     }
64 
65     // Special case for handling structs: we sort these to the end of the list
66     if (x.type == GL_NONE)
67     {
68         return false;
69     }
70 
71     if (y.type == GL_NONE)
72     {
73         return true;
74     }
75 
76     return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
77 }
78 
GetShaderTypeString(ShaderType type)79 const char *GetShaderTypeString(ShaderType type)
80 {
81     switch (type)
82     {
83         case ShaderType::Vertex:
84             return "VERTEX";
85 
86         case ShaderType::Fragment:
87             return "FRAGMENT";
88 
89         case ShaderType::Compute:
90             return "COMPUTE";
91 
92         case ShaderType::Geometry:
93             return "GEOMETRY";
94 
95         default:
96             UNREACHABLE();
97             return "";
98     }
99 }
100 
101 class ScopedExit final : angle::NonCopyable
102 {
103   public:
ScopedExit(std::function<void ()> exit)104     ScopedExit(std::function<void()> exit) : mExit(exit) {}
~ScopedExit()105     ~ScopedExit() { mExit(); }
106 
107   private:
108     std::function<void()> mExit;
109 };
110 
111 struct Shader::CompilingState
112 {
113     std::shared_ptr<rx::WaitableCompileEvent> compileEvent;
114     ShCompilerInstance shCompilerInstance;
115 };
116 
ShaderState(ShaderType shaderType)117 ShaderState::ShaderState(ShaderType shaderType)
118     : mLabel(),
119       mShaderType(shaderType),
120       mShaderVersion(100),
121       mNumViews(-1),
122       mGeometryShaderInvocations(1),
123       mCompileStatus(CompileStatus::NOT_COMPILED)
124 {
125     mLocalSize.fill(-1);
126 }
127 
~ShaderState()128 ShaderState::~ShaderState() {}
129 
Shader(ShaderProgramManager * manager,rx::GLImplFactory * implFactory,const gl::Limitations & rendererLimitations,ShaderType type,ShaderProgramID handle)130 Shader::Shader(ShaderProgramManager *manager,
131                rx::GLImplFactory *implFactory,
132                const gl::Limitations &rendererLimitations,
133                ShaderType type,
134                ShaderProgramID handle)
135     : mState(type),
136       mImplementation(implFactory->createShader(mState)),
137       mRendererLimitations(rendererLimitations),
138       mHandle(handle),
139       mType(type),
140       mRefCount(0),
141       mDeleteStatus(false),
142       mResourceManager(manager),
143       mCurrentMaxComputeWorkGroupInvocations(0u)
144 {
145     ASSERT(mImplementation);
146 }
147 
onDestroy(const gl::Context * context)148 void Shader::onDestroy(const gl::Context *context)
149 {
150     resolveCompile();
151     mImplementation->destroy();
152     mBoundCompiler.set(context, nullptr);
153     mImplementation.reset(nullptr);
154     delete this;
155 }
156 
~Shader()157 Shader::~Shader()
158 {
159     ASSERT(!mImplementation);
160 }
161 
setLabel(const Context * context,const std::string & label)162 void Shader::setLabel(const Context *context, const std::string &label)
163 {
164     mState.mLabel = label;
165 }
166 
getLabel() const167 const std::string &Shader::getLabel() const
168 {
169     return mState.mLabel;
170 }
171 
getHandle() const172 ShaderProgramID Shader::getHandle() const
173 {
174     return mHandle;
175 }
176 
setSource(GLsizei count,const char * const * string,const GLint * length)177 void Shader::setSource(GLsizei count, const char *const *string, const GLint *length)
178 {
179     std::ostringstream stream;
180 
181     for (int i = 0; i < count; i++)
182     {
183         if (length == nullptr || length[i] < 0)
184         {
185             stream.write(string[i], strlen(string[i]));
186         }
187         else
188         {
189             stream.write(string[i], length[i]);
190         }
191     }
192 
193     mState.mSource = stream.str();
194 }
195 
getInfoLogLength()196 int Shader::getInfoLogLength()
197 {
198     resolveCompile();
199     if (mInfoLog.empty())
200     {
201         return 0;
202     }
203 
204     return (static_cast<int>(mInfoLog.length()) + 1);
205 }
206 
getInfoLog(GLsizei bufSize,GLsizei * length,char * infoLog)207 void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
208 {
209     resolveCompile();
210 
211     int index = 0;
212 
213     if (bufSize > 0)
214     {
215         index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length()));
216         memcpy(infoLog, mInfoLog.c_str(), index);
217 
218         infoLog[index] = '\0';
219     }
220 
221     if (length)
222     {
223         *length = index;
224     }
225 }
226 
getSourceLength() const227 int Shader::getSourceLength() const
228 {
229     return mState.mSource.empty() ? 0 : (static_cast<int>(mState.mSource.length()) + 1);
230 }
231 
getTranslatedSourceLength()232 int Shader::getTranslatedSourceLength()
233 {
234     resolveCompile();
235 
236     if (mState.mTranslatedSource.empty())
237     {
238         return 0;
239     }
240 
241     return (static_cast<int>(mState.mTranslatedSource.length()) + 1);
242 }
243 
getTranslatedSourceWithDebugInfoLength()244 int Shader::getTranslatedSourceWithDebugInfoLength()
245 {
246     resolveCompile();
247 
248     const std::string &debugInfo = mImplementation->getDebugInfo();
249     if (debugInfo.empty())
250     {
251         return 0;
252     }
253 
254     return (static_cast<int>(debugInfo.length()) + 1);
255 }
256 
257 // static
GetSourceImpl(const std::string & source,GLsizei bufSize,GLsizei * length,char * buffer)258 void Shader::GetSourceImpl(const std::string &source,
259                            GLsizei bufSize,
260                            GLsizei *length,
261                            char *buffer)
262 {
263     int index = 0;
264 
265     if (bufSize > 0)
266     {
267         index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
268         memcpy(buffer, source.c_str(), index);
269 
270         buffer[index] = '\0';
271     }
272 
273     if (length)
274     {
275         *length = index;
276     }
277 }
278 
getSource(GLsizei bufSize,GLsizei * length,char * buffer) const279 void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
280 {
281     GetSourceImpl(mState.mSource, bufSize, length, buffer);
282 }
283 
getTranslatedSource(GLsizei bufSize,GLsizei * length,char * buffer)284 void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer)
285 {
286     GetSourceImpl(getTranslatedSource(), bufSize, length, buffer);
287 }
288 
getTranslatedSource()289 const std::string &Shader::getTranslatedSource()
290 {
291     resolveCompile();
292     return mState.mTranslatedSource;
293 }
294 
getTranslatedSourceWithDebugInfo(GLsizei bufSize,GLsizei * length,char * buffer)295 void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer)
296 {
297     resolveCompile();
298     const std::string &debugInfo = mImplementation->getDebugInfo();
299     GetSourceImpl(debugInfo, bufSize, length, buffer);
300 }
301 
compile(const Context * context)302 void Shader::compile(const Context *context)
303 {
304     resolveCompile();
305 
306     mState.mTranslatedSource.clear();
307     mInfoLog.clear();
308     mState.mShaderVersion = 100;
309     mState.mInputVaryings.clear();
310     mState.mOutputVaryings.clear();
311     mState.mUniforms.clear();
312     mState.mUniformBlocks.clear();
313     mState.mShaderStorageBlocks.clear();
314     mState.mActiveAttributes.clear();
315     mState.mActiveOutputVariables.clear();
316     mState.mNumViews = -1;
317     mState.mGeometryShaderInputPrimitiveType.reset();
318     mState.mGeometryShaderOutputPrimitiveType.reset();
319     mState.mGeometryShaderMaxVertices.reset();
320     mState.mGeometryShaderInvocations      = 1;
321     mState.mEarlyFragmentTestsOptimization = false;
322 
323     mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED;
324     mBoundCompiler.set(context, context->getCompiler());
325 
326     ShCompileOptions options = (SH_OBJECT_CODE | SH_VARIABLES | SH_EMULATE_GL_DRAW_ID |
327                                 SH_EMULATE_GL_BASE_VERTEX_BASE_INSTANCE);
328 
329     // Add default options to WebGL shaders to prevent unexpected behavior during
330     // compilation.
331     if (context->getExtensions().webglCompatibility)
332     {
333         options |= SH_INIT_GL_POSITION;
334         options |= SH_LIMIT_CALL_STACK_DEPTH;
335         options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
336         options |= SH_ENFORCE_PACKING_RESTRICTIONS;
337         options |= SH_INIT_SHARED_VARIABLES;
338     }
339 
340     // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop
341     // indexes in fragment shaders. Shader compilation will fail. To provide a better error
342     // message we can instruct the compiler to pre-validate.
343     if (mRendererLimitations.shadersRequireIndexedLoopValidation)
344     {
345         options |= SH_VALIDATE_LOOP_INDEXING;
346     }
347 
348     if (context->getFrontendFeatures().scalarizeVecAndMatConstructorArgs.enabled)
349     {
350         options |= SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS;
351     }
352 
353     mCurrentMaxComputeWorkGroupInvocations =
354         static_cast<GLuint>(context->getCaps().maxComputeWorkGroupInvocations);
355 
356     mMaxComputeSharedMemory = context->getCaps().maxComputeSharedMemorySize;
357 
358     ASSERT(mBoundCompiler.get());
359     ShCompilerInstance compilerInstance = mBoundCompiler->getInstance(mState.mShaderType);
360     ShHandle compilerHandle             = compilerInstance.getHandle();
361     ASSERT(compilerHandle);
362     mCompilerResourcesString = compilerInstance.getBuiltinResourcesString();
363 
364     mCompilingState.reset(new CompilingState());
365     mCompilingState->shCompilerInstance = std::move(compilerInstance);
366     mCompilingState->compileEvent =
367         mImplementation->compile(context, &(mCompilingState->shCompilerInstance), options);
368 }
369 
resolveCompile()370 void Shader::resolveCompile()
371 {
372     if (!mState.compilePending())
373     {
374         return;
375     }
376 
377     ASSERT(mCompilingState.get());
378 
379     mCompilingState->compileEvent->wait();
380 
381     mInfoLog += mCompilingState->compileEvent->getInfoLog();
382 
383     ScopedExit exit([this]() {
384         mBoundCompiler->putInstance(std::move(mCompilingState->shCompilerInstance));
385         mCompilingState->compileEvent.reset();
386         mCompilingState.reset();
387     });
388 
389     ShHandle compilerHandle = mCompilingState->shCompilerInstance.getHandle();
390     if (!mCompilingState->compileEvent->getResult())
391     {
392         mInfoLog += sh::GetInfoLog(compilerHandle);
393         WARN() << std::endl << mInfoLog;
394         mState.mCompileStatus = CompileStatus::NOT_COMPILED;
395         return;
396     }
397 
398     mState.mTranslatedSource = sh::GetObjectCode(compilerHandle);
399 
400 #if !defined(NDEBUG)
401     // Prefix translated shader with commented out un-translated shader.
402     // Useful in diagnostics tools which capture the shader source.
403     std::ostringstream shaderStream;
404     shaderStream << "// GLSL\n";
405     shaderStream << "//\n";
406 
407     std::istringstream inputSourceStream(mState.mSource);
408     std::string line;
409     while (std::getline(inputSourceStream, line))
410     {
411         // Remove null characters from the source line
412         line.erase(std::remove(line.begin(), line.end(), '\0'), line.end());
413 
414         shaderStream << "// " << line;
415 
416         // glslang complains if a comment ends with backslash
417         if (!line.empty() && line.back() == '\\')
418         {
419             shaderStream << "\\";
420         }
421 
422         shaderStream << std::endl;
423     }
424     shaderStream << "\n\n";
425     shaderStream << mState.mTranslatedSource;
426     mState.mTranslatedSource = shaderStream.str();
427 #endif  // !defined(NDEBUG)
428 
429     // Gather the shader information
430     mState.mShaderVersion = sh::GetShaderVersion(compilerHandle);
431 
432     mState.mUniforms            = GetShaderVariables(sh::GetUniforms(compilerHandle));
433     mState.mUniformBlocks       = GetShaderVariables(sh::GetUniformBlocks(compilerHandle));
434     mState.mShaderStorageBlocks = GetShaderVariables(sh::GetShaderStorageBlocks(compilerHandle));
435 
436     switch (mState.mShaderType)
437     {
438         case ShaderType::Compute:
439         {
440             mState.mAllAttributes    = GetShaderVariables(sh::GetAttributes(compilerHandle));
441             mState.mActiveAttributes = GetActiveShaderVariables(&mState.mAllAttributes);
442             mState.mLocalSize        = sh::GetComputeShaderLocalGroupSize(compilerHandle);
443             if (mState.mLocalSize.isDeclared())
444             {
445                 angle::CheckedNumeric<uint32_t> checked_local_size_product(mState.mLocalSize[0]);
446                 checked_local_size_product *= mState.mLocalSize[1];
447                 checked_local_size_product *= mState.mLocalSize[2];
448 
449                 if (!checked_local_size_product.IsValid())
450                 {
451                     WARN() << std::endl
452                            << "Integer overflow when computing the product of local_size_x, "
453                            << "local_size_y and local_size_z.";
454                     mState.mCompileStatus = CompileStatus::NOT_COMPILED;
455                     return;
456                 }
457                 if (checked_local_size_product.ValueOrDie() >
458                     mCurrentMaxComputeWorkGroupInvocations)
459                 {
460                     WARN() << std::endl
461                            << "The total number of invocations within a work group exceeds "
462                            << "MAX_COMPUTE_WORK_GROUP_INVOCATIONS.";
463                     mState.mCompileStatus = CompileStatus::NOT_COMPILED;
464                     return;
465                 }
466             }
467 
468             unsigned int sharedMemSize = sh::GetShaderSharedMemorySize(compilerHandle);
469             if (sharedMemSize > mMaxComputeSharedMemory)
470             {
471                 WARN() << std::endl << "Exceeded maximum shared memory size";
472                 mState.mCompileStatus = CompileStatus::NOT_COMPILED;
473                 return;
474             }
475             break;
476         }
477         case ShaderType::Vertex:
478         {
479             mState.mOutputVaryings   = GetShaderVariables(sh::GetOutputVaryings(compilerHandle));
480             mState.mAllAttributes    = GetShaderVariables(sh::GetAttributes(compilerHandle));
481             mState.mActiveAttributes = GetActiveShaderVariables(&mState.mAllAttributes);
482             mState.mNumViews         = sh::GetVertexShaderNumViews(compilerHandle);
483             break;
484         }
485         case ShaderType::Fragment:
486         {
487             mState.mAllAttributes    = GetShaderVariables(sh::GetAttributes(compilerHandle));
488             mState.mActiveAttributes = GetActiveShaderVariables(&mState.mAllAttributes);
489             mState.mInputVaryings    = GetShaderVariables(sh::GetInputVaryings(compilerHandle));
490             // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
491             std::sort(mState.mInputVaryings.begin(), mState.mInputVaryings.end(), CompareShaderVar);
492             mState.mActiveOutputVariables =
493                 GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle));
494             mState.mEarlyFragmentTestsOptimization =
495                 sh::HasEarlyFragmentTestsOptimization(compilerHandle);
496             break;
497         }
498         case ShaderType::Geometry:
499         {
500             mState.mInputVaryings  = GetShaderVariables(sh::GetInputVaryings(compilerHandle));
501             mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle));
502 
503             if (sh::HasValidGeometryShaderInputPrimitiveType(compilerHandle))
504             {
505                 mState.mGeometryShaderInputPrimitiveType = FromGLenum<PrimitiveMode>(
506                     sh::GetGeometryShaderInputPrimitiveType(compilerHandle));
507             }
508             if (sh::HasValidGeometryShaderOutputPrimitiveType(compilerHandle))
509             {
510                 mState.mGeometryShaderOutputPrimitiveType = FromGLenum<PrimitiveMode>(
511                     sh::GetGeometryShaderOutputPrimitiveType(compilerHandle));
512             }
513             if (sh::HasValidGeometryShaderMaxVertices(compilerHandle))
514             {
515                 mState.mGeometryShaderMaxVertices =
516                     sh::GetGeometryShaderMaxVertices(compilerHandle);
517             }
518             mState.mGeometryShaderInvocations = sh::GetGeometryShaderInvocations(compilerHandle);
519             break;
520         }
521         default:
522             UNREACHABLE();
523     }
524 
525     ASSERT(!mState.mTranslatedSource.empty());
526 
527     bool success          = mCompilingState->compileEvent->postTranslate(&mInfoLog);
528     mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED;
529 }
530 
addRef()531 void Shader::addRef()
532 {
533     mRefCount++;
534 }
535 
release(const Context * context)536 void Shader::release(const Context *context)
537 {
538     mRefCount--;
539 
540     if (mRefCount == 0 && mDeleteStatus)
541     {
542         mResourceManager->deleteShader(context, mHandle);
543     }
544 }
545 
getRefCount() const546 unsigned int Shader::getRefCount() const
547 {
548     return mRefCount;
549 }
550 
isFlaggedForDeletion() const551 bool Shader::isFlaggedForDeletion() const
552 {
553     return mDeleteStatus;
554 }
555 
flagForDeletion()556 void Shader::flagForDeletion()
557 {
558     mDeleteStatus = true;
559 }
560 
isCompiled()561 bool Shader::isCompiled()
562 {
563     resolveCompile();
564     return mState.mCompileStatus == CompileStatus::COMPILED;
565 }
566 
isCompleted()567 bool Shader::isCompleted()
568 {
569     return (!mState.compilePending() || mCompilingState->compileEvent->isReady());
570 }
571 
getShaderVersion()572 int Shader::getShaderVersion()
573 {
574     resolveCompile();
575     return mState.mShaderVersion;
576 }
577 
getInputVaryings()578 const std::vector<sh::ShaderVariable> &Shader::getInputVaryings()
579 {
580     resolveCompile();
581     return mState.getInputVaryings();
582 }
583 
getOutputVaryings()584 const std::vector<sh::ShaderVariable> &Shader::getOutputVaryings()
585 {
586     resolveCompile();
587     return mState.getOutputVaryings();
588 }
589 
getUniforms()590 const std::vector<sh::ShaderVariable> &Shader::getUniforms()
591 {
592     resolveCompile();
593     return mState.getUniforms();
594 }
595 
getUniformBlocks()596 const std::vector<sh::InterfaceBlock> &Shader::getUniformBlocks()
597 {
598     resolveCompile();
599     return mState.getUniformBlocks();
600 }
601 
getShaderStorageBlocks()602 const std::vector<sh::InterfaceBlock> &Shader::getShaderStorageBlocks()
603 {
604     resolveCompile();
605     return mState.getShaderStorageBlocks();
606 }
607 
getActiveAttributes()608 const std::vector<sh::ShaderVariable> &Shader::getActiveAttributes()
609 {
610     resolveCompile();
611     return mState.getActiveAttributes();
612 }
613 
getAllAttributes()614 const std::vector<sh::ShaderVariable> &Shader::getAllAttributes()
615 {
616     resolveCompile();
617     return mState.getAllAttributes();
618 }
619 
getActiveOutputVariables()620 const std::vector<sh::ShaderVariable> &Shader::getActiveOutputVariables()
621 {
622     resolveCompile();
623     return mState.getActiveOutputVariables();
624 }
625 
getTransformFeedbackVaryingMappedName(const std::string & tfVaryingName)626 std::string Shader::getTransformFeedbackVaryingMappedName(const std::string &tfVaryingName)
627 {
628     // TODO(jiawei.shao@intel.com): support transform feedback on geometry shader.
629     ASSERT(mState.getShaderType() == ShaderType::Vertex ||
630            mState.getShaderType() == ShaderType::Geometry);
631     const auto &varyings = getOutputVaryings();
632     auto bracketPos      = tfVaryingName.find("[");
633     if (bracketPos != std::string::npos)
634     {
635         auto tfVaryingBaseName = tfVaryingName.substr(0, bracketPos);
636         for (const auto &varying : varyings)
637         {
638             if (varying.name == tfVaryingBaseName)
639             {
640                 std::string mappedNameWithArrayIndex =
641                     varying.mappedName + tfVaryingName.substr(bracketPos);
642                 return mappedNameWithArrayIndex;
643             }
644         }
645     }
646     else
647     {
648         for (const auto &varying : varyings)
649         {
650             if (varying.name == tfVaryingName)
651             {
652                 return varying.mappedName;
653             }
654             else if (varying.isStruct())
655             {
656                 GLuint fieldIndex = 0;
657                 const auto *field = FindShaderVarField(varying, tfVaryingName, &fieldIndex);
658                 ASSERT(field != nullptr && !field->isStruct() && !field->isArray());
659                 return varying.mappedName + "." + field->mappedName;
660             }
661         }
662     }
663     UNREACHABLE();
664     return std::string();
665 }
666 
getWorkGroupSize()667 const sh::WorkGroupSize &Shader::getWorkGroupSize()
668 {
669     resolveCompile();
670     return mState.mLocalSize;
671 }
672 
getNumViews()673 int Shader::getNumViews()
674 {
675     resolveCompile();
676     return mState.mNumViews;
677 }
678 
getGeometryShaderInputPrimitiveType()679 Optional<PrimitiveMode> Shader::getGeometryShaderInputPrimitiveType()
680 {
681     resolveCompile();
682     return mState.mGeometryShaderInputPrimitiveType;
683 }
684 
getGeometryShaderOutputPrimitiveType()685 Optional<PrimitiveMode> Shader::getGeometryShaderOutputPrimitiveType()
686 {
687     resolveCompile();
688     return mState.mGeometryShaderOutputPrimitiveType;
689 }
690 
getGeometryShaderInvocations()691 int Shader::getGeometryShaderInvocations()
692 {
693     resolveCompile();
694     return mState.mGeometryShaderInvocations;
695 }
696 
getGeometryShaderMaxVertices()697 Optional<GLint> Shader::getGeometryShaderMaxVertices()
698 {
699     resolveCompile();
700     return mState.mGeometryShaderMaxVertices;
701 }
702 
getCompilerResourcesString() const703 const std::string &Shader::getCompilerResourcesString() const
704 {
705     return mCompilerResourcesString;
706 }
707 
708 }  // namespace gl
709