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