• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2017 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 // ProgramLinkedResources.cpp: implements link-time checks for default block uniforms, and generates
8 // uniform locations. Populates data structures related to uniforms so that they can be stored in
9 // program state.
10 
11 #include "libANGLE/ProgramLinkedResources.h"
12 
13 #include "common/string_utils.h"
14 #include "common/utilities.h"
15 #include "libANGLE/Caps.h"
16 #include "libANGLE/Context.h"
17 #include "libANGLE/Shader.h"
18 #include "libANGLE/features.h"
19 
20 namespace gl
21 {
22 namespace
23 {
FindUniform(std::vector<LinkedUniform> & list,const std::string & name)24 LinkedUniform *FindUniform(std::vector<LinkedUniform> &list, const std::string &name)
25 {
26     for (LinkedUniform &uniform : list)
27     {
28         if (uniform.name == name)
29             return &uniform;
30     }
31 
32     return nullptr;
33 }
34 
35 template <typename VarT>
SetActive(std::vector<VarT> * list,const std::string & name,ShaderType shaderType,bool active)36 void SetActive(std::vector<VarT> *list, const std::string &name, ShaderType shaderType, bool active)
37 {
38     for (auto &variable : *list)
39     {
40         if (variable.name == name)
41         {
42             variable.setActive(shaderType, active);
43             return;
44         }
45     }
46 }
47 
48 // GLSL ES Spec 3.00.3, section 4.3.5.
LinkValidateUniforms(const sh::Uniform & uniform1,const sh::Uniform & uniform2,std::string * mismatchedStructFieldName)49 LinkMismatchError LinkValidateUniforms(const sh::Uniform &uniform1,
50                                        const sh::Uniform &uniform2,
51                                        std::string *mismatchedStructFieldName)
52 {
53 #if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION == ANGLE_ENABLED
54     const bool validatePrecision = true;
55 #else
56     const bool validatePrecision = false;
57 #endif
58 
59     LinkMismatchError linkError = Program::LinkValidateVariablesBase(
60         uniform1, uniform2, validatePrecision, true, mismatchedStructFieldName);
61     if (linkError != LinkMismatchError::NO_MISMATCH)
62     {
63         return linkError;
64     }
65 
66     // GLSL ES Spec 3.10.4, section 4.4.5.
67     if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
68     {
69         return LinkMismatchError::BINDING_MISMATCH;
70     }
71 
72     // GLSL ES Spec 3.10.4, section 9.2.1.
73     if (uniform1.location != -1 && uniform2.location != -1 &&
74         uniform1.location != uniform2.location)
75     {
76         return LinkMismatchError::LOCATION_MISMATCH;
77     }
78     if (uniform1.offset != uniform2.offset)
79     {
80         return LinkMismatchError::OFFSET_MISMATCH;
81     }
82 
83     return LinkMismatchError::NO_MISMATCH;
84 }
85 
86 using ShaderUniform = std::pair<ShaderType, const sh::Uniform *>;
87 
ValidateGraphicsUniformsPerShader(Shader * shaderToLink,bool extendLinkedUniforms,std::map<std::string,ShaderUniform> * linkedUniforms,InfoLog & infoLog)88 bool ValidateGraphicsUniformsPerShader(Shader *shaderToLink,
89                                        bool extendLinkedUniforms,
90                                        std::map<std::string, ShaderUniform> *linkedUniforms,
91                                        InfoLog &infoLog)
92 {
93     ASSERT(shaderToLink && linkedUniforms);
94 
95     for (const sh::Uniform &uniform : shaderToLink->getUniforms())
96     {
97         const auto &entry = linkedUniforms->find(uniform.name);
98         if (entry != linkedUniforms->end())
99         {
100             const sh::Uniform &linkedUniform = *(entry->second.second);
101             std::string mismatchedStructFieldName;
102             LinkMismatchError linkError =
103                 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
104             if (linkError != LinkMismatchError::NO_MISMATCH)
105             {
106                 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
107                                 mismatchedStructFieldName, entry->second.first,
108                                 shaderToLink->getType());
109                 return false;
110             }
111         }
112         else if (extendLinkedUniforms)
113         {
114             (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink->getType(), &uniform);
115         }
116     }
117 
118     return true;
119 }
120 
GetMaximumShaderUniformVectors(ShaderType shaderType,const Caps & caps)121 GLuint GetMaximumShaderUniformVectors(ShaderType shaderType, const Caps &caps)
122 {
123     switch (shaderType)
124     {
125         case ShaderType::Vertex:
126             return caps.maxVertexUniformVectors;
127         case ShaderType::Fragment:
128             return caps.maxFragmentUniformVectors;
129 
130         case ShaderType::Compute:
131         case ShaderType::Geometry:
132             return caps.maxShaderUniformComponents[shaderType] / 4;
133 
134         default:
135             UNREACHABLE();
136             return 0u;
137     }
138 }
139 
140 enum class UniformType : uint8_t
141 {
142     Variable      = 0,
143     Sampler       = 1,
144     Image         = 2,
145     AtomicCounter = 3,
146 
147     InvalidEnum = 4,
148     EnumCount   = 4,
149 };
150 
GetUniformResourceNameString(UniformType uniformType)151 const char *GetUniformResourceNameString(UniformType uniformType)
152 {
153     switch (uniformType)
154     {
155         case UniformType::Variable:
156             return "uniform";
157         case UniformType::Sampler:
158             return "texture image unit";
159         case UniformType::Image:
160             return "image uniform";
161         case UniformType::AtomicCounter:
162             return "atomic counter";
163         default:
164             UNREACHABLE();
165             return "";
166     }
167 }
168 
GetUniformResourceLimitName(ShaderType shaderType,UniformType uniformType)169 std::string GetUniformResourceLimitName(ShaderType shaderType, UniformType uniformType)
170 {
171     // Special case: MAX_TEXTURE_IMAGE_UNITS (no "MAX_FRAGMENT_TEXTURE_IMAGE_UNITS")
172     if (shaderType == ShaderType::Fragment && uniformType == UniformType::Sampler)
173     {
174         return "MAX_TEXTURE_IMAGE_UNITS";
175     }
176 
177     std::ostringstream ostream;
178     ostream << "MAX_" << GetShaderTypeString(shaderType) << "_";
179 
180     switch (uniformType)
181     {
182         case UniformType::Variable:
183             // For vertex and fragment shaders, ES 2.0 only defines MAX_VERTEX_UNIFORM_VECTORS and
184             // MAX_FRAGMENT_UNIFORM_VECTORS ([OpenGL ES 2.0] Table 6.20).
185             if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
186             {
187                 ostream << "UNIFORM_VECTORS";
188                 break;
189             }
190             // For compute and geometry shaders, there are no definitions on
191             // "MAX_COMPUTE_UNIFORM_VECTORS" or "MAX_GEOMETRY_UNIFORM_VECTORS_EXT"
192             // ([OpenGL ES 3.1] Table 20.45, [EXT_geometry_shader] Table 20.43gs).
193             else
194             {
195                 ostream << "UNIFORM_COMPONENTS";
196             }
197             break;
198         case UniformType::Sampler:
199             ostream << "TEXTURE_IMAGE_UNITS";
200             break;
201         case UniformType::Image:
202             ostream << "IMAGE_UNIFORMS";
203             break;
204         case UniformType::AtomicCounter:
205             ostream << "ATOMIC_COUNTERS";
206             break;
207         default:
208             UNREACHABLE();
209             return "";
210     }
211 
212     if (shaderType == ShaderType::Geometry)
213     {
214         ostream << "_EXT";
215     }
216 
217     return ostream.str();
218 }
219 
LogUniformsExceedLimit(ShaderType shaderType,UniformType uniformType,GLuint limit,InfoLog & infoLog)220 void LogUniformsExceedLimit(ShaderType shaderType,
221                             UniformType uniformType,
222                             GLuint limit,
223                             InfoLog &infoLog)
224 {
225     infoLog << GetShaderTypeString(shaderType) << " shader "
226             << GetUniformResourceNameString(uniformType) << "s count exceeds "
227             << GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
228 }
229 
230 // The purpose of this visitor is to capture the uniforms in a uniform block. Each new uniform is
231 // added to "uniformsOut".
232 class UniformBlockEncodingVisitor : public sh::VariableNameVisitor
233 {
234   public:
UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<LinkedUniform> * uniformsOut,ShaderType shaderType,int blockIndex)235     UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
236                                 const std::string &namePrefix,
237                                 const std::string &mappedNamePrefix,
238                                 std::vector<LinkedUniform> *uniformsOut,
239                                 ShaderType shaderType,
240                                 int blockIndex)
241         : sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
242           mGetMemberInfo(getMemberInfo),
243           mUniformsOut(uniformsOut),
244           mShaderType(shaderType),
245           mBlockIndex(blockIndex)
246     {}
247 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName)248     void visitNamedVariable(const sh::ShaderVariable &variable,
249                             bool isRowMajor,
250                             const std::string &name,
251                             const std::string &mappedName) override
252     {
253         // If getBlockMemberInfo returns false, the variable is optimized out.
254         sh::BlockMemberInfo variableInfo;
255         if (!mGetMemberInfo(name, mappedName, &variableInfo))
256             return;
257 
258         std::string nameWithArrayIndex       = name;
259         std::string mappedNameWithArrayIndex = mappedName;
260 
261         if (variable.isArray())
262         {
263             nameWithArrayIndex += "[0]";
264             mappedNameWithArrayIndex += "[0]";
265         }
266 
267         if (mBlockIndex == -1)
268         {
269             SetActive(mUniformsOut, nameWithArrayIndex, mShaderType, variable.active);
270             return;
271         }
272 
273         LinkedUniform newUniform(variable.type, variable.precision, nameWithArrayIndex,
274                                  variable.arraySizes, -1, -1, -1, mBlockIndex, variableInfo);
275         newUniform.mappedName = mappedNameWithArrayIndex;
276         newUniform.setActive(mShaderType, variable.active);
277 
278         // Since block uniforms have no location, we don't need to store them in the uniform
279         // locations list.
280         mUniformsOut->push_back(newUniform);
281     }
282 
283   private:
284     const GetBlockMemberInfoFunc &mGetMemberInfo;
285     std::vector<LinkedUniform> *mUniformsOut;
286     const ShaderType mShaderType;
287     const int mBlockIndex;
288 };
289 
290 // The purpose of this visitor is to capture the buffer variables in a shader storage block. Each
291 // new buffer variable is stored in "bufferVariablesOut".
292 class ShaderStorageBlockVisitor : public sh::BlockEncoderVisitor
293 {
294   public:
ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<BufferVariable> * bufferVariablesOut,ShaderType shaderType,int blockIndex)295     ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
296                               const std::string &namePrefix,
297                               const std::string &mappedNamePrefix,
298                               std::vector<BufferVariable> *bufferVariablesOut,
299                               ShaderType shaderType,
300                               int blockIndex)
301         : sh::BlockEncoderVisitor(namePrefix, mappedNamePrefix, &mDummyEncoder),
302           mGetMemberInfo(getMemberInfo),
303           mBufferVariablesOut(bufferVariablesOut),
304           mShaderType(shaderType),
305           mBlockIndex(blockIndex)
306     {}
307 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName)308     void visitNamedVariable(const sh::ShaderVariable &variable,
309                             bool isRowMajor,
310                             const std::string &name,
311                             const std::string &mappedName) override
312     {
313         if (mSkipEnabled)
314             return;
315 
316         // If getBlockMemberInfo returns false, the variable is optimized out.
317         sh::BlockMemberInfo variableInfo;
318         if (!mGetMemberInfo(name, mappedName, &variableInfo))
319             return;
320 
321         std::string nameWithArrayIndex       = name;
322         std::string mappedNameWithArrayIndex = mappedName;
323 
324         if (variable.isArray())
325         {
326             nameWithArrayIndex += "[0]";
327             mappedNameWithArrayIndex += "[0]";
328         }
329 
330         if (mBlockIndex == -1)
331         {
332             SetActive(mBufferVariablesOut, nameWithArrayIndex, mShaderType, variable.active);
333             return;
334         }
335 
336         BufferVariable newBufferVariable(variable.type, variable.precision, nameWithArrayIndex,
337                                          variable.arraySizes, mBlockIndex, variableInfo);
338         newBufferVariable.mappedName = mappedNameWithArrayIndex;
339         newBufferVariable.setActive(mShaderType, variable.active);
340 
341         newBufferVariable.topLevelArraySize = mTopLevelArraySize;
342 
343         mBufferVariablesOut->push_back(newBufferVariable);
344     }
345 
346   private:
347     const GetBlockMemberInfoFunc &mGetMemberInfo;
348     std::vector<BufferVariable> *mBufferVariablesOut;
349     const ShaderType mShaderType;
350     const int mBlockIndex;
351     sh::DummyBlockEncoder mDummyEncoder;
352 };
353 
354 struct ShaderUniformCount
355 {
356     unsigned int vectorCount        = 0;
357     unsigned int samplerCount       = 0;
358     unsigned int imageCount         = 0;
359     unsigned int atomicCounterCount = 0;
360 };
361 
operator +=(ShaderUniformCount & lhs,const ShaderUniformCount & rhs)362 ShaderUniformCount &operator+=(ShaderUniformCount &lhs, const ShaderUniformCount &rhs)
363 {
364     lhs.vectorCount += rhs.vectorCount;
365     lhs.samplerCount += rhs.samplerCount;
366     lhs.imageCount += rhs.imageCount;
367     lhs.atomicCounterCount += rhs.atomicCounterCount;
368     return lhs;
369 }
370 
371 // The purpose of this visitor is to flatten struct and array uniforms into a list of singleton
372 // uniforms. They are stored in separate lists by uniform type so they can be sorted in order.
373 // Counts for each uniform category are stored and can be queried with "getCounts".
374 class FlattenUniformVisitor : public sh::VariableNameVisitor
375 {
376   public:
FlattenUniformVisitor(ShaderType shaderType,const sh::Uniform & uniform,std::vector<LinkedUniform> * uniforms,std::vector<LinkedUniform> * samplerUniforms,std::vector<LinkedUniform> * imageUniforms,std::vector<LinkedUniform> * atomicCounterUniforms,std::vector<UnusedUniform> * unusedUniforms)377     FlattenUniformVisitor(ShaderType shaderType,
378                           const sh::Uniform &uniform,
379                           std::vector<LinkedUniform> *uniforms,
380                           std::vector<LinkedUniform> *samplerUniforms,
381                           std::vector<LinkedUniform> *imageUniforms,
382                           std::vector<LinkedUniform> *atomicCounterUniforms,
383                           std::vector<UnusedUniform> *unusedUniforms)
384         : sh::VariableNameVisitor("", ""),
385           mShaderType(shaderType),
386           mMarkActive(uniform.active),
387           mMarkStaticUse(uniform.staticUse),
388           mBinding(uniform.binding),
389           mOffset(uniform.offset),
390           mLocation(uniform.location),
391           mUniforms(uniforms),
392           mSamplerUniforms(samplerUniforms),
393           mImageUniforms(imageUniforms),
394           mAtomicCounterUniforms(atomicCounterUniforms),
395           mUnusedUniforms(unusedUniforms)
396     {}
397 
visitNamedSampler(const sh::ShaderVariable & sampler,const std::string & name,const std::string & mappedName)398     void visitNamedSampler(const sh::ShaderVariable &sampler,
399                            const std::string &name,
400                            const std::string &mappedName) override
401     {
402         visitNamedVariable(sampler, false, name, mappedName);
403     }
404 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName)405     void visitNamedVariable(const sh::ShaderVariable &variable,
406                             bool isRowMajor,
407                             const std::string &name,
408                             const std::string &mappedName) override
409     {
410         bool isSampler                          = IsSamplerType(variable.type);
411         bool isImage                            = IsImageType(variable.type);
412         bool isAtomicCounter                    = IsAtomicCounterType(variable.type);
413         std::vector<LinkedUniform> *uniformList = mUniforms;
414         if (isSampler)
415         {
416             uniformList = mSamplerUniforms;
417         }
418         else if (isImage)
419         {
420             uniformList = mImageUniforms;
421         }
422         else if (isAtomicCounter)
423         {
424             uniformList = mAtomicCounterUniforms;
425         }
426 
427         std::string fullNameWithArrayIndex(name);
428         std::string fullMappedNameWithArrayIndex(mappedName);
429 
430         if (variable.isArray())
431         {
432             // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
433             // Resources and including [0] at the end of array variable names.
434             fullNameWithArrayIndex += "[0]";
435             fullMappedNameWithArrayIndex += "[0]";
436         }
437 
438         LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
439         if (existingUniform)
440         {
441             if (getBinding() != -1)
442             {
443                 existingUniform->binding = getBinding();
444             }
445             if (getOffset() != -1)
446             {
447                 existingUniform->offset = getOffset();
448             }
449             if (mLocation != -1)
450             {
451                 existingUniform->location = mLocation;
452             }
453             if (mMarkActive)
454             {
455                 existingUniform->active = true;
456                 existingUniform->setActive(mShaderType, true);
457             }
458             if (mMarkStaticUse)
459             {
460                 existingUniform->staticUse = true;
461             }
462         }
463         else
464         {
465             LinkedUniform linkedUniform(variable.type, variable.precision, fullNameWithArrayIndex,
466                                         variable.arraySizes, getBinding(), getOffset(), mLocation,
467                                         -1, sh::kDefaultBlockMemberInfo);
468             linkedUniform.mappedName = fullMappedNameWithArrayIndex;
469             linkedUniform.active     = mMarkActive;
470             linkedUniform.staticUse  = mMarkStaticUse;
471             if (variable.hasParentArrayIndex())
472             {
473                 linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
474             }
475             if (mMarkActive)
476             {
477                 linkedUniform.setActive(mShaderType, true);
478             }
479             else
480             {
481                 mUnusedUniforms->emplace_back(linkedUniform.name, linkedUniform.isSampler());
482             }
483 
484             uniformList->push_back(linkedUniform);
485         }
486 
487         unsigned int elementCount = variable.getBasicTypeElementCount();
488 
489         // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
490         // Likewise, don't count "real" uniforms towards opaque count.
491 
492         if (!IsOpaqueType(variable.type))
493         {
494             mUniformCount.vectorCount += VariableRegisterCount(variable.type) * elementCount;
495         }
496 
497         mUniformCount.samplerCount += (isSampler ? elementCount : 0);
498         mUniformCount.imageCount += (isImage ? elementCount : 0);
499         mUniformCount.atomicCounterCount += (isAtomicCounter ? elementCount : 0);
500 
501         if (mLocation != -1)
502         {
503             mLocation += elementCount;
504         }
505     }
506 
enterStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)507     void enterStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
508     {
509         mStructStackSize++;
510         sh::VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
511     }
512 
exitStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)513     void exitStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
514     {
515         mStructStackSize--;
516         sh::VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
517     }
518 
getCounts() const519     ShaderUniformCount getCounts() const { return mUniformCount; }
520 
521   private:
getBinding() const522     int getBinding() const { return mStructStackSize == 0 ? mBinding : -1; }
getOffset() const523     int getOffset() const { return mStructStackSize == 0 ? mOffset : -1; }
524 
525     ShaderType mShaderType;
526 
527     // Active and StaticUse are given separately because they are tracked at struct granularity.
528     bool mMarkActive;
529     bool mMarkStaticUse;
530     int mBinding;
531     int mOffset;
532     int mLocation;
533     std::vector<LinkedUniform> *mUniforms;
534     std::vector<LinkedUniform> *mSamplerUniforms;
535     std::vector<LinkedUniform> *mImageUniforms;
536     std::vector<LinkedUniform> *mAtomicCounterUniforms;
537     std::vector<UnusedUniform> *mUnusedUniforms;
538     ShaderUniformCount mUniformCount;
539     unsigned int mStructStackSize = 0;
540 };
541 
542 class InterfaceBlockInfo final : angle::NonCopyable
543 {
544   public:
InterfaceBlockInfo(CustomBlockLayoutEncoderFactory * customEncoderFactory)545     InterfaceBlockInfo(CustomBlockLayoutEncoderFactory *customEncoderFactory)
546         : mCustomEncoderFactory(customEncoderFactory)
547     {}
548 
549     void getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks);
550 
551     bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut);
552     bool getBlockMemberInfo(const std::string &name,
553                             const std::string &mappedName,
554                             sh::BlockMemberInfo *infoOut);
555 
556   private:
557     size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock);
558 
559     std::map<std::string, size_t> mBlockSizes;
560     sh::BlockLayoutMap mBlockLayout;
561     // Based on the interface block layout, the std140 or std430 encoders are used.  On some
562     // platforms (currently only D3D), there could be another non-standard encoder used.
563     CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
564 };
565 
getShaderBlockInfo(const std::vector<sh::InterfaceBlock> & interfaceBlocks)566 void InterfaceBlockInfo::getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks)
567 {
568     for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
569     {
570         if (!IsActiveInterfaceBlock(interfaceBlock))
571             continue;
572 
573         if (mBlockSizes.count(interfaceBlock.name) > 0)
574             continue;
575 
576         size_t dataSize                  = getBlockInfo(interfaceBlock);
577         mBlockSizes[interfaceBlock.name] = dataSize;
578     }
579 }
580 
getBlockInfo(const sh::InterfaceBlock & interfaceBlock)581 size_t InterfaceBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock)
582 {
583     ASSERT(IsActiveInterfaceBlock(interfaceBlock));
584 
585     // define member uniforms
586     sh::Std140BlockEncoder std140Encoder;
587     sh::Std430BlockEncoder std430Encoder;
588     sh::BlockLayoutEncoder *customEncoder = nullptr;
589     sh::BlockLayoutEncoder *encoder       = nullptr;
590 
591     if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140)
592     {
593         encoder = &std140Encoder;
594     }
595     else if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD430)
596     {
597         encoder = &std430Encoder;
598     }
599     else if (mCustomEncoderFactory)
600     {
601         encoder = customEncoder = mCustomEncoderFactory->makeEncoder();
602     }
603     else
604     {
605         UNREACHABLE();
606         return 0;
607     }
608 
609     sh::GetInterfaceBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
610                               &mBlockLayout);
611 
612     size_t offset = encoder->getCurrentOffset();
613 
614     SafeDelete(customEncoder);
615 
616     return offset;
617 }
618 
getBlockSize(const std::string & name,const std::string & mappedName,size_t * sizeOut)619 bool InterfaceBlockInfo::getBlockSize(const std::string &name,
620                                       const std::string &mappedName,
621                                       size_t *sizeOut)
622 {
623     size_t nameLengthWithoutArrayIndex;
624     ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
625     std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
626     auto sizeIter        = mBlockSizes.find(baseName);
627     if (sizeIter == mBlockSizes.end())
628     {
629         *sizeOut = 0;
630         return false;
631     }
632 
633     *sizeOut = sizeIter->second;
634     return true;
635 }
636 
getBlockMemberInfo(const std::string & name,const std::string & mappedName,sh::BlockMemberInfo * infoOut)637 bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name,
638                                             const std::string &mappedName,
639                                             sh::BlockMemberInfo *infoOut)
640 {
641     auto infoIter = mBlockLayout.find(name);
642     if (infoIter == mBlockLayout.end())
643     {
644         *infoOut = sh::kDefaultBlockMemberInfo;
645         return false;
646     }
647 
648     *infoOut = infoIter->second;
649     return true;
650 }
651 }  // anonymous namespace
652 
UniformLinker(const ProgramState & state)653 UniformLinker::UniformLinker(const ProgramState &state) : mState(state) {}
654 
655 UniformLinker::~UniformLinker() = default;
656 
getResults(std::vector<LinkedUniform> * uniforms,std::vector<UnusedUniform> * unusedUniforms,std::vector<VariableLocation> * uniformLocations)657 void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
658                                std::vector<UnusedUniform> *unusedUniforms,
659                                std::vector<VariableLocation> *uniformLocations)
660 {
661     uniforms->swap(mUniforms);
662     unusedUniforms->swap(mUnusedUniforms);
663     uniformLocations->swap(mUniformLocations);
664 }
665 
link(const Caps & caps,InfoLog & infoLog,const ProgramBindings & uniformLocationBindings)666 bool UniformLinker::link(const Caps &caps,
667                          InfoLog &infoLog,
668                          const ProgramBindings &uniformLocationBindings)
669 {
670     if (mState.getAttachedShader(ShaderType::Vertex) &&
671         mState.getAttachedShader(ShaderType::Fragment))
672     {
673         ASSERT(mState.getAttachedShader(ShaderType::Compute) == nullptr);
674         if (!validateGraphicsUniforms(infoLog))
675         {
676             return false;
677         }
678     }
679 
680     // Flatten the uniforms list (nested fields) into a simple list (no nesting).
681     // Also check the maximum uniform vector and sampler counts.
682     if (!flattenUniformsAndCheckCaps(caps, infoLog))
683     {
684         return false;
685     }
686 
687     if (!checkMaxCombinedAtomicCounters(caps, infoLog))
688     {
689         return false;
690     }
691 
692     if (!indexUniforms(infoLog, uniformLocationBindings))
693     {
694         return false;
695     }
696 
697     return true;
698 }
699 
validateGraphicsUniforms(InfoLog & infoLog) const700 bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
701 {
702     // Check that uniforms defined in the graphics shaders are identical
703     std::map<std::string, ShaderUniform> linkedUniforms;
704 
705     for (const ShaderType shaderType : kAllGraphicsShaderTypes)
706     {
707         Shader *currentShader = mState.getAttachedShader(shaderType);
708         if (currentShader)
709         {
710             if (shaderType == ShaderType::Vertex)
711             {
712                 for (const sh::Uniform &vertexUniform : currentShader->getUniforms())
713                 {
714                     linkedUniforms[vertexUniform.name] =
715                         std::make_pair(ShaderType::Vertex, &vertexUniform);
716                 }
717             }
718             else
719             {
720                 bool isLastShader = (shaderType == ShaderType::Fragment);
721                 if (!ValidateGraphicsUniformsPerShader(currentShader, !isLastShader,
722                                                        &linkedUniforms, infoLog))
723                 {
724                     return false;
725                 }
726             }
727         }
728     }
729 
730     return true;
731 }
732 
indexUniforms(InfoLog & infoLog,const ProgramBindings & uniformLocationBindings)733 bool UniformLinker::indexUniforms(InfoLog &infoLog, const ProgramBindings &uniformLocationBindings)
734 {
735     // Locations which have been allocated for an unused uniform.
736     std::set<GLuint> ignoredLocations;
737 
738     int maxUniformLocation = -1;
739 
740     // Gather uniform locations that have been set either using the bindUniformLocation API or by
741     // using a location layout qualifier and check conflicts between them.
742     if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
743                                                  &ignoredLocations, &maxUniformLocation))
744     {
745         return false;
746     }
747 
748     // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
749     // the line relies on only having statically used uniforms in mUniforms.
750     pruneUnusedUniforms();
751 
752     // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
753     std::vector<VariableLocation> unlocatedUniforms;
754     std::map<GLuint, VariableLocation> preLocatedUniforms;
755 
756     for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
757     {
758         const LinkedUniform &uniform = mUniforms[uniformIndex];
759 
760         if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) ||
761             IsAtomicCounterType(uniform.type))
762         {
763             continue;
764         }
765 
766         int preSetLocation = uniformLocationBindings.getBinding(uniform);
767         int shaderLocation = uniform.location;
768 
769         if (shaderLocation != -1)
770         {
771             preSetLocation = shaderLocation;
772         }
773 
774         unsigned int elementCount = uniform.getBasicTypeElementCount();
775         for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
776         {
777             VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
778 
779             if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
780             {
781                 int elementLocation                 = preSetLocation + arrayIndex;
782                 preLocatedUniforms[elementLocation] = location;
783             }
784             else
785             {
786                 unlocatedUniforms.push_back(location);
787             }
788         }
789     }
790 
791     // Make enough space for all uniforms, with pre-set locations or not.
792     mUniformLocations.resize(
793         std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
794                  static_cast<size_t>(maxUniformLocation + 1)));
795 
796     // Assign uniforms with pre-set locations
797     for (const auto &uniform : preLocatedUniforms)
798     {
799         mUniformLocations[uniform.first] = uniform.second;
800     }
801 
802     // Assign ignored uniforms
803     for (const auto &ignoredLocation : ignoredLocations)
804     {
805         mUniformLocations[ignoredLocation].markIgnored();
806     }
807 
808     // Automatically assign locations for the rest of the uniforms
809     size_t nextUniformLocation = 0;
810     for (const auto &unlocatedUniform : unlocatedUniforms)
811     {
812         while (mUniformLocations[nextUniformLocation].used() ||
813                mUniformLocations[nextUniformLocation].ignored)
814         {
815             nextUniformLocation++;
816         }
817 
818         ASSERT(nextUniformLocation < mUniformLocations.size());
819         mUniformLocations[nextUniformLocation] = unlocatedUniform;
820         nextUniformLocation++;
821     }
822 
823     return true;
824 }
825 
gatherUniformLocationsAndCheckConflicts(InfoLog & infoLog,const ProgramBindings & uniformLocationBindings,std::set<GLuint> * ignoredLocations,int * maxUniformLocation)826 bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
827     InfoLog &infoLog,
828     const ProgramBindings &uniformLocationBindings,
829     std::set<GLuint> *ignoredLocations,
830     int *maxUniformLocation)
831 {
832     // All the locations where another uniform can't be located.
833     std::set<GLuint> reservedLocations;
834 
835     for (const LinkedUniform &uniform : mUniforms)
836     {
837         if (uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn())
838         {
839             continue;
840         }
841 
842         int apiBoundLocation = uniformLocationBindings.getBinding(uniform);
843         int shaderLocation   = uniform.location;
844 
845         if (shaderLocation != -1)
846         {
847             unsigned int elementCount = uniform.getBasicTypeElementCount();
848 
849             for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
850             {
851                 // GLSL ES 3.10 section 4.4.3
852                 int elementLocation = shaderLocation + arrayIndex;
853                 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
854                 if (reservedLocations.find(elementLocation) != reservedLocations.end())
855                 {
856                     infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
857                     return false;
858                 }
859                 reservedLocations.insert(elementLocation);
860                 if (!uniform.active)
861                 {
862                     ignoredLocations->insert(elementLocation);
863                 }
864             }
865         }
866         else if (apiBoundLocation != -1 && uniform.staticUse)
867         {
868             // Only the first location is reserved even if the uniform is an array.
869             *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
870             if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
871             {
872                 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
873                 return false;
874             }
875             reservedLocations.insert(apiBoundLocation);
876             if (!uniform.active)
877             {
878                 ignoredLocations->insert(apiBoundLocation);
879             }
880         }
881     }
882 
883     // Record the uniform locations that were bound using the API for uniforms that were not found
884     // from the shader. Other uniforms should not be assigned to those locations.
885     for (const auto &locationBinding : uniformLocationBindings)
886     {
887         GLuint location = locationBinding.second.location;
888         if (reservedLocations.find(location) == reservedLocations.end())
889         {
890             ignoredLocations->insert(location);
891             *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
892         }
893     }
894 
895     return true;
896 }
897 
pruneUnusedUniforms()898 void UniformLinker::pruneUnusedUniforms()
899 {
900     auto uniformIter = mUniforms.begin();
901     while (uniformIter != mUniforms.end())
902     {
903         if (uniformIter->active)
904         {
905             ++uniformIter;
906         }
907         else
908         {
909             mUnusedUniforms.emplace_back(uniformIter->name, uniformIter->isSampler());
910             uniformIter = mUniforms.erase(uniformIter);
911         }
912     }
913 }
914 
flattenUniformsAndCheckCapsForShader(Shader * shader,const Caps & caps,std::vector<LinkedUniform> & samplerUniforms,std::vector<LinkedUniform> & imageUniforms,std::vector<LinkedUniform> & atomicCounterUniforms,std::vector<UnusedUniform> & unusedUniforms,InfoLog & infoLog)915 bool UniformLinker::flattenUniformsAndCheckCapsForShader(
916     Shader *shader,
917     const Caps &caps,
918     std::vector<LinkedUniform> &samplerUniforms,
919     std::vector<LinkedUniform> &imageUniforms,
920     std::vector<LinkedUniform> &atomicCounterUniforms,
921     std::vector<UnusedUniform> &unusedUniforms,
922     InfoLog &infoLog)
923 {
924     ShaderUniformCount shaderUniformCount;
925     for (const sh::Uniform &uniform : shader->getUniforms())
926     {
927         FlattenUniformVisitor flattener(shader->getType(), uniform, &mUniforms, &samplerUniforms,
928                                         &imageUniforms, &atomicCounterUniforms, &unusedUniforms);
929         sh::TraverseShaderVariable(uniform, false, &flattener);
930 
931         if (uniform.active)
932         {
933             shaderUniformCount += flattener.getCounts();
934         }
935         else
936         {
937             unusedUniforms.emplace_back(uniform.name, IsSamplerType(uniform.type));
938         }
939     }
940 
941     ShaderType shaderType = shader->getType();
942 
943     // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
944     GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
945     if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
946     {
947         GLuint maxUniforms = 0u;
948 
949         // See comments in GetUniformResourceLimitName()
950         if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
951         {
952             maxUniforms = maxUniformVectorsCount;
953         }
954         else
955         {
956             maxUniforms = maxUniformVectorsCount * 4;
957         }
958 
959         LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
960         return false;
961     }
962 
963     if (shaderUniformCount.samplerCount > caps.maxShaderTextureImageUnits[shaderType])
964     {
965         LogUniformsExceedLimit(shaderType, UniformType::Sampler,
966                                caps.maxShaderTextureImageUnits[shaderType], infoLog);
967         return false;
968     }
969 
970     if (shaderUniformCount.imageCount > caps.maxShaderImageUniforms[shaderType])
971     {
972         LogUniformsExceedLimit(shaderType, UniformType::Image,
973                                caps.maxShaderImageUniforms[shaderType], infoLog);
974         return false;
975     }
976 
977     if (shaderUniformCount.atomicCounterCount > caps.maxShaderAtomicCounters[shaderType])
978     {
979         LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
980                                caps.maxShaderAtomicCounters[shaderType], infoLog);
981         return false;
982     }
983 
984     return true;
985 }
986 
flattenUniformsAndCheckCaps(const Caps & caps,InfoLog & infoLog)987 bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
988 {
989     std::vector<LinkedUniform> samplerUniforms;
990     std::vector<LinkedUniform> imageUniforms;
991     std::vector<LinkedUniform> atomicCounterUniforms;
992     std::vector<UnusedUniform> unusedUniforms;
993 
994     for (const ShaderType shaderType : AllShaderTypes())
995     {
996         Shader *shader = mState.getAttachedShader(shaderType);
997         if (!shader)
998         {
999             continue;
1000         }
1001 
1002         if (!flattenUniformsAndCheckCapsForShader(shader, caps, samplerUniforms, imageUniforms,
1003                                                   atomicCounterUniforms, unusedUniforms, infoLog))
1004         {
1005             return false;
1006         }
1007     }
1008 
1009     mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
1010     mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
1011     mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
1012     mUnusedUniforms.insert(mUnusedUniforms.end(), unusedUniforms.begin(), unusedUniforms.end());
1013     return true;
1014 }
1015 
checkMaxCombinedAtomicCounters(const Caps & caps,InfoLog & infoLog)1016 bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
1017 {
1018     unsigned int atomicCounterCount = 0;
1019     for (const auto &uniform : mUniforms)
1020     {
1021         if (IsAtomicCounterType(uniform.type) && uniform.active)
1022         {
1023             atomicCounterCount += uniform.getBasicTypeElementCount();
1024             if (atomicCounterCount > caps.maxCombinedAtomicCounters)
1025             {
1026                 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
1027                         << caps.maxCombinedAtomicCounters << ").";
1028                 return false;
1029             }
1030         }
1031     }
1032     return true;
1033 }
1034 
1035 // InterfaceBlockLinker implementation.
InterfaceBlockLinker(std::vector<InterfaceBlock> * blocksOut,std::vector<std::string> * unusedInterfaceBlocksOut)1036 InterfaceBlockLinker::InterfaceBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1037                                            std::vector<std::string> *unusedInterfaceBlocksOut)
1038     : mShaderBlocks({}), mBlocksOut(blocksOut), mUnusedInterfaceBlocksOut(unusedInterfaceBlocksOut)
1039 {}
1040 
~InterfaceBlockLinker()1041 InterfaceBlockLinker::~InterfaceBlockLinker() {}
1042 
addShaderBlocks(ShaderType shaderType,const std::vector<sh::InterfaceBlock> * blocks)1043 void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
1044                                            const std::vector<sh::InterfaceBlock> *blocks)
1045 {
1046     mShaderBlocks[shaderType] = blocks;
1047 }
1048 
linkBlocks(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo) const1049 void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
1050                                       const GetBlockMemberInfoFunc &getMemberInfo) const
1051 {
1052     ASSERT(mBlocksOut->empty());
1053 
1054     std::set<std::string> visitedList;
1055 
1056     for (const ShaderType shaderType : AllShaderTypes())
1057     {
1058         if (!mShaderBlocks[shaderType])
1059         {
1060             continue;
1061         }
1062 
1063         for (const sh::InterfaceBlock &block : *mShaderBlocks[shaderType])
1064         {
1065             if (!IsActiveInterfaceBlock(block))
1066             {
1067                 mUnusedInterfaceBlocksOut->push_back(block.name);
1068                 continue;
1069             }
1070 
1071             if (visitedList.count(block.name) == 0)
1072             {
1073                 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
1074                 visitedList.insert(block.name);
1075                 continue;
1076             }
1077 
1078             if (!block.active)
1079             {
1080                 mUnusedInterfaceBlocksOut->push_back(block.name);
1081                 continue;
1082             }
1083 
1084             for (InterfaceBlock &priorBlock : *mBlocksOut)
1085             {
1086                 if (block.name == priorBlock.name)
1087                 {
1088                     priorBlock.setActive(shaderType, true);
1089 
1090                     std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1091                         getVisitor(getMemberInfo, block.fieldPrefix(), block.fieldMappedPrefix(),
1092                                    shaderType, -1));
1093 
1094                     sh::TraverseShaderVariables(block.fields, false, visitor.get());
1095                 }
1096             }
1097         }
1098     }
1099 }
1100 
defineInterfaceBlock(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo,const sh::InterfaceBlock & interfaceBlock,ShaderType shaderType) const1101 void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
1102                                                 const GetBlockMemberInfoFunc &getMemberInfo,
1103                                                 const sh::InterfaceBlock &interfaceBlock,
1104                                                 ShaderType shaderType) const
1105 {
1106     size_t blockSize = 0;
1107     std::vector<unsigned int> blockIndexes;
1108 
1109     int blockIndex = static_cast<int>(mBlocksOut->size());
1110     // Track the first and last block member index to determine the range of active block members in
1111     // the block.
1112     size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1113 
1114     std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1115         getVisitor(getMemberInfo, interfaceBlock.fieldPrefix(), interfaceBlock.fieldMappedPrefix(),
1116                    shaderType, blockIndex));
1117     sh::TraverseShaderVariables(interfaceBlock.fields, false, visitor.get());
1118 
1119     size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1120 
1121     for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1122          ++blockMemberIndex)
1123     {
1124         blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1125     }
1126 
1127     for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1128          ++arrayElement)
1129     {
1130         std::string blockArrayName       = interfaceBlock.name;
1131         std::string blockMappedArrayName = interfaceBlock.mappedName;
1132         if (interfaceBlock.isArray())
1133         {
1134             blockArrayName += ArrayString(arrayElement);
1135             blockMappedArrayName += ArrayString(arrayElement);
1136         }
1137 
1138         // Don't define this block at all if it's not active in the implementation.
1139         if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1140         {
1141             continue;
1142         }
1143 
1144         // ESSL 3.10 section 4.4.4 page 58:
1145         // Any uniform or shader storage block declared without a binding qualifier is initially
1146         // assigned to block binding point zero.
1147         int blockBinding =
1148             (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
1149         InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
1150                              interfaceBlock.isArray(), arrayElement, blockBinding);
1151         block.memberIndexes = blockIndexes;
1152         block.setActive(shaderType, interfaceBlock.active);
1153 
1154         // Since all block elements in an array share the same active interface blocks, they
1155         // will all be active once any block member is used. So, since interfaceBlock.name[0]
1156         // was active, here we will add every block element in the array.
1157         block.dataSize = static_cast<unsigned int>(blockSize);
1158         mBlocksOut->push_back(block);
1159     }
1160 }
1161 
1162 // UniformBlockLinker implementation.
UniformBlockLinker(std::vector<InterfaceBlock> * blocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * unusedInterfaceBlocksOut)1163 UniformBlockLinker::UniformBlockLinker(std::vector<InterfaceBlock> *blocksOut,
1164                                        std::vector<LinkedUniform> *uniformsOut,
1165                                        std::vector<std::string> *unusedInterfaceBlocksOut)
1166     : InterfaceBlockLinker(blocksOut, unusedInterfaceBlocksOut), mUniformsOut(uniformsOut)
1167 {}
1168 
~UniformBlockLinker()1169 UniformBlockLinker::~UniformBlockLinker() {}
1170 
getCurrentBlockMemberIndex() const1171 size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1172 {
1173     return mUniformsOut->size();
1174 }
1175 
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1176 sh::ShaderVariableVisitor *UniformBlockLinker::getVisitor(
1177     const GetBlockMemberInfoFunc &getMemberInfo,
1178     const std::string &namePrefix,
1179     const std::string &mappedNamePrefix,
1180     ShaderType shaderType,
1181     int blockIndex) const
1182 {
1183     return new UniformBlockEncodingVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1184                                            mUniformsOut, shaderType, blockIndex);
1185 }
1186 
1187 // ShaderStorageBlockLinker implementation.
ShaderStorageBlockLinker(std::vector<InterfaceBlock> * blocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1188 ShaderStorageBlockLinker::ShaderStorageBlockLinker(
1189     std::vector<InterfaceBlock> *blocksOut,
1190     std::vector<BufferVariable> *bufferVariablesOut,
1191     std::vector<std::string> *unusedInterfaceBlocksOut)
1192     : InterfaceBlockLinker(blocksOut, unusedInterfaceBlocksOut),
1193       mBufferVariablesOut(bufferVariablesOut)
1194 {}
1195 
~ShaderStorageBlockLinker()1196 ShaderStorageBlockLinker::~ShaderStorageBlockLinker() {}
1197 
getCurrentBlockMemberIndex() const1198 size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1199 {
1200     return mBufferVariablesOut->size();
1201 }
1202 
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1203 sh::ShaderVariableVisitor *ShaderStorageBlockLinker::getVisitor(
1204     const GetBlockMemberInfoFunc &getMemberInfo,
1205     const std::string &namePrefix,
1206     const std::string &mappedNamePrefix,
1207     ShaderType shaderType,
1208     int blockIndex) const
1209 {
1210     return new ShaderStorageBlockVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1211                                          mBufferVariablesOut, shaderType, blockIndex);
1212 }
1213 
1214 // AtomicCounterBufferLinker implementation.
AtomicCounterBufferLinker(std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1215 AtomicCounterBufferLinker::AtomicCounterBufferLinker(
1216     std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1217     : mAtomicCounterBuffersOut(atomicCounterBuffersOut)
1218 {}
1219 
~AtomicCounterBufferLinker()1220 AtomicCounterBufferLinker::~AtomicCounterBufferLinker() {}
1221 
link(const std::map<int,unsigned int> & sizeMap) const1222 void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1223 {
1224     for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1225     {
1226         auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1227         ASSERT(bufferSize != sizeMap.end());
1228         atomicCounterBuffer.dataSize = bufferSize->second;
1229     }
1230 }
1231 
ProgramLinkedResources(GLuint maxVaryingVectors,PackMode packMode,std::vector<InterfaceBlock> * uniformBlocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<InterfaceBlock> * shaderStorageBlocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1232 ProgramLinkedResources::ProgramLinkedResources(
1233     GLuint maxVaryingVectors,
1234     PackMode packMode,
1235     std::vector<InterfaceBlock> *uniformBlocksOut,
1236     std::vector<LinkedUniform> *uniformsOut,
1237     std::vector<InterfaceBlock> *shaderStorageBlocksOut,
1238     std::vector<BufferVariable> *bufferVariablesOut,
1239     std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1240     : varyingPacking(maxVaryingVectors, packMode),
1241       uniformBlockLinker(uniformBlocksOut, uniformsOut, &unusedInterfaceBlocks),
1242       shaderStorageBlockLinker(shaderStorageBlocksOut, bufferVariablesOut, &unusedInterfaceBlocks),
1243       atomicCounterBufferLinker(atomicCounterBuffersOut)
1244 {}
1245 
1246 ProgramLinkedResources::~ProgramLinkedResources() = default;
1247 
linkResources(const ProgramState & programState,const ProgramLinkedResources & resources) const1248 void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
1249                                                  const ProgramLinkedResources &resources) const
1250 {
1251     // Gather uniform interface block info.
1252     InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory);
1253     for (const ShaderType shaderType : AllShaderTypes())
1254     {
1255         Shader *shader = programState.getAttachedShader(shaderType);
1256         if (shader)
1257         {
1258             uniformBlockInfo.getShaderBlockInfo(shader->getUniformBlocks());
1259         }
1260     }
1261 
1262     auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name,
1263                                                    const std::string &mappedName, size_t *sizeOut) {
1264         return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut);
1265     };
1266 
1267     auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name,
1268                                                          const std::string &mappedName,
1269                                                          sh::BlockMemberInfo *infoOut) {
1270         return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1271     };
1272 
1273     // Link uniform interface blocks.
1274     resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
1275 
1276     // Gather storage bufer interface block info.
1277     InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory);
1278     for (const ShaderType shaderType : AllShaderTypes())
1279     {
1280         Shader *shader = programState.getAttachedShader(shaderType);
1281         if (shader)
1282         {
1283             shaderStorageBlockInfo.getShaderBlockInfo(shader->getShaderStorageBlocks());
1284         }
1285     }
1286     auto getShaderStorageBlockSize = [&shaderStorageBlockInfo](const std::string &name,
1287                                                                const std::string &mappedName,
1288                                                                size_t *sizeOut) {
1289         return shaderStorageBlockInfo.getBlockSize(name, mappedName, sizeOut);
1290     };
1291 
1292     auto getShaderStorageBlockMemberInfo = [&shaderStorageBlockInfo](const std::string &name,
1293                                                                      const std::string &mappedName,
1294                                                                      sh::BlockMemberInfo *infoOut) {
1295         return shaderStorageBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1296     };
1297 
1298     // Link storage buffer interface blocks.
1299     resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
1300                                                   getShaderStorageBlockMemberInfo);
1301 
1302     // Gather and link atomic counter buffer interface blocks.
1303     std::map<int, unsigned int> sizeMap;
1304     getAtomicCounterBufferSizeMap(programState, sizeMap);
1305     resources.atomicCounterBufferLinker.link(sizeMap);
1306 }
1307 
getAtomicCounterBufferSizeMap(const ProgramState & programState,std::map<int,unsigned int> & sizeMapOut) const1308 void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
1309     const ProgramState &programState,
1310     std::map<int, unsigned int> &sizeMapOut) const
1311 {
1312     for (unsigned int index : programState.getAtomicCounterUniformRange())
1313     {
1314         const LinkedUniform &glUniform = programState.getUniforms()[index];
1315 
1316         auto &bufferDataSize = sizeMapOut[glUniform.binding];
1317 
1318         // Calculate the size of the buffer by finding the end of the last uniform with the same
1319         // binding. The end of the uniform is calculated by finding the initial offset of the
1320         // uniform and adding size of the uniform. For arrays, the size is the number of elements
1321         // times the element size (should always by 4 for atomic_units).
1322         unsigned dataOffset =
1323             glUniform.offset + static_cast<unsigned int>(glUniform.getBasicTypeElementCount() *
1324                                                          glUniform.getElementSize());
1325         if (dataOffset > bufferDataSize)
1326         {
1327             bufferDataSize = dataOffset;
1328         }
1329     }
1330 }
1331 
1332 }  // namespace gl
1333