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