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