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