xref: /aosp_15_r20/external/angle/src/libANGLE/Shader.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 "libANGLE/trace.h"
32 #include "platform/autogen/FrontendFeatures_autogen.h"
33 
34 namespace gl
35 {
36 
37 namespace
38 {
39 constexpr uint32_t kShaderCacheIdentifier = 0x12345678;
40 
41 // Environment variable (and associated Android property) for the path to read and write shader
42 // dumps
43 constexpr char kShaderDumpPathVarName[]       = "ANGLE_SHADER_DUMP_PATH";
44 constexpr char kEShaderDumpPathPropertyName[] = "debug.angle.shader_dump_path";
45 
ComputeShaderHash(const std::string & mergedSource)46 size_t ComputeShaderHash(const std::string &mergedSource)
47 {
48     return std::hash<std::string>{}(mergedSource);
49 }
50 
GetShaderDumpFilePath(size_t shaderHash,const char * suffix)51 std::string GetShaderDumpFilePath(size_t shaderHash, const char *suffix)
52 {
53     std::stringstream path;
54     std::string shaderDumpDir = GetShaderDumpFileDirectory();
55     if (!shaderDumpDir.empty())
56     {
57         path << shaderDumpDir << "/";
58     }
59     path << shaderHash << "." << suffix;
60 
61     return path.str();
62 }
63 
64 class CompileTask final : public angle::Closure
65 {
66   public:
67     // Translate and compile
CompileTask(const angle::FrontendFeatures & frontendFeatures,ShHandle compilerHandle,ShShaderOutput outputType,const ShCompileOptions & options,const std::string & source,size_t sourceHash,const SharedCompiledShaderState & compiledState,size_t maxComputeWorkGroupInvocations,size_t maxComputeSharedMemory,std::shared_ptr<rx::ShaderTranslateTask> && translateTask)68     CompileTask(const angle::FrontendFeatures &frontendFeatures,
69                 ShHandle compilerHandle,
70                 ShShaderOutput outputType,
71                 const ShCompileOptions &options,
72                 const std::string &source,
73                 size_t sourceHash,
74                 const SharedCompiledShaderState &compiledState,
75                 size_t maxComputeWorkGroupInvocations,
76                 size_t maxComputeSharedMemory,
77                 std::shared_ptr<rx::ShaderTranslateTask> &&translateTask)
78         : mFrontendFeatures(frontendFeatures),
79           mMaxComputeWorkGroupInvocations(maxComputeWorkGroupInvocations),
80           mMaxComputeSharedMemory(maxComputeSharedMemory),
81           mCompilerHandle(compilerHandle),
82           mOutputType(outputType),
83           mOptions(options),
84           mSource(source),
85           mSourceHash(sourceHash),
86           mCompiledState(compiledState),
87           mTranslateTask(std::move(translateTask))
88     {}
89 
90     // Load from binary
CompileTask(const angle::FrontendFeatures & frontendFeatures,const SharedCompiledShaderState & compiledState,std::shared_ptr<rx::ShaderTranslateTask> && translateTask)91     CompileTask(const angle::FrontendFeatures &frontendFeatures,
92                 const SharedCompiledShaderState &compiledState,
93                 std::shared_ptr<rx::ShaderTranslateTask> &&translateTask)
94         : mFrontendFeatures(frontendFeatures),
95           mCompiledState(compiledState),
96           mTranslateTask(std::move(translateTask))
97     {}
98     ~CompileTask() override = default;
99 
operator ()()100     void operator()() override { mResult = compileImpl(); }
101 
getResult()102     angle::Result getResult()
103     {
104         // Note: this function is called from WaitCompileJobUnlocked(), and must therefore be
105         // thread-safe if the linkJobIsThreadSafe feature is enabled.  Without linkJobIsThreadSafe,
106         // the call will end up done in the main thread, which is the case for the GL backend (which
107         // happens to be the only backend that actually does anything in getResult).
108         //
109         // Consequently, this function must not _write_ to anything, e.g. by trying to cache the
110         // result of |mTranslateTask->getResult()|.
111         ANGLE_TRY(mResult);
112         ANGLE_TRY(mTranslateTask->getResult(mInfoLog));
113 
114         return angle::Result::Continue;
115     }
116 
isCompilingInternally()117     bool isCompilingInternally() { return mTranslateTask->isCompilingInternally(); }
118 
getInfoLog()119     std::string &&getInfoLog() { return std::move(mInfoLog); }
120 
121   private:
122     angle::Result compileImpl();
123     angle::Result postTranslate();
124 
125     // Global constants that are safe to access by the worker thread
126     const angle::FrontendFeatures &mFrontendFeatures;
127     size_t mMaxComputeWorkGroupInvocations = 0;
128     size_t mMaxComputeSharedMemory         = 0;
129 
130     // Access to the compile information.  Note that the compiler instance is kept alive until
131     // resolveCompile.
132     ShHandle mCompilerHandle = 0;
133     ShShaderOutput mOutputType;
134     ShCompileOptions mOptions;
135     const std::string mSource;
136     size_t mSourceHash = 0;
137     SharedCompiledShaderState mCompiledState;
138 
139     std::shared_ptr<rx::ShaderTranslateTask> mTranslateTask;
140     angle::Result mResult;
141     std::string mInfoLog;
142 };
143 
144 class CompileEvent final
145 {
146   public:
CompileEvent(const std::shared_ptr<CompileTask> & compileTask,const std::shared_ptr<angle::WaitableEvent> & waitEvent)147     CompileEvent(const std::shared_ptr<CompileTask> &compileTask,
148                  const std::shared_ptr<angle::WaitableEvent> &waitEvent)
149         : mCompileTask(compileTask), mWaitableEvent(waitEvent)
150     {}
151     ~CompileEvent() = default;
152 
wait()153     angle::Result wait()
154     {
155         ANGLE_TRACE_EVENT0("gpu.angle", "CompileEvent::wait");
156 
157         mWaitableEvent->wait();
158 
159         return mCompileTask->getResult();
160     }
isCompiling()161     bool isCompiling()
162     {
163         return !mWaitableEvent->isReady() || mCompileTask->isCompilingInternally();
164     }
165 
getInfoLog()166     std::string &&getInfoLog() { return std::move(mCompileTask->getInfoLog()); }
167 
168   private:
169     std::shared_ptr<CompileTask> mCompileTask;
170     std::shared_ptr<angle::WaitableEvent> mWaitableEvent;
171 };
172 
compileImpl()173 angle::Result CompileTask::compileImpl()
174 {
175     if (mCompilerHandle)
176     {
177         // Compiling from source
178 
179         // Call the translator and get the info log
180         bool result = mTranslateTask->translate(mCompilerHandle, mOptions, mSource);
181         mInfoLog    = sh::GetInfoLog(mCompilerHandle);
182         if (!result)
183         {
184             return angle::Result::Stop;
185         }
186 
187         // Process the translation results itself; gather compilation info, substitute the shader if
188         // being overriden, etc.
189         return postTranslate();
190     }
191     else
192     {
193         // Loading from binary
194         mTranslateTask->load(*mCompiledState.get());
195         return angle::Result::Continue;
196     }
197 }
198 
postTranslate()199 angle::Result CompileTask::postTranslate()
200 {
201     const bool isBinaryOutput = mOutputType == SH_SPIRV_VULKAN_OUTPUT;
202     mCompiledState->buildCompiledShaderState(mCompilerHandle, isBinaryOutput);
203 
204     ASSERT(!mCompiledState->translatedSource.empty() || !mCompiledState->compiledBinary.empty());
205 
206     // Validation checks for compute shaders
207     if (mCompiledState->shaderType == ShaderType::Compute && mCompiledState->localSize.isDeclared())
208     {
209         angle::CheckedNumeric<size_t> checked_local_size_product(mCompiledState->localSize[0]);
210         checked_local_size_product *= mCompiledState->localSize[1];
211         checked_local_size_product *= mCompiledState->localSize[2];
212 
213         if (!checked_local_size_product.IsValid() ||
214             checked_local_size_product.ValueOrDie() > mMaxComputeWorkGroupInvocations)
215         {
216             mInfoLog +=
217                 "\nThe total number of invocations within a work group exceeds "
218                 "MAX_COMPUTE_WORK_GROUP_INVOCATIONS.";
219             return angle::Result::Stop;
220         }
221     }
222 
223     unsigned int sharedMemSize = sh::GetShaderSharedMemorySize(mCompilerHandle);
224     if (sharedMemSize > mMaxComputeSharedMemory)
225     {
226         mInfoLog += "\nShared memory size exceeds GL_MAX_COMPUTE_SHARED_MEMORY_SIZE";
227         return angle::Result::Stop;
228     }
229 
230     bool substitutedTranslatedShader = false;
231     const char *suffix               = "translated";
232     if (mFrontendFeatures.enableTranslatedShaderSubstitution.enabled)
233     {
234         // To support reading/writing compiled binaries (SPIR-V representation), need more file
235         // input/output facilities, and figure out the byte ordering of writing the 32-bit words to
236         // disk.
237         if (isBinaryOutput)
238         {
239             INFO() << "Can not substitute compiled binary (SPIR-V) shaders yet";
240         }
241         else
242         {
243             std::string substituteShaderPath = GetShaderDumpFilePath(mSourceHash, suffix);
244 
245             std::string substituteShader;
246             if (angle::ReadFileToString(substituteShaderPath, &substituteShader))
247             {
248                 mCompiledState->translatedSource = std::move(substituteShader);
249                 substitutedTranslatedShader      = true;
250                 INFO() << "Translated shader substitute found, loading from "
251                        << substituteShaderPath;
252             }
253         }
254     }
255 
256     // Only dump translated shaders that have not been previously substituted. It would write the
257     // same data back to the file.
258     if (mFrontendFeatures.dumpTranslatedShaders.enabled && !substitutedTranslatedShader)
259     {
260         if (isBinaryOutput)
261         {
262             INFO() << "Can not dump compiled binary (SPIR-V) shaders yet";
263         }
264         else
265         {
266             std::string dumpFile = GetShaderDumpFilePath(mSourceHash, suffix);
267 
268             const std::string &translatedSource = mCompiledState->translatedSource;
269             writeFile(dumpFile.c_str(), translatedSource.c_str(), translatedSource.length());
270             INFO() << "Dumped translated source: " << dumpFile;
271         }
272     }
273 
274 #if defined(ANGLE_ENABLE_ASSERTS)
275     if (!isBinaryOutput)
276     {
277         // Suffix the translated shader with commented out un-translated shader.
278         // Useful in diagnostics tools which capture the shader source.
279         std::ostringstream shaderStream;
280         shaderStream << "\n";
281         shaderStream << "// GLSL\n";
282         shaderStream << "//\n";
283 
284         std::istringstream inputSourceStream(mSource);
285         std::string line;
286         while (std::getline(inputSourceStream, line))
287         {
288             // Remove null characters from the source line
289             line.erase(std::remove(line.begin(), line.end(), '\0'), line.end());
290 
291             shaderStream << "// " << line;
292 
293             // glslang complains if a comment ends with backslash
294             if (!line.empty() && line.back() == '\\')
295             {
296                 shaderStream << "\\";
297             }
298 
299             shaderStream << std::endl;
300         }
301         mCompiledState->translatedSource += shaderStream.str();
302     }
303 #endif  // defined(ANGLE_ENABLE_ASSERTS)
304 
305     // Let the backend process the result of the compilation.  For the GL backend, this means
306     // kicking off compilation internally.  Some of the other backends fill in their internal
307     // "compiled state" at this point.
308     mTranslateTask->postTranslate(mCompilerHandle, *mCompiledState.get());
309 
310     return angle::Result::Continue;
311 }
312 
313 template <typename T>
AppendHashValue(angle::base::SecureHashAlgorithm & hasher,T value)314 void AppendHashValue(angle::base::SecureHashAlgorithm &hasher, T value)
315 {
316     static_assert(std::is_fundamental<T>::value || std::is_enum<T>::value);
317     hasher.Update(&value, sizeof(T));
318 }
319 
GetTranslateTaskThreadSafety(const Context * context)320 angle::JobThreadSafety GetTranslateTaskThreadSafety(const Context *context)
321 {
322     // The GL backend relies on the driver's internal parallel compilation, and thus does not use a
323     // thread to compile.  A front-end feature selects whether the single-threaded pool must be
324     // used.
325     return context->getFrontendFeatures().compileJobIsThreadSafe.enabled
326                ? angle::JobThreadSafety::Safe
327                : angle::JobThreadSafety::Unsafe;
328 }
329 
330 }  // anonymous namespace
331 
GetShaderTypeString(ShaderType type)332 const char *GetShaderTypeString(ShaderType type)
333 {
334     switch (type)
335     {
336         case ShaderType::Vertex:
337             return "VERTEX";
338 
339         case ShaderType::Fragment:
340             return "FRAGMENT";
341 
342         case ShaderType::Compute:
343             return "COMPUTE";
344 
345         case ShaderType::Geometry:
346             return "GEOMETRY";
347 
348         case ShaderType::TessControl:
349             return "TESS_CONTROL";
350 
351         case ShaderType::TessEvaluation:
352             return "TESS_EVALUATION";
353 
354         default:
355             UNREACHABLE();
356             return "";
357     }
358 }
359 
GetShaderDumpFileDirectory()360 std::string GetShaderDumpFileDirectory()
361 {
362     // Check the environment variable for the path to save and read shader dump files.
363     std::string environmentVariableDumpDir =
364         angle::GetAndSetEnvironmentVarOrUnCachedAndroidProperty(kShaderDumpPathVarName,
365                                                                 kEShaderDumpPathPropertyName);
366     if (!environmentVariableDumpDir.empty() && environmentVariableDumpDir.compare("0") != 0)
367     {
368         return environmentVariableDumpDir;
369     }
370 
371     // Fall back to the temp dir. If that doesn't exist, use the current working directory.
372     return angle::GetTempDirectory().valueOr("");
373 }
374 
GetShaderDumpFileName(size_t shaderHash)375 std::string GetShaderDumpFileName(size_t shaderHash)
376 {
377     std::stringstream name;
378     name << shaderHash << ".essl";
379     return name.str();
380 }
381 
382 struct CompileJob
383 {
384     virtual ~CompileJob() = default;
waitgl::CompileJob385     virtual bool wait() { return compileEvent->wait() == angle::Result::Continue; }
386 
387     std::unique_ptr<CompileEvent> compileEvent;
388     ShCompilerInstance shCompilerInstance;
389 };
390 
391 struct CompileJobDone final : public CompileJob
392 {
CompileJobDonegl::CompileJobDone393     CompileJobDone(bool compiledIn) : compiled(compiledIn) {}
waitgl::CompileJobDone394     bool wait() override { return compiled; }
395 
396     bool compiled;
397 };
398 
ShaderState(ShaderType shaderType)399 ShaderState::ShaderState(ShaderType shaderType)
400     : mCompiledState(std::make_shared<CompiledShaderState>(shaderType))
401 {}
402 
~ShaderState()403 ShaderState::~ShaderState() {}
404 
Shader(ShaderProgramManager * manager,rx::GLImplFactory * implFactory,const gl::Limitations & rendererLimitations,ShaderType type,ShaderProgramID handle)405 Shader::Shader(ShaderProgramManager *manager,
406                rx::GLImplFactory *implFactory,
407                const gl::Limitations &rendererLimitations,
408                ShaderType type,
409                ShaderProgramID handle)
410     : mState(type),
411       mImplementation(implFactory->createShader(mState)),
412       mRendererLimitations(rendererLimitations),
413       mHandle(handle),
414       mRefCount(0),
415       mDeleteStatus(false),
416       mResourceManager(manager)
417 {
418     ASSERT(mImplementation);
419 
420     mShaderHash = {0};
421 }
422 
onDestroy(const gl::Context * context)423 void Shader::onDestroy(const gl::Context *context)
424 {
425     resolveCompile(context);
426     mImplementation->onDestroy(context);
427     mBoundCompiler.set(context, nullptr);
428     mImplementation.reset(nullptr);
429     delete this;
430 }
431 
~Shader()432 Shader::~Shader()
433 {
434     ASSERT(!mImplementation);
435 }
436 
setLabel(const Context * context,const std::string & label)437 angle::Result Shader::setLabel(const Context *context, const std::string &label)
438 {
439     mState.mLabel = label;
440 
441     if (mImplementation)
442     {
443         return mImplementation->onLabelUpdate(context);
444     }
445     return angle::Result::Continue;
446 }
447 
getLabel() const448 const std::string &Shader::getLabel() const
449 {
450     return mState.mLabel;
451 }
452 
getHandle() const453 ShaderProgramID Shader::getHandle() const
454 {
455     return mHandle;
456 }
457 
joinShaderSources(GLsizei count,const char * const * string,const GLint * length)458 std::string Shader::joinShaderSources(GLsizei count, const char *const *string, const GLint *length)
459 {
460     // Fast path for the most common case.
461     if (count == 1)
462     {
463         if (length == nullptr || length[0] < 0)
464             return std::string(string[0]);
465         else
466             return std::string(string[0], static_cast<size_t>(length[0]));
467     }
468 
469     // Start with totalLength of 1 to reserve space for the null terminator
470     size_t totalLength = 1;
471 
472     // First pass, calculate the total length of the joined string
473     for (GLsizei i = 0; i < count; ++i)
474     {
475         if (length == nullptr || length[i] < 0)
476             totalLength += std::strlen(string[i]);
477         else
478             totalLength += static_cast<size_t>(length[i]);
479     }
480 
481     // Second pass, allocate the string and concatenate each shader source
482     // fragment
483     std::string joinedString;
484     joinedString.reserve(totalLength);
485     for (GLsizei i = 0; i < count; ++i)
486     {
487         if (length == nullptr || length[i] < 0)
488             joinedString.append(string[i]);
489         else
490             joinedString.append(string[i], static_cast<size_t>(length[i]));
491     }
492 
493     return joinedString;
494 }
495 
setSource(const Context * context,GLsizei count,const char * const * string,const GLint * length)496 void Shader::setSource(const Context *context,
497                        GLsizei count,
498                        const char *const *string,
499                        const GLint *length)
500 {
501     std::string source = joinShaderSources(count, string, length);
502 
503     // Compute the hash based on the original source before any substitutions
504     size_t sourceHash = ComputeShaderHash(source);
505 
506     const angle::FrontendFeatures &frontendFeatures = context->getFrontendFeatures();
507 
508     bool substitutedShader = false;
509     const char *suffix     = "essl";
510     if (frontendFeatures.enableShaderSubstitution.enabled)
511     {
512         std::string subsitutionShaderPath = GetShaderDumpFilePath(sourceHash, suffix);
513 
514         std::string substituteShader;
515         if (angle::ReadFileToString(subsitutionShaderPath, &substituteShader))
516         {
517             source            = std::move(substituteShader);
518             substitutedShader = true;
519             INFO() << "Shader substitute found, loading from " << subsitutionShaderPath;
520         }
521     }
522 
523     // Only dump shaders that have not been previously substituted. It would write the same data
524     // back to the file.
525     if (frontendFeatures.dumpShaderSource.enabled && !substitutedShader)
526     {
527         std::string dumpFile = GetShaderDumpFilePath(sourceHash, suffix);
528 
529         writeFile(dumpFile.c_str(), source.c_str(), source.length());
530         INFO() << "Dumped shader source: " << dumpFile;
531     }
532 
533     mState.mSource     = std::move(source);
534     mState.mSourceHash = sourceHash;
535 }
536 
getInfoLogLength(const Context * context)537 int Shader::getInfoLogLength(const Context *context)
538 {
539     resolveCompile(context);
540     if (mInfoLog.empty())
541     {
542         return 0;
543     }
544 
545     return (static_cast<int>(mInfoLog.length()) + 1);
546 }
547 
getInfoLog(const Context * context,GLsizei bufSize,GLsizei * length,char * infoLog)548 void Shader::getInfoLog(const Context *context, GLsizei bufSize, GLsizei *length, char *infoLog)
549 {
550     resolveCompile(context);
551 
552     int index = 0;
553 
554     if (bufSize > 0)
555     {
556         index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length()));
557         memcpy(infoLog, mInfoLog.c_str(), index);
558 
559         infoLog[index] = '\0';
560     }
561 
562     if (length)
563     {
564         *length = index;
565     }
566 }
567 
getSourceLength() const568 int Shader::getSourceLength() const
569 {
570     return mState.mSource.empty() ? 0 : (static_cast<int>(mState.mSource.length()) + 1);
571 }
572 
getTranslatedSourceLength(const Context * context)573 int Shader::getTranslatedSourceLength(const Context *context)
574 {
575     resolveCompile(context);
576 
577     if (mState.mCompiledState->translatedSource.empty())
578     {
579         return 0;
580     }
581 
582     return static_cast<int>(mState.mCompiledState->translatedSource.length()) + 1;
583 }
584 
getTranslatedSourceWithDebugInfoLength(const Context * context)585 int Shader::getTranslatedSourceWithDebugInfoLength(const Context *context)
586 {
587     resolveCompile(context);
588 
589     const std::string &debugInfo = mImplementation->getDebugInfo();
590     if (debugInfo.empty())
591     {
592         return 0;
593     }
594 
595     return (static_cast<int>(debugInfo.length()) + 1);
596 }
597 
598 // static
GetSourceImpl(const std::string & source,GLsizei bufSize,GLsizei * length,char * buffer)599 void Shader::GetSourceImpl(const std::string &source,
600                            GLsizei bufSize,
601                            GLsizei *length,
602                            char *buffer)
603 {
604     int index = 0;
605 
606     if (bufSize > 0)
607     {
608         index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
609         memcpy(buffer, source.c_str(), index);
610 
611         buffer[index] = '\0';
612     }
613 
614     if (length)
615     {
616         *length = index;
617     }
618 }
619 
getSource(GLsizei bufSize,GLsizei * length,char * buffer) const620 void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
621 {
622     GetSourceImpl(mState.mSource, bufSize, length, buffer);
623 }
624 
getTranslatedSource(const Context * context,GLsizei bufSize,GLsizei * length,char * buffer)625 void Shader::getTranslatedSource(const Context *context,
626                                  GLsizei bufSize,
627                                  GLsizei *length,
628                                  char *buffer)
629 {
630     GetSourceImpl(getTranslatedSource(context), bufSize, length, buffer);
631 }
632 
getTranslatedSource(const Context * context)633 const std::string &Shader::getTranslatedSource(const Context *context)
634 {
635     resolveCompile(context);
636     return mState.mCompiledState->translatedSource;
637 }
638 
getSourceHash() const639 size_t Shader::getSourceHash() const
640 {
641     return mState.mSourceHash;
642 }
643 
getTranslatedSourceWithDebugInfo(const Context * context,GLsizei bufSize,GLsizei * length,char * buffer)644 void Shader::getTranslatedSourceWithDebugInfo(const Context *context,
645                                               GLsizei bufSize,
646                                               GLsizei *length,
647                                               char *buffer)
648 {
649     resolveCompile(context);
650     const std::string &debugInfo = mImplementation->getDebugInfo();
651     GetSourceImpl(debugInfo, bufSize, length, buffer);
652 }
653 
compile(const Context * context,angle::JobResultExpectancy resultExpectancy)654 void Shader::compile(const Context *context, angle::JobResultExpectancy resultExpectancy)
655 {
656     resolveCompile(context);
657 
658     // Create a new compiled shader state.  If any programs are currently linking using this shader,
659     // they would use the old compiled state, and this shader is free to recompile in the meantime.
660     mState.mCompiledState = std::make_shared<CompiledShaderState>(mState.getShaderType());
661 
662     mInfoLog.clear();
663 
664     ShCompileOptions options = {};
665     options.objectCode       = true;
666     options.emulateGLDrawID  = true;
667 
668     // Add default options to WebGL shaders to prevent unexpected behavior during
669     // compilation.
670     if (context->isWebGL())
671     {
672         options.initGLPosition             = true;
673         options.limitCallStackDepth        = true;
674         options.limitExpressionComplexity  = true;
675         options.enforcePackingRestrictions = true;
676         options.initSharedVariables        = true;
677 
678         if (context->getFrontendFeatures().rejectWebglShadersWithUndefinedBehavior.enabled)
679         {
680             options.rejectWebglShadersWithUndefinedBehavior = true;
681         }
682     }
683     else
684     {
685         // Per https://github.com/KhronosGroup/WebGL/pull/3278 gl_BaseVertex/gl_BaseInstance are
686         // removed from WebGL
687         options.emulateGLBaseVertexBaseInstance = true;
688     }
689 
690     if (context->getFrontendFeatures().forceInitShaderVariables.enabled)
691     {
692         options.initOutputVariables           = true;
693         options.initializeUninitializedLocals = true;
694     }
695 
696 #if defined(ANGLE_ENABLE_ASSERTS)
697     options.validateAST = true;
698 #endif
699 
700     // Find a shader in Blob Cache
701     Compiler *compiler = context->getCompiler();
702     setShaderKey(context, options, compiler->getShaderOutputType(),
703                  compiler->getBuiltInResources());
704     ASSERT(!mShaderHash.empty());
705     MemoryShaderCache *shaderCache = context->getMemoryShaderCache();
706     if (shaderCache != nullptr)
707     {
708         egl::CacheGetResult result =
709             shaderCache->getShader(context, this, mShaderHash, resultExpectancy);
710         switch (result)
711         {
712             case egl::CacheGetResult::Success:
713                 return;
714             case egl::CacheGetResult::Rejected:
715                 // Reset the state
716                 mState.mCompiledState =
717                     std::make_shared<CompiledShaderState>(mState.getShaderType());
718                 break;
719             case egl::CacheGetResult::NotFound:
720             default:
721                 break;
722         }
723     }
724 
725     mBoundCompiler.set(context, compiler);
726     ASSERT(mBoundCompiler.get());
727 
728     ShCompilerInstance compilerInstance = mBoundCompiler->getInstance(mState.getShaderType());
729     ShHandle compilerHandle             = compilerInstance.getHandle();
730     ASSERT(compilerHandle);
731 
732     // Cache load failed, fall through normal compiling.
733     mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED;
734 
735     // Ask the backend to prepare the translate task
736     std::shared_ptr<rx::ShaderTranslateTask> translateTask =
737         mImplementation->compile(context, &options);
738 
739     // Prepare the complete compile task
740     const size_t maxComputeWorkGroupInvocations =
741         static_cast<size_t>(context->getCaps().maxComputeWorkGroupInvocations);
742     const size_t maxComputeSharedMemory = context->getCaps().maxComputeSharedMemorySize;
743 
744     std::shared_ptr<CompileTask> compileTask(
745         new CompileTask(context->getFrontendFeatures(), compilerInstance.getHandle(),
746                         compilerInstance.getShaderOutputType(), options, mState.mSource,
747                         mState.mSourceHash, mState.mCompiledState, maxComputeWorkGroupInvocations,
748                         maxComputeSharedMemory, std::move(translateTask)));
749 
750     // The GL backend relies on the driver's internal parallel compilation, and thus does not use a
751     // thread to compile.  A front-end feature selects whether the single-threaded pool must be
752     // used.
753     const angle::JobThreadSafety threadSafety =
754         context->getFrontendFeatures().compileJobIsThreadSafe.enabled
755             ? angle::JobThreadSafety::Safe
756             : angle::JobThreadSafety::Unsafe;
757     std::shared_ptr<angle::WaitableEvent> compileEvent =
758         context->postCompileLinkTask(compileTask, threadSafety, resultExpectancy);
759 
760     mCompileJob                     = std::make_shared<CompileJob>();
761     mCompileJob->shCompilerInstance = std::move(compilerInstance);
762     mCompileJob->compileEvent       = std::make_unique<CompileEvent>(compileTask, compileEvent);
763 }
764 
resolveCompile(const Context * context)765 void Shader::resolveCompile(const Context *context)
766 {
767     if (!mState.compilePending())
768     {
769         return;
770     }
771 
772     ASSERT(mCompileJob.get());
773     mState.mCompileStatus = CompileStatus::IS_RESOLVING;
774 
775     const bool success    = WaitCompileJobUnlocked(mCompileJob);
776     mInfoLog              = std::move(mCompileJob->compileEvent->getInfoLog());
777     mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED;
778 
779     if (mCompileJob->shCompilerInstance.getHandle())
780     {
781         // Only save this shader to the cache if it was a compile from source (not load from binary)
782         if (success)
783         {
784             MemoryShaderCache *shaderCache = context->getMemoryShaderCache();
785             if (shaderCache != nullptr)
786             {
787                 // Save to the shader cache.
788                 if (shaderCache->putShader(context, mShaderHash, this) != angle::Result::Continue)
789                 {
790                     ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
791                                        "Failed to save compiled shader to memory shader cache.");
792                 }
793             }
794         }
795 
796         mBoundCompiler->putInstance(std::move(mCompileJob->shCompilerInstance));
797     }
798     mCompileJob.reset();
799 }
800 
addRef()801 void Shader::addRef()
802 {
803     mRefCount++;
804 }
805 
release(const Context * context)806 void Shader::release(const Context *context)
807 {
808     mRefCount--;
809 
810     if (mRefCount == 0 && mDeleteStatus)
811     {
812         mResourceManager->deleteShader(context, mHandle);
813     }
814 }
815 
getRefCount() const816 unsigned int Shader::getRefCount() const
817 {
818     return mRefCount;
819 }
820 
isFlaggedForDeletion() const821 bool Shader::isFlaggedForDeletion() const
822 {
823     return mDeleteStatus;
824 }
825 
flagForDeletion()826 void Shader::flagForDeletion()
827 {
828     mDeleteStatus = true;
829 }
830 
isCompiled(const Context * context)831 bool Shader::isCompiled(const Context *context)
832 {
833     resolveCompile(context);
834     return mState.mCompileStatus == CompileStatus::COMPILED;
835 }
836 
isCompleted()837 bool Shader::isCompleted()
838 {
839     return !mState.compilePending() || !mCompileJob->compileEvent->isCompiling();
840 }
841 
getCompileJob(SharedCompiledShaderState * compiledStateOut)842 SharedCompileJob Shader::getCompileJob(SharedCompiledShaderState *compiledStateOut)
843 {
844     // mState.mCompiledState is the same as the one in the current compile job, because this call is
845     // made during link which expects to pick up the currently compiled (or pending compilation)
846     // state.
847     *compiledStateOut = mState.mCompiledState;
848 
849     if (mCompileJob)
850     {
851         ASSERT(mState.compilePending());
852         return mCompileJob;
853     }
854 
855     ASSERT(!mState.compilePending());
856     ASSERT(mState.mCompileStatus == CompileStatus::COMPILED ||
857            mState.mCompileStatus == CompileStatus::NOT_COMPILED);
858 
859     return std::make_shared<CompileJobDone>(mState.mCompileStatus == CompileStatus::COMPILED);
860 }
861 
serialize(const Context * context,angle::MemoryBuffer * binaryOut) const862 angle::Result Shader::serialize(const Context *context, angle::MemoryBuffer *binaryOut) const
863 {
864     BinaryOutputStream stream;
865 
866     stream.writeInt(kShaderCacheIdentifier);
867     mState.mCompiledState->serialize(stream);
868 
869     ASSERT(binaryOut);
870     if (!binaryOut->resize(stream.length()))
871     {
872         ANGLE_PERF_WARNING(context->getState().getDebug(), GL_DEBUG_SEVERITY_LOW,
873                            "Failed to allocate enough memory to serialize a shader. (%zu bytes)",
874                            stream.length());
875         return angle::Result::Stop;
876     }
877 
878     memcpy(binaryOut->data(), stream.data(), stream.length());
879 
880     return angle::Result::Continue;
881 }
882 
deserialize(BinaryInputStream & stream)883 bool Shader::deserialize(BinaryInputStream &stream)
884 {
885     mState.mCompiledState->deserialize(stream);
886 
887     if (stream.error())
888     {
889         // Error while deserializing binary stream
890         return false;
891     }
892 
893     // Note: Currently, shader binaries are only supported on backends that don't happen to have any
894     // additional state used at link time.  If other backends implement this functionality, this
895     // function should call into the backend object to deserialize their part.
896 
897     return true;
898 }
899 
loadBinary(const Context * context,const void * binary,GLsizei length,angle::JobResultExpectancy resultExpectancy)900 bool Shader::loadBinary(const Context *context,
901                         const void *binary,
902                         GLsizei length,
903                         angle::JobResultExpectancy resultExpectancy)
904 {
905     return loadBinaryImpl(context, binary, length, resultExpectancy, false);
906 }
907 
loadShaderBinary(const Context * context,const void * binary,GLsizei length,angle::JobResultExpectancy resultExpectancy)908 bool Shader::loadShaderBinary(const Context *context,
909                               const void *binary,
910                               GLsizei length,
911                               angle::JobResultExpectancy resultExpectancy)
912 {
913     return loadBinaryImpl(context, binary, length, resultExpectancy, true);
914 }
915 
loadBinaryImpl(const Context * context,const void * binary,GLsizei length,angle::JobResultExpectancy resultExpectancy,bool generatedWithOfflineCompiler)916 bool Shader::loadBinaryImpl(const Context *context,
917                             const void *binary,
918                             GLsizei length,
919                             angle::JobResultExpectancy resultExpectancy,
920                             bool generatedWithOfflineCompiler)
921 {
922     BinaryInputStream stream(binary, length);
923 
924     mState.mCompiledState = std::make_shared<CompiledShaderState>(mState.getShaderType());
925 
926     // Shader binaries generated with offline compiler have additional fields
927     if (generatedWithOfflineCompiler)
928     {
929         // Load binary from a glShaderBinary call.
930         // Validation layer should have already verified that the shader program version and shader
931         // type match
932         std::vector<uint8_t> commitString(angle::GetANGLEShaderProgramVersionHashSize(), 0);
933         stream.readBytes(commitString.data(), commitString.size());
934         ASSERT(memcmp(commitString.data(), angle::GetANGLEShaderProgramVersion(),
935                       commitString.size()) == 0);
936 
937         gl::ShaderType shaderType;
938         stream.readEnum(&shaderType);
939         ASSERT(mState.getShaderType() == shaderType);
940 
941         // Get fields needed to generate the key for memory caches.
942         ShShaderOutput outputType;
943         stream.readEnum<ShShaderOutput>(&outputType);
944 
945         // Get the shader's source string.
946         mState.mSource = stream.readString();
947 
948         // In the absence of element-by-element serialize/deserialize functions, read
949         // ShCompileOptions and ShBuiltInResources as raw binary blobs.
950         ShCompileOptions compileOptions;
951         stream.readBytes(reinterpret_cast<uint8_t *>(&compileOptions), sizeof(ShCompileOptions));
952 
953         ShBuiltInResources resources;
954         stream.readBytes(reinterpret_cast<uint8_t *>(&resources), sizeof(ShBuiltInResources));
955 
956         setShaderKey(context, compileOptions, outputType, resources);
957     }
958     else
959     {
960         // Load binary from shader cache.
961         if (stream.readInt<uint32_t>() != kShaderCacheIdentifier)
962         {
963             return false;
964         }
965     }
966 
967     if (!deserialize(stream))
968     {
969         return false;
970     }
971 
972     mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED;
973 
974     // Ask the backend to prepare the translate task
975     std::shared_ptr<rx::ShaderTranslateTask> translateTask =
976         mImplementation->load(context, &stream);
977 
978     std::shared_ptr<CompileTask> compileTask(new CompileTask(
979         context->getFrontendFeatures(), mState.mCompiledState, std::move(translateTask)));
980 
981     const angle::JobThreadSafety threadSafety = GetTranslateTaskThreadSafety(context);
982     std::shared_ptr<angle::WaitableEvent> compileEvent =
983         context->postCompileLinkTask(compileTask, threadSafety, resultExpectancy);
984 
985     mCompileJob               = std::make_shared<CompileJob>();
986     mCompileJob->compileEvent = std::make_unique<CompileEvent>(compileTask, compileEvent);
987 
988     return true;
989 }
990 
setShaderKey(const Context * context,const ShCompileOptions & compileOptions,const ShShaderOutput & outputType,const ShBuiltInResources & resources)991 void Shader::setShaderKey(const Context *context,
992                           const ShCompileOptions &compileOptions,
993                           const ShShaderOutput &outputType,
994                           const ShBuiltInResources &resources)
995 {
996     // Compute shader key.
997     angle::base::SecureHashAlgorithm hasher;
998     hasher.Init();
999 
1000     // Start with the shader type and source.
1001     AppendHashValue(hasher, mState.getShaderType());
1002     hasher.Update(mState.getSource().c_str(), mState.getSource().length());
1003 
1004     // Include the shader program version hash.
1005     hasher.Update(angle::GetANGLEShaderProgramVersion(),
1006                   angle::GetANGLEShaderProgramVersionHashSize());
1007 
1008     AppendHashValue(hasher, Compiler::SelectShaderSpec(context->getState()));
1009     AppendHashValue(hasher, outputType);
1010     hasher.Update(reinterpret_cast<const uint8_t *>(&compileOptions), sizeof(compileOptions));
1011 
1012     // Include the ShBuiltInResources, which represent the extensions and constants used by the
1013     // shader.
1014     hasher.Update(reinterpret_cast<const uint8_t *>(&resources), sizeof(resources));
1015 
1016     // Call the secure SHA hashing function.
1017     hasher.Final();
1018     memcpy(mShaderHash.data(), hasher.Digest(), angle::base::kSHA1Length);
1019 }
1020 
WaitCompileJobUnlocked(const SharedCompileJob & compileJob)1021 bool WaitCompileJobUnlocked(const SharedCompileJob &compileJob)
1022 {
1023     // Simply wait for the job and return whether it succeeded.  Do nothing more as this can be
1024     // called from multiple threads.  Caching of the shader results and compiler clean up will be
1025     // done in resolveCompile() when the main thread happens to call it.
1026     return compileJob->wait();
1027 }
1028 }  // namespace gl
1029