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/utilities.h"
18 #include "libANGLE/Caps.h"
19 #include "libANGLE/Compiler.h"
20 #include "libANGLE/Constants.h"
21 #include "libANGLE/Context.h"
22 #include "libANGLE/ResourceManager.h"
23 #include "libANGLE/renderer/GLImplFactory.h"
24 #include "libANGLE/renderer/ShaderImpl.h"
25 #include "platform/FrontendFeatures.h"
26
27 namespace gl
28 {
29
30 namespace
31 {
32 template <typename VarT>
GetActiveShaderVariables(const std::vector<VarT> * variableList)33 std::vector<VarT> GetActiveShaderVariables(const std::vector<VarT> *variableList)
34 {
35 ASSERT(variableList);
36 std::vector<VarT> result;
37 for (size_t varIndex = 0; varIndex < variableList->size(); varIndex++)
38 {
39 const VarT &var = variableList->at(varIndex);
40 if (var.active)
41 {
42 result.push_back(var);
43 }
44 }
45 return result;
46 }
47
48 template <typename VarT>
GetShaderVariables(const std::vector<VarT> * variableList)49 const std::vector<VarT> &GetShaderVariables(const std::vector<VarT> *variableList)
50 {
51 ASSERT(variableList);
52 return *variableList;
53 }
54
55 } // anonymous namespace
56
57 // true if varying x has a higher priority in packing than y
CompareShaderVar(const sh::ShaderVariable & x,const sh::ShaderVariable & y)58 bool CompareShaderVar(const sh::ShaderVariable &x, const sh::ShaderVariable &y)
59 {
60 if (x.type == y.type)
61 {
62 return x.getArraySizeProduct() > y.getArraySizeProduct();
63 }
64
65 // Special case for handling structs: we sort these to the end of the list
66 if (x.type == GL_NONE)
67 {
68 return false;
69 }
70
71 if (y.type == GL_NONE)
72 {
73 return true;
74 }
75
76 return gl::VariableSortOrder(x.type) < gl::VariableSortOrder(y.type);
77 }
78
GetShaderTypeString(ShaderType type)79 const char *GetShaderTypeString(ShaderType type)
80 {
81 switch (type)
82 {
83 case ShaderType::Vertex:
84 return "VERTEX";
85
86 case ShaderType::Fragment:
87 return "FRAGMENT";
88
89 case ShaderType::Compute:
90 return "COMPUTE";
91
92 case ShaderType::Geometry:
93 return "GEOMETRY";
94
95 default:
96 UNREACHABLE();
97 return "";
98 }
99 }
100
101 class ScopedExit final : angle::NonCopyable
102 {
103 public:
ScopedExit(std::function<void ()> exit)104 ScopedExit(std::function<void()> exit) : mExit(exit) {}
~ScopedExit()105 ~ScopedExit() { mExit(); }
106
107 private:
108 std::function<void()> mExit;
109 };
110
111 struct Shader::CompilingState
112 {
113 std::shared_ptr<rx::WaitableCompileEvent> compileEvent;
114 ShCompilerInstance shCompilerInstance;
115 };
116
ShaderState(ShaderType shaderType)117 ShaderState::ShaderState(ShaderType shaderType)
118 : mLabel(),
119 mShaderType(shaderType),
120 mShaderVersion(100),
121 mNumViews(-1),
122 mGeometryShaderInvocations(1),
123 mCompileStatus(CompileStatus::NOT_COMPILED)
124 {
125 mLocalSize.fill(-1);
126 }
127
~ShaderState()128 ShaderState::~ShaderState() {}
129
Shader(ShaderProgramManager * manager,rx::GLImplFactory * implFactory,const gl::Limitations & rendererLimitations,ShaderType type,GLuint handle)130 Shader::Shader(ShaderProgramManager *manager,
131 rx::GLImplFactory *implFactory,
132 const gl::Limitations &rendererLimitations,
133 ShaderType type,
134 GLuint handle)
135 : mState(type),
136 mImplementation(implFactory->createShader(mState)),
137 mRendererLimitations(rendererLimitations),
138 mHandle(handle),
139 mType(type),
140 mRefCount(0),
141 mDeleteStatus(false),
142 mResourceManager(manager),
143 mCurrentMaxComputeWorkGroupInvocations(0u)
144 {
145 ASSERT(mImplementation);
146 }
147
onDestroy(const gl::Context * context)148 void Shader::onDestroy(const gl::Context *context)
149 {
150 resolveCompile();
151 mImplementation->destroy();
152 mBoundCompiler.set(context, nullptr);
153 mImplementation.reset(nullptr);
154 delete this;
155 }
156
~Shader()157 Shader::~Shader()
158 {
159 ASSERT(!mImplementation);
160 }
161
setLabel(const Context * context,const std::string & label)162 void Shader::setLabel(const Context *context, const std::string &label)
163 {
164 mState.mLabel = label;
165 }
166
getLabel() const167 const std::string &Shader::getLabel() const
168 {
169 return mState.mLabel;
170 }
171
getHandle() const172 GLuint Shader::getHandle() const
173 {
174 return mHandle;
175 }
176
setSource(GLsizei count,const char * const * string,const GLint * length)177 void Shader::setSource(GLsizei count, const char *const *string, const GLint *length)
178 {
179 std::ostringstream stream;
180
181 for (int i = 0; i < count; i++)
182 {
183 if (length == nullptr || length[i] < 0)
184 {
185 stream.write(string[i], strlen(string[i]));
186 }
187 else
188 {
189 stream.write(string[i], length[i]);
190 }
191 }
192
193 mState.mSource = stream.str();
194 }
195
getInfoLogLength()196 int Shader::getInfoLogLength()
197 {
198 resolveCompile();
199 if (mInfoLog.empty())
200 {
201 return 0;
202 }
203
204 return (static_cast<int>(mInfoLog.length()) + 1);
205 }
206
getInfoLog(GLsizei bufSize,GLsizei * length,char * infoLog)207 void Shader::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
208 {
209 resolveCompile();
210
211 int index = 0;
212
213 if (bufSize > 0)
214 {
215 index = std::min(bufSize - 1, static_cast<GLsizei>(mInfoLog.length()));
216 memcpy(infoLog, mInfoLog.c_str(), index);
217
218 infoLog[index] = '\0';
219 }
220
221 if (length)
222 {
223 *length = index;
224 }
225 }
226
getSourceLength() const227 int Shader::getSourceLength() const
228 {
229 return mState.mSource.empty() ? 0 : (static_cast<int>(mState.mSource.length()) + 1);
230 }
231
getTranslatedSourceLength()232 int Shader::getTranslatedSourceLength()
233 {
234 resolveCompile();
235
236 if (mState.mTranslatedSource.empty())
237 {
238 return 0;
239 }
240
241 return (static_cast<int>(mState.mTranslatedSource.length()) + 1);
242 }
243
getTranslatedSourceWithDebugInfoLength()244 int Shader::getTranslatedSourceWithDebugInfoLength()
245 {
246 resolveCompile();
247
248 const std::string &debugInfo = mImplementation->getDebugInfo();
249 if (debugInfo.empty())
250 {
251 return 0;
252 }
253
254 return (static_cast<int>(debugInfo.length()) + 1);
255 }
256
257 // static
GetSourceImpl(const std::string & source,GLsizei bufSize,GLsizei * length,char * buffer)258 void Shader::GetSourceImpl(const std::string &source,
259 GLsizei bufSize,
260 GLsizei *length,
261 char *buffer)
262 {
263 int index = 0;
264
265 if (bufSize > 0)
266 {
267 index = std::min(bufSize - 1, static_cast<GLsizei>(source.length()));
268 memcpy(buffer, source.c_str(), index);
269
270 buffer[index] = '\0';
271 }
272
273 if (length)
274 {
275 *length = index;
276 }
277 }
278
getSource(GLsizei bufSize,GLsizei * length,char * buffer) const279 void Shader::getSource(GLsizei bufSize, GLsizei *length, char *buffer) const
280 {
281 GetSourceImpl(mState.mSource, bufSize, length, buffer);
282 }
283
getTranslatedSource(GLsizei bufSize,GLsizei * length,char * buffer)284 void Shader::getTranslatedSource(GLsizei bufSize, GLsizei *length, char *buffer)
285 {
286 GetSourceImpl(getTranslatedSource(), bufSize, length, buffer);
287 }
288
getTranslatedSource()289 const std::string &Shader::getTranslatedSource()
290 {
291 resolveCompile();
292 return mState.mTranslatedSource;
293 }
294
getTranslatedSourceWithDebugInfo(GLsizei bufSize,GLsizei * length,char * buffer)295 void Shader::getTranslatedSourceWithDebugInfo(GLsizei bufSize, GLsizei *length, char *buffer)
296 {
297 resolveCompile();
298 const std::string &debugInfo = mImplementation->getDebugInfo();
299 GetSourceImpl(debugInfo, bufSize, length, buffer);
300 }
301
compile(const Context * context)302 void Shader::compile(const Context *context)
303 {
304 resolveCompile();
305
306 mState.mTranslatedSource.clear();
307 mInfoLog.clear();
308 mState.mShaderVersion = 100;
309 mState.mInputVaryings.clear();
310 mState.mOutputVaryings.clear();
311 mState.mUniforms.clear();
312 mState.mUniformBlocks.clear();
313 mState.mShaderStorageBlocks.clear();
314 mState.mActiveAttributes.clear();
315 mState.mActiveOutputVariables.clear();
316 mState.mNumViews = -1;
317 mState.mGeometryShaderInputPrimitiveType.reset();
318 mState.mGeometryShaderOutputPrimitiveType.reset();
319 mState.mGeometryShaderMaxVertices.reset();
320 mState.mGeometryShaderInvocations = 1;
321
322 mState.mCompileStatus = CompileStatus::COMPILE_REQUESTED;
323 mBoundCompiler.set(context, context->getCompiler());
324
325 ShCompileOptions options = (SH_OBJECT_CODE | SH_VARIABLES | SH_EMULATE_GL_DRAW_ID);
326
327 // Add default options to WebGL shaders to prevent unexpected behavior during
328 // compilation.
329 if (context->getExtensions().webglCompatibility)
330 {
331 options |= SH_INIT_GL_POSITION;
332 options |= SH_LIMIT_CALL_STACK_DEPTH;
333 options |= SH_LIMIT_EXPRESSION_COMPLEXITY;
334 options |= SH_ENFORCE_PACKING_RESTRICTIONS;
335 options |= SH_INIT_SHARED_VARIABLES;
336 }
337
338 // Some targets (eg D3D11 Feature Level 9_3 and below) do not support non-constant loop
339 // indexes in fragment shaders. Shader compilation will fail. To provide a better error
340 // message we can instruct the compiler to pre-validate.
341 if (mRendererLimitations.shadersRequireIndexedLoopValidation)
342 {
343 options |= SH_VALIDATE_LOOP_INDEXING;
344 }
345
346 if (context->getFrontendFeatures().scalarizeVecAndMatConstructorArgs.enabled)
347 {
348 options |= SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS;
349 }
350
351 mCurrentMaxComputeWorkGroupInvocations = context->getCaps().maxComputeWorkGroupInvocations;
352
353 ASSERT(mBoundCompiler.get());
354 ShCompilerInstance compilerInstance = mBoundCompiler->getInstance(mState.mShaderType);
355 ShHandle compilerHandle = compilerInstance.getHandle();
356 ASSERT(compilerHandle);
357 mCompilerResourcesString = compilerInstance.getBuiltinResourcesString();
358
359 mCompilingState.reset(new CompilingState());
360 mCompilingState->shCompilerInstance = std::move(compilerInstance);
361 mCompilingState->compileEvent =
362 mImplementation->compile(context, &(mCompilingState->shCompilerInstance), options);
363 }
364
resolveCompile()365 void Shader::resolveCompile()
366 {
367 if (!mState.compilePending())
368 {
369 return;
370 }
371
372 ASSERT(mCompilingState.get());
373
374 mCompilingState->compileEvent->wait();
375
376 mInfoLog += mCompilingState->compileEvent->getInfoLog();
377
378 ScopedExit exit([this]() {
379 mBoundCompiler->putInstance(std::move(mCompilingState->shCompilerInstance));
380 mCompilingState->compileEvent.reset();
381 mCompilingState.reset();
382 });
383
384 ShHandle compilerHandle = mCompilingState->shCompilerInstance.getHandle();
385 if (!mCompilingState->compileEvent->getResult())
386 {
387 mInfoLog += sh::GetInfoLog(compilerHandle);
388 WARN() << std::endl << mInfoLog;
389 mState.mCompileStatus = CompileStatus::NOT_COMPILED;
390 return;
391 }
392
393 mState.mTranslatedSource = sh::GetObjectCode(compilerHandle);
394
395 #if !defined(NDEBUG)
396 // Prefix translated shader with commented out un-translated shader.
397 // Useful in diagnostics tools which capture the shader source.
398 std::ostringstream shaderStream;
399 shaderStream << "// GLSL\n";
400 shaderStream << "//\n";
401
402 std::istringstream inputSourceStream(mState.mSource);
403 std::string line;
404 while (std::getline(inputSourceStream, line))
405 {
406 // Remove null characters from the source line
407 line.erase(std::remove(line.begin(), line.end(), '\0'), line.end());
408
409 shaderStream << "// " << line << std::endl;
410 }
411 shaderStream << "\n\n";
412 shaderStream << mState.mTranslatedSource;
413 mState.mTranslatedSource = shaderStream.str();
414 #endif // !defined(NDEBUG)
415
416 // Gather the shader information
417 mState.mShaderVersion = sh::GetShaderVersion(compilerHandle);
418
419 mState.mUniforms = GetShaderVariables(sh::GetUniforms(compilerHandle));
420 mState.mUniformBlocks = GetShaderVariables(sh::GetUniformBlocks(compilerHandle));
421 mState.mShaderStorageBlocks = GetShaderVariables(sh::GetShaderStorageBlocks(compilerHandle));
422
423 switch (mState.mShaderType)
424 {
425 case ShaderType::Compute:
426 {
427 mState.mLocalSize = sh::GetComputeShaderLocalGroupSize(compilerHandle);
428 if (mState.mLocalSize.isDeclared())
429 {
430 angle::CheckedNumeric<uint32_t> checked_local_size_product(mState.mLocalSize[0]);
431 checked_local_size_product *= mState.mLocalSize[1];
432 checked_local_size_product *= mState.mLocalSize[2];
433
434 if (!checked_local_size_product.IsValid())
435 {
436 WARN() << std::endl
437 << "Integer overflow when computing the product of local_size_x, "
438 << "local_size_y and local_size_z.";
439 mState.mCompileStatus = CompileStatus::NOT_COMPILED;
440 return;
441 }
442 if (checked_local_size_product.ValueOrDie() >
443 mCurrentMaxComputeWorkGroupInvocations)
444 {
445 WARN() << std::endl
446 << "The total number of invocations within a work group exceeds "
447 << "MAX_COMPUTE_WORK_GROUP_INVOCATIONS.";
448 mState.mCompileStatus = CompileStatus::NOT_COMPILED;
449 return;
450 }
451 }
452 break;
453 }
454 case ShaderType::Vertex:
455 {
456 {
457 mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle));
458 mState.mAllAttributes = GetShaderVariables(sh::GetAttributes(compilerHandle));
459 mState.mActiveAttributes = GetActiveShaderVariables(&mState.mAllAttributes);
460 mState.mNumViews = sh::GetVertexShaderNumViews(compilerHandle);
461 }
462 break;
463 }
464 case ShaderType::Fragment:
465 {
466 mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle));
467 // TODO(jmadill): Figure out why we only sort in the FS, and if we need to.
468 std::sort(mState.mInputVaryings.begin(), mState.mInputVaryings.end(), CompareShaderVar);
469 mState.mActiveOutputVariables =
470 GetActiveShaderVariables(sh::GetOutputVariables(compilerHandle));
471 break;
472 }
473 case ShaderType::Geometry:
474 {
475 mState.mInputVaryings = GetShaderVariables(sh::GetInputVaryings(compilerHandle));
476 mState.mOutputVaryings = GetShaderVariables(sh::GetOutputVaryings(compilerHandle));
477
478 if (sh::HasValidGeometryShaderInputPrimitiveType(compilerHandle))
479 {
480 mState.mGeometryShaderInputPrimitiveType = FromGLenum<PrimitiveMode>(
481 sh::GetGeometryShaderInputPrimitiveType(compilerHandle));
482 }
483 if (sh::HasValidGeometryShaderOutputPrimitiveType(compilerHandle))
484 {
485 mState.mGeometryShaderOutputPrimitiveType = FromGLenum<PrimitiveMode>(
486 sh::GetGeometryShaderOutputPrimitiveType(compilerHandle));
487 }
488 if (sh::HasValidGeometryShaderMaxVertices(compilerHandle))
489 {
490 mState.mGeometryShaderMaxVertices =
491 sh::GetGeometryShaderMaxVertices(compilerHandle);
492 }
493 mState.mGeometryShaderInvocations = sh::GetGeometryShaderInvocations(compilerHandle);
494 break;
495 }
496 default:
497 UNREACHABLE();
498 }
499
500 ASSERT(!mState.mTranslatedSource.empty());
501
502 bool success = mCompilingState->compileEvent->postTranslate(&mInfoLog);
503 mState.mCompileStatus = success ? CompileStatus::COMPILED : CompileStatus::NOT_COMPILED;
504 }
505
addRef()506 void Shader::addRef()
507 {
508 mRefCount++;
509 }
510
release(const Context * context)511 void Shader::release(const Context *context)
512 {
513 mRefCount--;
514
515 if (mRefCount == 0 && mDeleteStatus)
516 {
517 mResourceManager->deleteShader(context, mHandle);
518 }
519 }
520
getRefCount() const521 unsigned int Shader::getRefCount() const
522 {
523 return mRefCount;
524 }
525
isFlaggedForDeletion() const526 bool Shader::isFlaggedForDeletion() const
527 {
528 return mDeleteStatus;
529 }
530
flagForDeletion()531 void Shader::flagForDeletion()
532 {
533 mDeleteStatus = true;
534 }
535
isCompiled()536 bool Shader::isCompiled()
537 {
538 resolveCompile();
539 return mState.mCompileStatus == CompileStatus::COMPILED;
540 }
541
isCompleted()542 bool Shader::isCompleted()
543 {
544 return (!mState.compilePending() || mCompilingState->compileEvent->isReady());
545 }
546
getShaderVersion()547 int Shader::getShaderVersion()
548 {
549 resolveCompile();
550 return mState.mShaderVersion;
551 }
552
getInputVaryings()553 const std::vector<sh::Varying> &Shader::getInputVaryings()
554 {
555 resolveCompile();
556 return mState.getInputVaryings();
557 }
558
getOutputVaryings()559 const std::vector<sh::Varying> &Shader::getOutputVaryings()
560 {
561 resolveCompile();
562 return mState.getOutputVaryings();
563 }
564
getUniforms()565 const std::vector<sh::Uniform> &Shader::getUniforms()
566 {
567 resolveCompile();
568 return mState.getUniforms();
569 }
570
getUniformBlocks()571 const std::vector<sh::InterfaceBlock> &Shader::getUniformBlocks()
572 {
573 resolveCompile();
574 return mState.getUniformBlocks();
575 }
576
getShaderStorageBlocks()577 const std::vector<sh::InterfaceBlock> &Shader::getShaderStorageBlocks()
578 {
579 resolveCompile();
580 return mState.getShaderStorageBlocks();
581 }
582
getActiveAttributes()583 const std::vector<sh::Attribute> &Shader::getActiveAttributes()
584 {
585 resolveCompile();
586 return mState.getActiveAttributes();
587 }
588
getAllAttributes()589 const std::vector<sh::Attribute> &Shader::getAllAttributes()
590 {
591 resolveCompile();
592 return mState.getAllAttributes();
593 }
594
getActiveOutputVariables()595 const std::vector<sh::OutputVariable> &Shader::getActiveOutputVariables()
596 {
597 resolveCompile();
598 return mState.getActiveOutputVariables();
599 }
600
getTransformFeedbackVaryingMappedName(const std::string & tfVaryingName)601 std::string Shader::getTransformFeedbackVaryingMappedName(const std::string &tfVaryingName)
602 {
603 // TODO(jiawei.shao@intel.com): support transform feedback on geometry shader.
604 ASSERT(mState.getShaderType() == ShaderType::Vertex);
605 const auto &varyings = getOutputVaryings();
606 auto bracketPos = tfVaryingName.find("[");
607 if (bracketPos != std::string::npos)
608 {
609 auto tfVaryingBaseName = tfVaryingName.substr(0, bracketPos);
610 for (const auto &varying : varyings)
611 {
612 if (varying.name == tfVaryingBaseName)
613 {
614 std::string mappedNameWithArrayIndex =
615 varying.mappedName + tfVaryingName.substr(bracketPos);
616 return mappedNameWithArrayIndex;
617 }
618 }
619 }
620 else
621 {
622 for (const auto &varying : varyings)
623 {
624 if (varying.name == tfVaryingName)
625 {
626 return varying.mappedName;
627 }
628 else if (varying.isStruct())
629 {
630 GLuint fieldIndex = 0;
631 const auto *field = FindShaderVarField(varying, tfVaryingName, &fieldIndex);
632 ASSERT(field != nullptr && !field->isStruct() && !field->isArray());
633 return varying.mappedName + "." + field->mappedName;
634 }
635 }
636 }
637 UNREACHABLE();
638 return std::string();
639 }
640
getWorkGroupSize()641 const sh::WorkGroupSize &Shader::getWorkGroupSize()
642 {
643 resolveCompile();
644 return mState.mLocalSize;
645 }
646
getNumViews()647 int Shader::getNumViews()
648 {
649 resolveCompile();
650 return mState.mNumViews;
651 }
652
getGeometryShaderInputPrimitiveType()653 Optional<PrimitiveMode> Shader::getGeometryShaderInputPrimitiveType()
654 {
655 resolveCompile();
656 return mState.mGeometryShaderInputPrimitiveType;
657 }
658
getGeometryShaderOutputPrimitiveType()659 Optional<PrimitiveMode> Shader::getGeometryShaderOutputPrimitiveType()
660 {
661 resolveCompile();
662 return mState.mGeometryShaderOutputPrimitiveType;
663 }
664
getGeometryShaderInvocations()665 int Shader::getGeometryShaderInvocations()
666 {
667 resolveCompile();
668 return mState.mGeometryShaderInvocations;
669 }
670
getGeometryShaderMaxVertices()671 Optional<GLint> Shader::getGeometryShaderMaxVertices()
672 {
673 resolveCompile();
674 return mState.mGeometryShaderMaxVertices;
675 }
676
getCompilerResourcesString() const677 const std::string &Shader::getCompilerResourcesString() const
678 {
679 return mCompilerResourcesString;
680 }
681
682 } // namespace gl
683