• 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/angle_version_info.h"
18 #include "common/string_utils.h"
19 #include "common/system_utils.h"
20 #include "common/utilities.h"
21 #include "libANGLE/Caps.h"
22 #include "libANGLE/Compiler.h"
23 #include "libANGLE/Constants.h"
24 #include "libANGLE/Context.h"
25 #include "libANGLE/Display.h"
26 #include "libANGLE/MemoryShaderCache.h"
27 #include "libANGLE/Program.h"
28 #include "libANGLE/ResourceManager.h"
29 #include "libANGLE/renderer/GLImplFactory.h"
30 #include "libANGLE/renderer/ShaderImpl.h"
31 #include "platform/autogen/FrontendFeatures_autogen.h"
32 
33 namespace gl
34 {
35 
36 namespace
37 {
38 constexpr uint32_t kShaderCacheIdentifier = 0x12345678;
39 
40 // Environment variable (and associated Android property) for the path to read and write shader
41 // dumps
42 constexpr char kShaderDumpPathVarName[]       = "ANGLE_SHADER_DUMP_PATH";
43 constexpr char kEShaderDumpPathPropertyName[] = "debug.angle.shader_dump_path";
44 
ComputeShaderHash(const std::string & mergedSource)45 size_t ComputeShaderHash(const std::string &mergedSource)
46 {
47     return std::hash<std::string>{}(mergedSource);
48 }
49 
GetShaderDumpFilePath(size_t shaderHash,const char * suffix)50 std::string GetShaderDumpFilePath(size_t shaderHash, const char *suffix)
51 {
52     std::stringstream path;
53     std::string shaderDumpDir = GetShaderDumpFileDirectory();
54     if (!shaderDumpDir.empty())
55     {
56         path << shaderDumpDir << "/";
57     }
58     path << shaderHash << "." << suffix;
59 
60     return path.str();
61 }
62 }  // anonymous namespace
63 
GetShaderTypeString(ShaderType type)64 const char *GetShaderTypeString(ShaderType type)
65 {
66     switch (type)
67     {
68         case ShaderType::Vertex:
69             return "VERTEX";
70 
71         case ShaderType::Fragment:
72             return "FRAGMENT";
73 
74         case ShaderType::Compute:
75             return "COMPUTE";
76 
77         case ShaderType::Geometry:
78             return "GEOMETRY";
79 
80         case ShaderType::TessControl:
81             return "TESS_CONTROL";
82 
83         case ShaderType::TessEvaluation:
84             return "TESS_EVALUATION";
85 
86         default:
87             UNREACHABLE();
88             return "";
89     }
90 }
91 
GetShaderDumpFileDirectory()92 std::string GetShaderDumpFileDirectory()
93 {
94     // Check the environment variable for the path to save and read shader dump files.
95     std::string environmentVariableDumpDir =
96         angle::GetAndSetEnvironmentVarOrUnCachedAndroidProperty(kShaderDumpPathVarName,
97                                                                 kEShaderDumpPathPropertyName);
98     if (!environmentVariableDumpDir.empty() && environmentVariableDumpDir.compare("0") != 0)
99     {
100         return environmentVariableDumpDir;
101     }
102 
103     // Fall back to the temp dir. If that doesn't exist, use the current working directory.
104     return angle::GetTempDirectory().valueOr("");
105 }
106 
GetShaderDumpFileName(size_t shaderHash)107 std::string GetShaderDumpFileName(size_t shaderHash)
108 {
109     std::stringstream name;
110     name << shaderHash << ".essl";
111     return name.str();
112 }
113 
114 class [[nodiscard]] ScopedExit final : angle::NonCopyable
115 {
116   public:
ScopedExit(std::function<void ()> exit)117     ScopedExit(std::function<void()> exit) : mExit(exit) {}
~ScopedExit()118     ~ScopedExit() { mExit(); }
119 
120   private:
121     std::function<void()> mExit;
122 };
123 
124 struct Shader::CompilingState
125 {
126     std::shared_ptr<rx::WaitableCompileEvent> compileEvent;
127     ShCompilerInstance shCompilerInstance;
128 };
129 
ShaderState(ShaderType shaderType)130 ShaderState::ShaderState(ShaderType shaderType) : mCompiledShaderState(shaderType) {}
131 
~ShaderState()132 ShaderState::~ShaderState() {}
133 
Shader(ShaderProgramManager * manager,rx::GLImplFactory * implFactory,const gl::Limitations & rendererLimitations,ShaderType type,ShaderProgramID handle)134 Shader::Shader(ShaderProgramManager *manager,
135                rx::GLImplFactory *implFactory,
136                const gl::Limitations &rendererLimitations,
137                ShaderType type,
138                ShaderProgramID handle)
139     : mState(type),
140       mImplementation(implFactory->createShader(mState)),
141       mRendererLimitations(rendererLimitations),
142       mHandle(handle),
143       mType(type),
144       mRefCount(0),
145       mDeleteStatus(false),
146       mResourceManager(manager),
147       mCurrentMaxComputeWorkGroupInvocations(0u),
148       mMaxComputeSharedMemory(0u)
149 {
150     ASSERT(mImplementation);
151 }
152 
onDestroy(const gl::Context * context)153 void Shader::onDestroy(const gl::Context *context)
154 {
155     resolveCompile(context);
156     mImplementation->destroy();
157     mBoundCompiler.set(context, nullptr);
158     mImplementation.reset(nullptr);
159     delete this;
160 }
161 
~Shader()162 Shader::~Shader()
163 {
164     ASSERT(!mImplementation);
165 }
166 
setLabel(const Context * context,const std::string & label)167 angle::Result Shader::setLabel(const Context *context, const std::string &label)
168 {
169     mState.mLabel = label;
170 
171     if (mImplementation)
172     {
173         return mImplementation->onLabelUpdate(context);
174     }
175     return angle::Result::Continue;
176 }
177 
getLabel() const178 const std::string &Shader::getLabel() const
179 {
180     return mState.mLabel;
181 }
182 
getHandle() const183 ShaderProgramID Shader::getHandle() const
184 {
185     return mHandle;
186 }
187 
joinShaderSources(GLsizei count,const char * const * string,const GLint * length)188 std::string Shader::joinShaderSources(GLsizei count, const char *const *string, const GLint *length)
189 {
190     // Fast path for the most common case.
191     if (count == 1)
192     {
193         if (length == nullptr || length[0] < 0)
194             return std::string(string[0]);
195         else
196             return std::string(string[0], static_cast<size_t>(length[0]));
197     }
198 
199     // Start with totalLength of 1 to reserve space for the null terminator
200     size_t totalLength = 1;
201 
202     // First pass, calculate the total length of the joined string
203     for (GLsizei i = 0; i < count; ++i)
204     {
205         if (length == nullptr || length[i] < 0)
206             totalLength += std::strlen(string[i]);
207         else
208             totalLength += static_cast<size_t>(length[i]);
209     }
210 
211     // Second pass, allocate the string and concatenate each shader source
212     // fragment
213     std::string joinedString;
214     joinedString.reserve(totalLength);
215     for (GLsizei i = 0; i < count; ++i)
216     {
217         if (length == nullptr || length[i] < 0)
218             joinedString.append(string[i]);
219         else
220             joinedString.append(string[i], static_cast<size_t>(length[i]));
221     }
222 
223     return joinedString;
224 }
225 
setSource(const Context * context,GLsizei count,const char * const * string,const GLint * length)226 void Shader::setSource(const Context *context,
227                        GLsizei count,
228                        const char *const *string,
229                        const GLint *length)
230 {
231     std::string source = joinShaderSources(count, string, length);
232 
233     // Compute the hash based on the original source before any substitutions
234     size_t sourceHash = ComputeShaderHash(source);
235 
236     const angle::FrontendFeatures &frontendFeatures = context->getFrontendFeatures();
237 
238     bool substitutedShader = false;
239     const char *suffix     = "essl";
240     if (frontendFeatures.enableShaderSubstitution.enabled)
241     {
242         std::string subsitutionShaderPath = GetShaderDumpFilePath(sourceHash, suffix);
243 
244         std::string substituteShader;
245         if (angle::ReadFileToString(subsitutionShaderPath, &substituteShader))
246         {
247             source            = std::move(substituteShader);
248             substitutedShader = true;
249             INFO() << "Shader substitute found, loading from " << subsitutionShaderPath;
250         }
251     }
252 
253     // Only dump shaders that have not been previously substituted. It would write the same data
254     // back to the file.
255     if (frontendFeatures.dumpShaderSource.enabled && !substitutedShader)
256     {
257         std::string dumpFile = GetShaderDumpFilePath(sourceHash, suffix);
258 
259         writeFile(dumpFile.c_str(), source.c_str(), source.length());
260         INFO() << "Dumped shader source: " << dumpFile;
261     }
262 
263     mState.mSource     = std::move(source);
264     mState.mSourceHash = sourceHash;
265 }
266 
getInfoLogLength(const Context * context)267 int Shader::getInfoLogLength(const Context *context)
268 {
269     resolveCompile(context);
270     if (mInfoLog.empty())
271     {
272         return 0;
273     }
274 
275     return (static_cast<int>(mInfoLog.length()) + 1);
276 }
277 
getInfoLog(const Context * context,GLsizei bufSize,GLsizei * length,char * infoLog)278 void Shader::getInfoLog(const Context *context, GLsizei bufSize, GLsizei *length, char *infoLog)
279 {
280     resolveCompile(context);
281 
282     int index = 0;
283 
284     if (bufSize > 0)
285     {
286         index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length()));
287         memcpy(infoLog, mInfoLog.c_str(), index);
288 
289         infoLog[index] = '\0';
290     }
291 
292     if (length)
293     {
294         *length = index;
295     }
296 }
297 
getSourceLength() const298 int Shader::getSourceLength() const
299 {
300     return mState.mSource.empty() ? 0 : (static_cast<int>(mState.mSource.length()) + 1);
301 }
302 
getTranslatedSourceLength(const Context * context)303 int Shader::getTranslatedSourceLength(const Context *context)
304 {
305     resolveCompile(context);
306 
307     if (mState.getTranslatedSource().empty())
308     {
309         return 0;
310     }
311 
312     return (static_cast<int>(mState.getTranslatedSource().length()) + 1);
313 }
314 
getTranslatedSourceWithDebugInfoLength(const Context * context)315 int Shader::getTranslatedSourceWithDebugInfoLength(const Context *context)
316 {
317     resolveCompile(context);
318 
319     const std::string &debugInfo = mImplementation->getDebugInfo();
320     if (debugInfo.empty())
321     {
322         return 0;
323     }
324 
325     return (static_cast<int>(debugInfo.length()) + 1);
326 }
327 
328 // static
GetSourceImpl(const std::string & source,GLsizei bufSize,GLsizei * length,char * buffer)329 void Shader::GetSourceImpl(const std::string &source,
330                            GLsizei bufSize,
331                            GLsizei *length,
332                            char *buffer)
333 {
334     int index = 0;
335 
336     if (bufSize > 0)
337     {
338         index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
339         memcpy(buffer, source.c_str(), index);
340 
341         buffer[index] = '\0';
342     }
343 
344     if (length)
345     {
346         *length = index;
347     }
348 }
349 
getSource(GLsizei bufSize,GLsizei * length,char * buffer) const350 void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
351 {
352     GetSourceImpl(mState.mSource, bufSize, length, buffer);
353 }
354 
getTranslatedSource(const Context * context,GLsizei bufSize,GLsizei * length,char * buffer)355 void Shader::getTranslatedSource(const Context *context,
356                                  GLsizei bufSize,
357                                  GLsizei *length,
358                                  char *buffer)
359 {
360     GetSourceImpl(getTranslatedSource(context), bufSize, length, buffer);
361 }
362 
getTranslatedSource(const Context * context)363 const std::string &Shader::getTranslatedSource(const Context *context)
364 {
365     resolveCompile(context);
366     return mState.getTranslatedSource();
367 }
368 
getCompiledBinary(const Context * context)369 const sh::BinaryBlob &Shader::getCompiledBinary(const Context *context)
370 {
371     resolveCompile(context);
372     return mState.getCompiledBinary();
373 }
374 
getSourceHash() const375 size_t Shader::getSourceHash() const
376 {
377     return mState.mSourceHash;
378 }
379 
getTranslatedSourceWithDebugInfo(const Context * context,GLsizei bufSize,GLsizei * length,char * buffer)380 void Shader::getTranslatedSourceWithDebugInfo(const Context *context,
381                                               GLsizei bufSize,
382                                               GLsizei *length,
383                                               char *buffer)
384 {
385     resolveCompile(context);
386     const std::string &debugInfo = mImplementation->getDebugInfo();
387     GetSourceImpl(debugInfo, bufSize, length, buffer);
388 }
389 
compile(const Context * context)390 void Shader::compile(const Context *context)
391 {
392     resolveCompile(context);
393 
394     mState.mCompiledShaderState.translatedSource.clear();
395     mState.mCompiledShaderState.compiledBinary.clear();
396     mInfoLog.clear();
397     mState.mCompiledShaderState.shaderVersion = 100;
398     mState.mCompiledShaderState.inputVaryings.clear();
399     mState.mCompiledShaderState.outputVaryings.clear();
400     mState.mCompiledShaderState.uniforms.clear();
401     mState.mCompiledShaderState.uniformBlocks.clear();
402     mState.mCompiledShaderState.shaderStorageBlocks.clear();
403     mState.mCompiledShaderState.activeAttributes.clear();
404     mState.mCompiledShaderState.activeOutputVariables.clear();
405     mState.mCompiledShaderState.numViews = -1;
406     mState.mCompiledShaderState.geometryShaderInputPrimitiveType.reset();
407     mState.mCompiledShaderState.geometryShaderOutputPrimitiveType.reset();
408     mState.mCompiledShaderState.geometryShaderMaxVertices.reset();
409     mState.mCompiledShaderState.geometryShaderInvocations = 1;
410     mState.mCompiledShaderState.tessControlShaderVertices = 0;
411     mState.mCompiledShaderState.tessGenMode               = 0;
412     mState.mCompiledShaderState.tessGenSpacing            = 0;
413     mState.mCompiledShaderState.tessGenVertexOrder        = 0;
414     mState.mCompiledShaderState.tessGenPointMode          = 0;
415     mState.mCompiledShaderState.advancedBlendEquations.reset();
416     mState.mCompiledShaderState.hasClipDistance         = false;
417     mState.mCompiledShaderState.hasDiscard              = false;
418     mState.mCompiledShaderState.enablesPerSampleShading = false;
419     mState.mCompiledShaderState.specConstUsageBits.reset();
420 
421     mCurrentMaxComputeWorkGroupInvocations =
422         static_cast<GLuint>(context->getCaps().maxComputeWorkGroupInvocations);
423     mMaxComputeSharedMemory = context->getCaps().maxComputeSharedMemorySize;
424 
425     ShCompileOptions options = {};
426     options.objectCode       = true;
427     options.emulateGLDrawID  = true;
428 
429     // Add default options to WebGL shaders to prevent unexpected behavior during
430     // compilation.
431     if (context->isWebGL())
432     {
433         options.initGLPosition             = true;
434         options.limitCallStackDepth        = true;
435         options.limitExpressionComplexity  = true;
436         options.enforcePackingRestrictions = true;
437         options.initSharedVariables        = true;
438     }
439     else
440     {
441         // Per https://github.com/KhronosGroup/WebGL/pull/3278 gl_BaseVertex/gl_BaseInstance are
442         // removed from WebGL
443         options.emulateGLBaseVertexBaseInstance = true;
444     }
445 
446     // Some targets (e.g. D3D11 Feature Level 9_3 and below) do not support non-constant loop
447     // indexes in fragment shaders. Shader compilation will fail. To provide a better error
448     // message we can instruct the compiler to pre-validate.
449     if (mRendererLimitations.shadersRequireIndexedLoopValidation)
450     {
451         options.validateLoopIndexing = true;
452     }
453 
454     if (context->getFrontendFeatures().forceInitShaderVariables.enabled)
455     {
456         options.initOutputVariables           = true;
457         options.initializeUninitializedLocals = true;
458     }
459 
460     mBoundCompiler.set(context, context->getCompiler());
461 
462     ASSERT(mBoundCompiler.get());
463     ShCompilerInstance compilerInstance = mBoundCompiler->getInstance(mType);
464     ShHandle compilerHandle             = compilerInstance.getHandle();
465     ASSERT(compilerHandle);
466 
467     // Find a shader in Blob Cache
468     setShaderKey(context, options, compilerInstance.getShaderOutputType(),
469                  compilerInstance.getBuiltInResources());
470     ASSERT(!mShaderHash.empty());
471     MemoryShaderCache *shaderCache = context->getMemoryShaderCache();
472     if (shaderCache)
473     {
474         angle::Result cacheResult =
475             shaderCache->getShader(context, this, options, compilerInstance, mShaderHash);
476 
477         if (cacheResult == angle::Result::Continue)
478         {
479             compilerInstance.destroy();
480             return;
481         }
482     }
483 
484     // Cache load failed, fall through normal compiling.
485     mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED;
486     mCompilingState.reset(new CompilingState());
487     mCompilingState->shCompilerInstance = std::move(compilerInstance);
488     mCompilingState->compileEvent =
489         mImplementation->compile(context, &(mCompilingState->shCompilerInstance), &options);
490 }
491 
resolveCompile(const Context * context)492 void Shader::resolveCompile(const Context *context)
493 {
494     if (!mState.compilePending())
495     {
496         return;
497     }
498 
499     ASSERT(mCompilingState.get());
500 
501     mCompilingState->compileEvent->wait();
502 
503     mInfoLog += mCompilingState->compileEvent->getInfoLog();
504 
505     ScopedExit exit([this]() {
506         mBoundCompiler->putInstance(std::move(mCompilingState->shCompilerInstance));
507         mCompilingState->compileEvent.reset();
508         mCompilingState.reset();
509     });
510 
511     ShHandle compilerHandle = mCompilingState->shCompilerInstance.getHandle();
512     if (!mCompilingState->compileEvent->getResult())
513     {
514         mInfoLog += sh::GetInfoLog(compilerHandle);
515         INFO() << std::endl << mInfoLog;
516         mState.mCompileStatus = CompileStatus::NOT_COMPILED;
517         return;
518     }
519 
520     const ShShaderOutput outputType = mCompilingState->shCompilerInstance.getShaderOutputType();
521     bool isBinaryOutput             = outputType == SH_SPIRV_VULKAN_OUTPUT;
522     mState.mCompiledShaderState.buildCompiledShaderState(compilerHandle, isBinaryOutput);
523 
524     const angle::FrontendFeatures &frontendFeatures = context->getFrontendFeatures();
525     bool substitutedTranslatedShader                = false;
526     const char *suffix                              = "translated";
527     if (frontendFeatures.enableTranslatedShaderSubstitution.enabled)
528     {
529         // To support reading/writing compiled binaries (SPIR-V
530         // representation), need more file input/output facilities,
531         // and figure out the byte ordering of writing the 32-bit
532         // words to disk.
533         if (isBinaryOutput)
534         {
535             INFO() << "Can not substitute compiled binary (SPIR-V) shaders yet";
536         }
537         else
538         {
539             std::string substituteShaderPath = GetShaderDumpFilePath(mState.mSourceHash, suffix);
540 
541             std::string substituteShader;
542             if (angle::ReadFileToString(substituteShaderPath, &substituteShader))
543             {
544                 mState.mCompiledShaderState.translatedSource = std::move(substituteShader);
545                 substitutedTranslatedShader                  = true;
546                 INFO() << "Trasnslated shader substitute found, loading from "
547                        << substituteShaderPath;
548             }
549         }
550     }
551 
552     // Only dump translated shaders that have not been previously substituted. It would write the
553     // same data back to the file.
554     if (frontendFeatures.dumpTranslatedShaders.enabled && !substitutedTranslatedShader)
555     {
556         if (isBinaryOutput)
557         {
558             INFO() << "Can not dump compiled binary (SPIR-V) shaders yet";
559         }
560         else
561         {
562             std::string dumpFile = GetShaderDumpFilePath(mState.mSourceHash, suffix);
563 
564             const std::string &translatedSource = mState.mCompiledShaderState.translatedSource;
565             writeFile(dumpFile.c_str(), translatedSource.c_str(), translatedSource.length());
566             INFO() << "Dumped translated source: " << dumpFile;
567         }
568     }
569 
570 #if !defined(NDEBUG)
571     if (outputType != SH_SPIRV_VULKAN_OUTPUT)
572     {
573         // Prefix translated shader with commented out un-translated shader.
574         // Useful in diagnostics tools which capture the shader source.
575         std::ostringstream shaderStream;
576         shaderStream << "// GLSL\n";
577         shaderStream << "//\n";
578 
579         std::istringstream inputSourceStream(mState.mSource);
580         std::string line;
581         while (std::getline(inputSourceStream, line))
582         {
583             // Remove null characters from the source line
584             line.erase(std::remove(line.begin(), line.end(), '\0'), line.end());
585 
586             shaderStream << "// " << line;
587 
588             // glslang complains if a comment ends with backslash
589             if (!line.empty() && line.back() == '\\')
590             {
591                 shaderStream << "\\";
592             }
593 
594             shaderStream << std::endl;
595         }
596         shaderStream << "\n\n";
597         shaderStream << mState.mCompiledShaderState.translatedSource;
598         mState.mCompiledShaderState.translatedSource = shaderStream.str();
599     }
600 #endif  // !defined(NDEBUG)
601 
602     // Validation checks for compute shaders
603     if (mState.mCompiledShaderState.shaderType == ShaderType::Compute &&
604         mState.mCompiledShaderState.localSize.isDeclared())
605     {
606         angle::CheckedNumeric<uint32_t> checked_local_size_product(
607             mState.mCompiledShaderState.localSize[0]);
608         checked_local_size_product *= mState.mCompiledShaderState.localSize[1];
609         checked_local_size_product *= mState.mCompiledShaderState.localSize[2];
610 
611         if (!checked_local_size_product.IsValid())
612         {
613             WARN() << std::endl
614                    << "Integer overflow when computing the product of local_size_x, "
615                    << "local_size_y and local_size_z.";
616             mState.mCompileStatus = CompileStatus::NOT_COMPILED;
617             return;
618         }
619         if (checked_local_size_product.ValueOrDie() > mCurrentMaxComputeWorkGroupInvocations)
620         {
621             WARN() << std::endl
622                    << "The total number of invocations within a work group exceeds "
623                    << "MAX_COMPUTE_WORK_GROUP_INVOCATIONS.";
624             mState.mCompileStatus = CompileStatus::NOT_COMPILED;
625             return;
626         }
627     }
628 
629     unsigned int sharedMemSize = sh::GetShaderSharedMemorySize(compilerHandle);
630     if (sharedMemSize > mMaxComputeSharedMemory)
631     {
632         WARN() << std::endl << "Exceeded maximum shared memory size";
633         mState.mCompileStatus = CompileStatus::NOT_COMPILED;
634         return;
635     }
636 
637     ASSERT(!mState.mCompiledShaderState.translatedSource.empty() ||
638            !mState.mCompiledShaderState.compiledBinary.empty());
639 
640     bool success          = mCompilingState->compileEvent->postTranslate(&mInfoLog);
641     mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED;
642 
643     MemoryShaderCache *shaderCache = context->getMemoryShaderCache();
644     if (success && shaderCache)
645     {
646         // Save to the shader cache.
647         if (shaderCache->putShader(context, mShaderHash, this) != angle::Result::Continue)
648         {
649             ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
650                                "Failed to save compiled shader to memory shader cache.");
651         }
652     }
653 }
654 
addRef()655 void Shader::addRef()
656 {
657     mRefCount++;
658 }
659 
release(const Context * context)660 void Shader::release(const Context *context)
661 {
662     mRefCount--;
663 
664     if (mRefCount == 0 && mDeleteStatus)
665     {
666         mResourceManager->deleteShader(context, mHandle);
667     }
668 }
669 
getRefCount() const670 unsigned int Shader::getRefCount() const
671 {
672     return mRefCount;
673 }
674 
isFlaggedForDeletion() const675 bool Shader::isFlaggedForDeletion() const
676 {
677     return mDeleteStatus;
678 }
679 
flagForDeletion()680 void Shader::flagForDeletion()
681 {
682     mDeleteStatus = true;
683 }
684 
isCompiled(const Context * context)685 bool Shader::isCompiled(const Context *context)
686 {
687     resolveCompile(context);
688     return mState.mCompileStatus == CompileStatus::COMPILED;
689 }
690 
isCompleted()691 bool Shader::isCompleted()
692 {
693     return (!mState.compilePending() || mCompilingState->compileEvent->isReady());
694 }
695 
getShaderVersion(const Context * context)696 int Shader::getShaderVersion(const Context *context)
697 {
698     resolveCompile(context);
699     return mState.mCompiledShaderState.shaderVersion;
700 }
701 
getInputVaryings(const Context * context)702 const std::vector<sh::ShaderVariable> &Shader::getInputVaryings(const Context *context)
703 {
704     resolveCompile(context);
705     return mState.getInputVaryings();
706 }
707 
getOutputVaryings(const Context * context)708 const std::vector<sh::ShaderVariable> &Shader::getOutputVaryings(const Context *context)
709 {
710     resolveCompile(context);
711     return mState.getOutputVaryings();
712 }
713 
getUniforms(const Context * context)714 const std::vector<sh::ShaderVariable> &Shader::getUniforms(const Context *context)
715 {
716     resolveCompile(context);
717     return mState.getUniforms();
718 }
719 
getUniformBlocks(const Context * context)720 const std::vector<sh::InterfaceBlock> &Shader::getUniformBlocks(const Context *context)
721 {
722     resolveCompile(context);
723     return mState.getUniformBlocks();
724 }
725 
getShaderStorageBlocks(const Context * context)726 const std::vector<sh::InterfaceBlock> &Shader::getShaderStorageBlocks(const Context *context)
727 {
728     resolveCompile(context);
729     return mState.getShaderStorageBlocks();
730 }
731 
getActiveAttributes(const Context * context)732 const std::vector<sh::ShaderVariable> &Shader::getActiveAttributes(const Context *context)
733 {
734     resolveCompile(context);
735     return mState.getActiveAttributes();
736 }
737 
getAllAttributes(const Context * context)738 const std::vector<sh::ShaderVariable> &Shader::getAllAttributes(const Context *context)
739 {
740     resolveCompile(context);
741     return mState.getAllAttributes();
742 }
743 
getActiveOutputVariables(const Context * context)744 const std::vector<sh::ShaderVariable> &Shader::getActiveOutputVariables(const Context *context)
745 {
746     resolveCompile(context);
747     return mState.getActiveOutputVariables();
748 }
749 
getTransformFeedbackVaryingMappedName(const Context * context,const std::string & tfVaryingName)750 std::string Shader::getTransformFeedbackVaryingMappedName(const Context *context,
751                                                           const std::string &tfVaryingName)
752 {
753     ASSERT(mState.getShaderType() != ShaderType::Fragment &&
754            mState.getShaderType() != ShaderType::Compute);
755     const auto &varyings = getOutputVaryings(context);
756     auto bracketPos      = tfVaryingName.find("[");
757     if (bracketPos != std::string::npos)
758     {
759         auto tfVaryingBaseName = tfVaryingName.substr(0, bracketPos);
760         for (const auto &varying : varyings)
761         {
762             if (varying.name == tfVaryingBaseName)
763             {
764                 std::string mappedNameWithArrayIndex =
765                     varying.mappedName + tfVaryingName.substr(bracketPos);
766                 return mappedNameWithArrayIndex;
767             }
768         }
769     }
770     else
771     {
772         for (const auto &varying : varyings)
773         {
774             if (varying.name == tfVaryingName)
775             {
776                 return varying.mappedName;
777             }
778             else if (varying.isStruct())
779             {
780                 GLuint fieldIndex = 0;
781                 const auto *field = varying.findField(tfVaryingName, &fieldIndex);
782                 if (field == nullptr)
783                 {
784                     continue;
785                 }
786                 ASSERT(field != nullptr && !field->isStruct() &&
787                        (!field->isArray() || varying.isShaderIOBlock));
788                 std::string mappedName;
789                 // If it's an I/O block without an instance name, don't include the block name.
790                 if (!varying.isShaderIOBlock || !varying.name.empty())
791                 {
792                     mappedName = varying.isShaderIOBlock ? varying.mappedStructOrBlockName
793                                                          : varying.mappedName;
794                     mappedName += '.';
795                 }
796                 return mappedName + field->mappedName;
797             }
798         }
799     }
800     UNREACHABLE();
801     return std::string();
802 }
803 
getWorkGroupSize(const Context * context)804 const sh::WorkGroupSize &Shader::getWorkGroupSize(const Context *context)
805 {
806     resolveCompile(context);
807     return mState.mCompiledShaderState.localSize;
808 }
809 
getNumViews(const Context * context)810 int Shader::getNumViews(const Context *context)
811 {
812     resolveCompile(context);
813     return mState.mCompiledShaderState.numViews;
814 }
815 
getGeometryShaderInputPrimitiveType(const Context * context)816 Optional<PrimitiveMode> Shader::getGeometryShaderInputPrimitiveType(const Context *context)
817 {
818     resolveCompile(context);
819     return mState.mCompiledShaderState.geometryShaderInputPrimitiveType;
820 }
821 
getGeometryShaderOutputPrimitiveType(const Context * context)822 Optional<PrimitiveMode> Shader::getGeometryShaderOutputPrimitiveType(const Context *context)
823 {
824     resolveCompile(context);
825     return mState.mCompiledShaderState.geometryShaderOutputPrimitiveType;
826 }
827 
getGeometryShaderInvocations(const Context * context)828 int Shader::getGeometryShaderInvocations(const Context *context)
829 {
830     resolveCompile(context);
831     return mState.mCompiledShaderState.geometryShaderInvocations;
832 }
833 
getGeometryShaderMaxVertices(const Context * context)834 Optional<GLint> Shader::getGeometryShaderMaxVertices(const Context *context)
835 {
836     resolveCompile(context);
837     return mState.mCompiledShaderState.geometryShaderMaxVertices;
838 }
839 
getTessControlShaderVertices(const Context * context)840 int Shader::getTessControlShaderVertices(const Context *context)
841 {
842     resolveCompile(context);
843     return mState.mCompiledShaderState.tessControlShaderVertices;
844 }
845 
getTessGenMode(const Context * context)846 GLenum Shader::getTessGenMode(const Context *context)
847 {
848     resolveCompile(context);
849     return mState.mCompiledShaderState.tessGenMode;
850 }
851 
getTessGenSpacing(const Context * context)852 GLenum Shader::getTessGenSpacing(const Context *context)
853 {
854     resolveCompile(context);
855     return mState.mCompiledShaderState.tessGenSpacing;
856 }
857 
getTessGenVertexOrder(const Context * context)858 GLenum Shader::getTessGenVertexOrder(const Context *context)
859 {
860     resolveCompile(context);
861     return mState.mCompiledShaderState.tessGenVertexOrder;
862 }
863 
getTessGenPointMode(const Context * context)864 GLenum Shader::getTessGenPointMode(const Context *context)
865 {
866     resolveCompile(context);
867     return mState.mCompiledShaderState.tessGenPointMode;
868 }
869 
serialize(const Context * context,angle::MemoryBuffer * binaryOut) const870 angle::Result Shader::serialize(const Context *context, angle::MemoryBuffer *binaryOut) const
871 {
872     BinaryOutputStream stream;
873 
874     stream.writeInt(kShaderCacheIdentifier);
875     mState.mCompiledShaderState.serialize(stream);
876 
877     ASSERT(binaryOut);
878     if (!binaryOut->resize(stream.length()))
879     {
880         std::stringstream sstream;
881         sstream << "Failed to allocate enough memory to serialize a shader. (" << stream.length()
882                 << " bytes )";
883         ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
884                            sstream.str().c_str());
885         return angle::Result::Incomplete;
886     }
887 
888     memcpy(binaryOut->data(), stream.data(), stream.length());
889 
890     return angle::Result::Continue;
891 }
892 
deserialize(BinaryInputStream & stream)893 angle::Result Shader::deserialize(BinaryInputStream &stream)
894 {
895     mState.mCompiledShaderState.deserialize(stream);
896 
897     if (stream.error())
898     {
899         // Error while deserializing binary stream
900         return angle::Result::Stop;
901     }
902 
903     return angle::Result::Continue;
904 }
905 
loadBinary(const Context * context,const void * binary,GLsizei length)906 angle::Result Shader::loadBinary(const Context *context, const void *binary, GLsizei length)
907 {
908     return loadBinaryImpl(context, binary, length, false);
909 }
910 
loadShaderBinary(const Context * context,const void * binary,GLsizei length)911 angle::Result Shader::loadShaderBinary(const Context *context, const void *binary, GLsizei length)
912 {
913     return loadBinaryImpl(context, binary, length, true);
914 }
915 
loadBinaryImpl(const Context * context,const void * binary,GLsizei length,bool generatedWithOfflineCompiler)916 angle::Result Shader::loadBinaryImpl(const Context *context,
917                                      const void *binary,
918                                      GLsizei length,
919                                      bool generatedWithOfflineCompiler)
920 {
921     BinaryInputStream stream(binary, length);
922 
923     // Shader binaries generated with offline compiler have additional fields
924     if (generatedWithOfflineCompiler)
925     {
926         // Load binary from a glShaderBinary call.
927         // Validation layer should have already verified that the shader program version and shader
928         // type match
929         std::vector<uint8_t> commitString(angle::GetANGLEShaderProgramVersionHashSize(), 0);
930         stream.readBytes(commitString.data(), commitString.size());
931         ASSERT(memcmp(commitString.data(), angle::GetANGLEShaderProgramVersion(),
932                       commitString.size()) == 0);
933 
934         gl::ShaderType shaderType;
935         stream.readEnum(&shaderType);
936         ASSERT(mType == shaderType);
937 
938         // Get fields needed to generate the key for memory caches.
939         ShShaderOutput outputType;
940         stream.readEnum<ShShaderOutput>(&outputType);
941 
942         // Get the shader's source string.
943         mState.mSource = stream.readString();
944 
945         // In the absence of element-by-element serialize/deserialize functions, read
946         // ShCompileOptions and ShBuiltInResources as raw binary blobs.
947         ShCompileOptions compileOptions;
948         stream.readBytes(reinterpret_cast<uint8_t *>(&compileOptions), sizeof(ShCompileOptions));
949 
950         ShBuiltInResources resources;
951         stream.readBytes(reinterpret_cast<uint8_t *>(&resources), sizeof(ShBuiltInResources));
952 
953         setShaderKey(context, compileOptions, outputType, resources);
954     }
955     else
956     {
957         // Load binary from shader cache.
958         if (stream.readInt<uint32_t>() != kShaderCacheIdentifier)
959         {
960             return angle::Result::Stop;
961         }
962     }
963 
964     ANGLE_TRY(deserialize(stream));
965 
966     // Only successfully-compiled shaders are serialized. If deserialization is successful, we can
967     // assume the CompileStatus.
968     mState.mCompileStatus = CompileStatus::COMPILED;
969 
970     return angle::Result::Continue;
971 }
972 
setShaderKey(const Context * context,const ShCompileOptions & compileOptions,const ShShaderOutput & outputType,const ShBuiltInResources & resources)973 void Shader::setShaderKey(const Context *context,
974                           const ShCompileOptions &compileOptions,
975                           const ShShaderOutput &outputType,
976                           const ShBuiltInResources &resources)
977 {
978     // Compute shader key.
979     BinaryOutputStream hashStream;
980 
981     // Start with the shader type and source.
982     hashStream.writeEnum(mType);
983     hashStream.writeString(mState.getSource());
984 
985     // Include the shader program version hash.
986     hashStream.writeString(angle::GetANGLEShaderProgramVersion());
987 
988     hashStream.writeEnum(Compiler::SelectShaderSpec(context->getState()));
989     hashStream.writeEnum(outputType);
990     hashStream.writeBytes(reinterpret_cast<const uint8_t *>(&compileOptions),
991                           sizeof(compileOptions));
992 
993     // Include the ShBuiltInResources, which represent the extensions and constants used by the
994     // shader.
995     hashStream.writeBytes(reinterpret_cast<const uint8_t *>(&resources), sizeof(resources));
996 
997     // Call the secure SHA hashing function.
998     const std::vector<uint8_t> &shaderKey = hashStream.getData();
999     mShaderHash                           = {0};
1000     angle::base::SHA1HashBytes(shaderKey.data(), shaderKey.size(), mShaderHash.data());
1001 }
1002 
1003 }  // namespace gl
1004