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