xref: /aosp_15_r20/external/angle/src/libANGLE/ProgramLinkedResources.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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<UsedUniform> & list,const std::string & name)24 UsedUniform *FindUniform(std::vector<UsedUniform> &list, const std::string &name)
25 {
26     for (UsedUniform &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,uint32_t id)36 void SetActive(std::vector<VarT> *list,
37                const std::string &name,
38                ShaderType shaderType,
39                bool active,
40                uint32_t id)
41 {
42     for (auto &variable : *list)
43     {
44         if (variable.name == name)
45         {
46             variable.setActive(shaderType, active, id);
47             return;
48         }
49     }
50 }
51 
52 template <typename VarT>
SetActive(std::vector<VarT> * list,std::vector<std::string> * nameList,const std::string & name,ShaderType shaderType,bool active,uint32_t id)53 void SetActive(std::vector<VarT> *list,
54                std::vector<std::string> *nameList,
55                const std::string &name,
56                ShaderType shaderType,
57                bool active,
58                uint32_t id)
59 {
60     for (GLint index = 0; index < static_cast<GLint>(nameList->size()); index++)
61     {
62         if ((*nameList)[index] == name)
63         {
64             (*list)[index].setActive(shaderType, active, id);
65             return;
66         }
67     }
68 }
69 
70 // GLSL ES Spec 3.00.3, section 4.3.5.
LinkValidateUniforms(const sh::ShaderVariable & uniform1,const sh::ShaderVariable & uniform2,std::string * mismatchedStructFieldName)71 LinkMismatchError LinkValidateUniforms(const sh::ShaderVariable &uniform1,
72                                        const sh::ShaderVariable &uniform2,
73                                        std::string *mismatchedStructFieldName)
74 {
75 #if ANGLE_PROGRAM_LINK_VALIDATE_UNIFORM_PRECISION
76     const bool validatePrecisionFeature = true;
77 #else
78     const bool validatePrecisionFeature = false;
79 #endif
80 
81     // Validate precision match of uniforms iff they are statically used
82     bool validatePrecision = uniform1.staticUse && uniform2.staticUse && validatePrecisionFeature;
83     LinkMismatchError linkError = LinkValidateProgramVariables(
84         uniform1, uniform2, validatePrecision, false, false, mismatchedStructFieldName);
85     if (linkError != LinkMismatchError::NO_MISMATCH)
86     {
87         return linkError;
88     }
89 
90     // GLSL ES Spec 3.10.4, section 4.4.5.
91     if (uniform1.binding != -1 && uniform2.binding != -1 && uniform1.binding != uniform2.binding)
92     {
93         return LinkMismatchError::BINDING_MISMATCH;
94     }
95 
96     // GLSL ES Spec 3.10.4, section 9.2.1.
97     if (uniform1.location != -1 && uniform2.location != -1 &&
98         uniform1.location != uniform2.location)
99     {
100         return LinkMismatchError::LOCATION_MISMATCH;
101     }
102     if (uniform1.offset != uniform2.offset)
103     {
104         return LinkMismatchError::OFFSET_MISMATCH;
105     }
106 
107     return LinkMismatchError::NO_MISMATCH;
108 }
109 
GetMaximumShaderUniformVectors(ShaderType shaderType,const Caps & caps)110 GLuint GetMaximumShaderUniformVectors(ShaderType shaderType, const Caps &caps)
111 {
112     switch (shaderType)
113     {
114         case ShaderType::Vertex:
115             return static_cast<GLuint>(caps.maxVertexUniformVectors);
116         case ShaderType::Fragment:
117             return static_cast<GLuint>(caps.maxFragmentUniformVectors);
118 
119         case ShaderType::Compute:
120         case ShaderType::Geometry:
121         case ShaderType::TessControl:
122         case ShaderType::TessEvaluation:
123             return static_cast<GLuint>(caps.maxShaderUniformComponents[shaderType]) / 4;
124 
125         default:
126             UNREACHABLE();
127             return 0u;
128     }
129 }
130 
131 enum class UniformType : uint8_t
132 {
133     Variable      = 0,
134     Sampler       = 1,
135     Image         = 2,
136     AtomicCounter = 3,
137 
138     InvalidEnum = 4,
139     EnumCount   = 4,
140 };
141 
GetUniformResourceNameString(UniformType uniformType)142 const char *GetUniformResourceNameString(UniformType uniformType)
143 {
144     switch (uniformType)
145     {
146         case UniformType::Variable:
147             return "uniform";
148         case UniformType::Sampler:
149             return "texture image unit";
150         case UniformType::Image:
151             return "image uniform";
152         case UniformType::AtomicCounter:
153             return "atomic counter";
154         default:
155             UNREACHABLE();
156             return "";
157     }
158 }
159 
GetUniformResourceLimitName(ShaderType shaderType,UniformType uniformType)160 std::string GetUniformResourceLimitName(ShaderType shaderType, UniformType uniformType)
161 {
162     // Special case: MAX_TEXTURE_IMAGE_UNITS (no "MAX_FRAGMENT_TEXTURE_IMAGE_UNITS")
163     if (shaderType == ShaderType::Fragment && uniformType == UniformType::Sampler)
164     {
165         return "MAX_TEXTURE_IMAGE_UNITS";
166     }
167 
168     std::ostringstream ostream;
169     ostream << "MAX_" << GetShaderTypeString(shaderType) << "_";
170 
171     switch (uniformType)
172     {
173         case UniformType::Variable:
174             // For vertex and fragment shaders, ES 2.0 only defines MAX_VERTEX_UNIFORM_VECTORS and
175             // MAX_FRAGMENT_UNIFORM_VECTORS ([OpenGL ES 2.0] Table 6.20).
176             if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
177             {
178                 ostream << "UNIFORM_VECTORS";
179                 break;
180             }
181             // For compute and geometry shaders, there are no definitions on
182             // "MAX_COMPUTE_UNIFORM_VECTORS" or "MAX_GEOMETRY_UNIFORM_VECTORS_EXT"
183             // ([OpenGL ES 3.1] Table 20.45, [EXT_geometry_shader] Table 20.43gs).
184             else
185             {
186                 ostream << "UNIFORM_COMPONENTS";
187             }
188             break;
189         case UniformType::Sampler:
190             ostream << "TEXTURE_IMAGE_UNITS";
191             break;
192         case UniformType::Image:
193             ostream << "IMAGE_UNIFORMS";
194             break;
195         case UniformType::AtomicCounter:
196             ostream << "ATOMIC_COUNTERS";
197             break;
198         default:
199             UNREACHABLE();
200             return "";
201     }
202 
203     if (shaderType == ShaderType::Geometry)
204     {
205         ostream << "_EXT";
206     }
207 
208     return ostream.str();
209 }
210 
LogUniformsExceedLimit(ShaderType shaderType,UniformType uniformType,GLuint limit,InfoLog & infoLog)211 void LogUniformsExceedLimit(ShaderType shaderType,
212                             UniformType uniformType,
213                             GLuint limit,
214                             InfoLog &infoLog)
215 {
216     infoLog << GetShaderTypeString(shaderType) << " shader "
217             << GetUniformResourceNameString(uniformType) << "s count exceeds "
218             << GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
219 }
220 
221 // The purpose of this visitor is to capture the uniforms in a uniform block. Each new uniform is
222 // added to "uniformsOut".
223 class UniformBlockEncodingVisitor : public sh::VariableNameVisitor
224 {
225   public:
UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * uniformNamesOut,std::vector<std::string> * uniformMappedNamesOut,ShaderType shaderType,int blockIndex)226     UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
227                                 const std::string &namePrefix,
228                                 const std::string &mappedNamePrefix,
229                                 std::vector<LinkedUniform> *uniformsOut,
230                                 std::vector<std::string> *uniformNamesOut,
231                                 std::vector<std::string> *uniformMappedNamesOut,
232                                 ShaderType shaderType,
233                                 int blockIndex)
234         : sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
235           mGetMemberInfo(getMemberInfo),
236           mUniformsOut(uniformsOut),
237           mUniformNamesOut(uniformNamesOut),
238           mUniformMappedNamesOut(uniformMappedNamesOut),
239           mShaderType(shaderType),
240           mBlockIndex(blockIndex)
241     {}
242 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)243     void visitNamedVariable(const sh::ShaderVariable &variable,
244                             bool isRowMajor,
245                             const std::string &name,
246                             const std::string &mappedName,
247                             const std::vector<unsigned int> &arraySizes) override
248     {
249         // If getBlockMemberInfo returns false, the variable is optimized out.
250         sh::BlockMemberInfo variableInfo;
251         if (!mGetMemberInfo(name, mappedName, &variableInfo))
252             return;
253 
254         std::string nameWithArrayIndex       = name;
255         std::string mappedNameWithArrayIndex = mappedName;
256 
257         if (variable.isArray())
258         {
259             nameWithArrayIndex += "[0]";
260             mappedNameWithArrayIndex += "[0]";
261         }
262 
263         if (mBlockIndex == -1)
264         {
265             SetActive(mUniformsOut, mUniformNamesOut, nameWithArrayIndex, mShaderType,
266                       variable.active, variable.id);
267             return;
268         }
269 
270         LinkedUniform newUniform(variable.type, variable.precision, variable.arraySizes, -1, -1, -1,
271                                  mBlockIndex, variableInfo);
272         newUniform.setActive(mShaderType, variable.active, variable.id);
273 
274         // Since block uniforms have no location, we don't need to store them in the uniform
275         // locations list.
276         mUniformsOut->push_back(newUniform);
277         mUniformNamesOut->push_back(nameWithArrayIndex);
278         mUniformMappedNamesOut->push_back(mappedNameWithArrayIndex);
279     }
280 
281   private:
282     const GetBlockMemberInfoFunc &mGetMemberInfo;
283     std::vector<LinkedUniform> *mUniformsOut;
284     std::vector<std::string> *mUniformNamesOut;
285     std::vector<std::string> *mUniformMappedNamesOut;
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, &mStubEncoder),
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,const std::vector<unsigned int> & arraySizes)308     void visitNamedVariable(const sh::ShaderVariable &variable,
309                             bool isRowMajor,
310                             const std::string &name,
311                             const std::string &mappedName,
312                             const std::vector<unsigned int> &arraySizes) override
313     {
314         if (mSkipEnabled)
315             return;
316 
317         // If getBlockMemberInfo returns false, the variable is optimized out.
318         sh::BlockMemberInfo variableInfo;
319         if (!mGetMemberInfo(name, mappedName, &variableInfo))
320             return;
321 
322         std::string nameWithArrayIndex       = name;
323         std::string mappedNameWithArrayIndex = mappedName;
324 
325         if (variable.isArray())
326         {
327             nameWithArrayIndex += "[0]";
328             mappedNameWithArrayIndex += "[0]";
329         }
330 
331         if (mBlockIndex == -1)
332         {
333             SetActive(mBufferVariablesOut, nameWithArrayIndex, mShaderType, variable.active,
334                       variable.id);
335             return;
336         }
337 
338         BufferVariable newBufferVariable(variable.type, variable.precision, nameWithArrayIndex,
339                                          variable.arraySizes, mBlockIndex, mTopLevelArraySize,
340                                          variableInfo);
341         newBufferVariable.mappedName = mappedNameWithArrayIndex;
342         newBufferVariable.setActive(mShaderType, variable.active, variable.id);
343 
344         mBufferVariablesOut->push_back(newBufferVariable);
345     }
346 
347   private:
348     const GetBlockMemberInfoFunc &mGetMemberInfo;
349     std::vector<BufferVariable> *mBufferVariablesOut;
350     const ShaderType mShaderType;
351     const int mBlockIndex;
352     sh::StubBlockEncoder mStubEncoder;
353 };
354 
355 struct ShaderUniformCount
356 {
357     unsigned int vectorCount        = 0;
358     unsigned int samplerCount       = 0;
359     unsigned int imageCount         = 0;
360     unsigned int atomicCounterCount = 0;
361     unsigned int fragmentInOutCount = 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     lhs.fragmentInOutCount += rhs.fragmentInOutCount;
371     return lhs;
372 }
373 
374 // The purpose of this visitor is to flatten struct and array uniforms into a list of singleton
375 // uniforms. They are stored in separate lists by uniform type so they can be sorted in order.
376 // Counts for each uniform category are stored and can be queried with "getCounts".
377 class FlattenUniformVisitor : public sh::VariableNameVisitor
378 {
379   public:
FlattenUniformVisitor(ShaderType shaderType,const sh::ShaderVariable & uniform,std::vector<UsedUniform> * uniforms,std::vector<UsedUniform> * samplerUniforms,std::vector<UsedUniform> * imageUniforms,std::vector<UsedUniform> * atomicCounterUniforms,std::vector<UsedUniform> * inputAttachmentUniforms,std::vector<UnusedUniform> * unusedUniforms)380     FlattenUniformVisitor(ShaderType shaderType,
381                           const sh::ShaderVariable &uniform,
382                           std::vector<UsedUniform> *uniforms,
383                           std::vector<UsedUniform> *samplerUniforms,
384                           std::vector<UsedUniform> *imageUniforms,
385                           std::vector<UsedUniform> *atomicCounterUniforms,
386                           std::vector<UsedUniform> *inputAttachmentUniforms,
387                           std::vector<UnusedUniform> *unusedUniforms)
388         : sh::VariableNameVisitor("", ""),
389           mShaderType(shaderType),
390           mMarkActive(uniform.active),
391           mMarkStaticUse(uniform.staticUse),
392           mBinding(uniform.binding),
393           mOffset(uniform.offset),
394           mLocation(uniform.location),
395           mUniforms(uniforms),
396           mSamplerUniforms(samplerUniforms),
397           mImageUniforms(imageUniforms),
398           mAtomicCounterUniforms(atomicCounterUniforms),
399           mInputAttachmentUniforms(inputAttachmentUniforms),
400           mUnusedUniforms(unusedUniforms)
401     {}
402 
visitNamedOpaqueObject(const sh::ShaderVariable & variable,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)403     void visitNamedOpaqueObject(const sh::ShaderVariable &variable,
404                                 const std::string &name,
405                                 const std::string &mappedName,
406                                 const std::vector<unsigned int> &arraySizes) override
407     {
408         visitNamedVariable(variable, false, name, mappedName, arraySizes);
409     }
410 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)411     void visitNamedVariable(const sh::ShaderVariable &variable,
412                             bool isRowMajor,
413                             const std::string &name,
414                             const std::string &mappedName,
415                             const std::vector<unsigned int> &arraySizes) override
416     {
417         bool isSampler                        = IsSamplerType(variable.type);
418         bool isImage                          = IsImageType(variable.type);
419         bool isAtomicCounter                  = IsAtomicCounterType(variable.type);
420         bool isFragmentInOut                  = variable.isFragmentInOut;
421         std::vector<UsedUniform> *uniformList = mUniforms;
422         if (isSampler)
423         {
424             uniformList = mSamplerUniforms;
425         }
426         else if (isImage)
427         {
428             uniformList = mImageUniforms;
429         }
430         else if (isAtomicCounter)
431         {
432             uniformList = mAtomicCounterUniforms;
433         }
434         else if (isFragmentInOut)
435         {
436             uniformList = mInputAttachmentUniforms;
437         }
438 
439         std::string fullNameWithArrayIndex(name);
440         std::string fullMappedNameWithArrayIndex(mappedName);
441 
442         if (variable.isArray())
443         {
444             // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
445             // Resources and including [0] at the end of array variable names.
446             fullNameWithArrayIndex += "[0]";
447             fullMappedNameWithArrayIndex += "[0]";
448         }
449 
450         UsedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
451         if (existingUniform)
452         {
453             if (getBinding() != -1)
454             {
455                 existingUniform->binding = getBinding();
456             }
457             if (getOffset() != -1)
458             {
459                 existingUniform->offset = getOffset();
460             }
461             if (mLocation != -1)
462             {
463                 existingUniform->location = mLocation;
464             }
465             if (mMarkActive)
466             {
467                 existingUniform->active = true;
468                 existingUniform->setActive(mShaderType, true, variable.id);
469             }
470             if (mMarkStaticUse)
471             {
472                 existingUniform->staticUse = true;
473             }
474         }
475         else
476         {
477             UsedUniform linkedUniform(variable.type, variable.precision, fullNameWithArrayIndex,
478                                       variable.arraySizes, getBinding(), getOffset(), mLocation, -1,
479                                       sh::kDefaultBlockMemberInfo);
480             linkedUniform.mappedName          = fullMappedNameWithArrayIndex;
481             linkedUniform.active              = mMarkActive;
482             linkedUniform.staticUse           = mMarkStaticUse;
483             linkedUniform.outerArraySizes     = arraySizes;
484             linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse;
485             linkedUniform.id                  = variable.id;
486             linkedUniform.imageUnitFormat     = variable.imageUnitFormat;
487             linkedUniform.isFragmentInOut     = variable.isFragmentInOut;
488             if (variable.hasParentArrayIndex())
489             {
490                 linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
491             }
492 
493             std::vector<unsigned int> arrayDims = arraySizes;
494             ASSERT(variable.arraySizes.size() == 1 || variable.arraySizes.size() == 0);
495             arrayDims.push_back(variable.arraySizes.empty() ? 1 : variable.arraySizes[0]);
496 
497             size_t numDimensions = arraySizes.size();
498             uint32_t arrayStride = 1;
499             for (size_t dimension = numDimensions; dimension > 0;)
500             {
501                 --dimension;
502                 arrayStride *= arrayDims[dimension + 1];
503                 linkedUniform.outerArrayOffset += arrayStride * mArrayElementStack[dimension];
504             }
505 
506             if (mMarkActive)
507             {
508                 linkedUniform.setActive(mShaderType, true, variable.id);
509             }
510             else
511             {
512                 mUnusedUniforms->emplace_back(
513                     linkedUniform.name, linkedUniform.isSampler(), linkedUniform.isImage(),
514                     linkedUniform.isAtomicCounter(), linkedUniform.isFragmentInOut);
515             }
516 
517             uniformList->push_back(linkedUniform);
518         }
519 
520         unsigned int elementCount = variable.getBasicTypeElementCount();
521 
522         // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
523         // Likewise, don't count "real" uniforms towards opaque count.
524 
525         if (!IsOpaqueType(variable.type) && !isFragmentInOut)
526         {
527             mUniformCount.vectorCount += VariableRegisterCount(variable.type) * elementCount;
528         }
529 
530         mUniformCount.samplerCount += (isSampler ? elementCount : 0);
531         mUniformCount.imageCount += (isImage ? elementCount : 0);
532         mUniformCount.atomicCounterCount += (isAtomicCounter ? elementCount : 0);
533         mUniformCount.fragmentInOutCount += (isFragmentInOut ? elementCount : 0);
534 
535         if (mLocation != -1)
536         {
537             mLocation += elementCount;
538         }
539     }
540 
enterStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)541     void enterStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
542     {
543         mStructStackSize++;
544         sh::VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
545     }
546 
exitStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)547     void exitStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
548     {
549         mStructStackSize--;
550         sh::VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
551     }
552 
enterArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)553     void enterArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
554     {
555         mArrayElementStack.push_back(arrayElement);
556         sh::VariableNameVisitor::enterArrayElement(arrayVar, arrayElement);
557     }
558 
exitArrayElement(const sh::ShaderVariable & arrayVar,unsigned int arrayElement)559     void exitArrayElement(const sh::ShaderVariable &arrayVar, unsigned int arrayElement) override
560     {
561         mArrayElementStack.pop_back();
562         sh::VariableNameVisitor::exitArrayElement(arrayVar, arrayElement);
563     }
564 
getCounts() const565     ShaderUniformCount getCounts() const { return mUniformCount; }
566 
567   private:
getBinding() const568     int getBinding() const { return mStructStackSize == 0 ? mBinding : -1; }
getOffset() const569     int getOffset() const { return mStructStackSize == 0 ? mOffset : -1; }
570 
571     ShaderType mShaderType;
572 
573     // Active and StaticUse are given separately because they are tracked at struct granularity.
574     bool mMarkActive;
575     bool mMarkStaticUse;
576     int mBinding;
577     int mOffset;
578     int mLocation;
579     std::vector<UsedUniform> *mUniforms;
580     std::vector<UsedUniform> *mSamplerUniforms;
581     std::vector<UsedUniform> *mImageUniforms;
582     std::vector<UsedUniform> *mAtomicCounterUniforms;
583     std::vector<UsedUniform> *mInputAttachmentUniforms;
584     std::vector<UnusedUniform> *mUnusedUniforms;
585     std::vector<unsigned int> mArrayElementStack;
586     ShaderUniformCount mUniformCount;
587     unsigned int mStructStackSize = 0;
588 };
589 
590 class InterfaceBlockInfo final : angle::NonCopyable
591 {
592   public:
InterfaceBlockInfo(CustomBlockLayoutEncoderFactory * customEncoderFactory)593     InterfaceBlockInfo(CustomBlockLayoutEncoderFactory *customEncoderFactory)
594         : mCustomEncoderFactory(customEncoderFactory)
595     {}
596 
597     void getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks);
598 
599     bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut);
600     bool getBlockMemberInfo(const std::string &name,
601                             const std::string &mappedName,
602                             sh::BlockMemberInfo *infoOut);
603 
604   private:
605     size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock);
606 
607     std::map<std::string, size_t> mBlockSizes;
608     sh::BlockLayoutMap mBlockLayout;
609     // Based on the interface block layout, the std140 or std430 encoders are used.  On some
610     // platforms (currently only D3D), there could be another non-standard encoder used.
611     CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
612 };
613 
getShaderBlockInfo(const std::vector<sh::InterfaceBlock> & interfaceBlocks)614 void InterfaceBlockInfo::getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks)
615 {
616     for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
617     {
618         if (!IsActiveInterfaceBlock(interfaceBlock))
619             continue;
620 
621         if (mBlockSizes.count(interfaceBlock.name) > 0)
622             continue;
623 
624         size_t dataSize                  = getBlockInfo(interfaceBlock);
625         mBlockSizes[interfaceBlock.name] = dataSize;
626     }
627 }
628 
getBlockInfo(const sh::InterfaceBlock & interfaceBlock)629 size_t InterfaceBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock)
630 {
631     ASSERT(IsActiveInterfaceBlock(interfaceBlock));
632 
633     // define member uniforms
634     sh::Std140BlockEncoder std140Encoder;
635     sh::Std430BlockEncoder std430Encoder;
636     sh::BlockLayoutEncoder *customEncoder = nullptr;
637     sh::BlockLayoutEncoder *encoder       = nullptr;
638 
639     if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140)
640     {
641         encoder = &std140Encoder;
642     }
643     else if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD430)
644     {
645         encoder = &std430Encoder;
646     }
647     else if (mCustomEncoderFactory)
648     {
649         encoder = customEncoder = mCustomEncoderFactory->makeEncoder();
650     }
651     else
652     {
653         UNREACHABLE();
654         return 0;
655     }
656 
657     sh::GetInterfaceBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
658                               &mBlockLayout);
659 
660     size_t offset = encoder->getCurrentOffset();
661 
662     SafeDelete(customEncoder);
663 
664     return offset;
665 }
666 
getBlockSize(const std::string & name,const std::string & mappedName,size_t * sizeOut)667 bool InterfaceBlockInfo::getBlockSize(const std::string &name,
668                                       const std::string &mappedName,
669                                       size_t *sizeOut)
670 {
671     size_t nameLengthWithoutArrayIndex;
672     ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
673     std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
674     auto sizeIter        = mBlockSizes.find(baseName);
675     if (sizeIter == mBlockSizes.end())
676     {
677         *sizeOut = 0;
678         return false;
679     }
680 
681     *sizeOut = sizeIter->second;
682     return true;
683 }
684 
getBlockMemberInfo(const std::string & name,const std::string & mappedName,sh::BlockMemberInfo * infoOut)685 bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name,
686                                             const std::string &mappedName,
687                                             sh::BlockMemberInfo *infoOut)
688 {
689     auto infoIter = mBlockLayout.find(name);
690     if (infoIter == mBlockLayout.end())
691     {
692         *infoOut = sh::kDefaultBlockMemberInfo;
693         return false;
694     }
695 
696     *infoOut = infoIter->second;
697     return true;
698 }
699 
GetFilteredVaryings(const std::vector<sh::ShaderVariable> & varyings,std::vector<const sh::ShaderVariable * > * filteredVaryingsOut)700 void GetFilteredVaryings(const std::vector<sh::ShaderVariable> &varyings,
701                          std::vector<const sh::ShaderVariable *> *filteredVaryingsOut)
702 {
703     for (const sh::ShaderVariable &varying : varyings)
704     {
705         // Built-in varyings obey special rules
706         if (varying.isBuiltIn())
707         {
708             continue;
709         }
710 
711         filteredVaryingsOut->push_back(&varying);
712     }
713 }
714 
LinkValidateVaryings(const sh::ShaderVariable & outputVarying,const sh::ShaderVariable & inputVarying,int shaderVersion,ShaderType frontShaderType,ShaderType backShaderType,bool isSeparable,std::string * mismatchedStructFieldName)715 LinkMismatchError LinkValidateVaryings(const sh::ShaderVariable &outputVarying,
716                                        const sh::ShaderVariable &inputVarying,
717                                        int shaderVersion,
718                                        ShaderType frontShaderType,
719                                        ShaderType backShaderType,
720                                        bool isSeparable,
721                                        std::string *mismatchedStructFieldName)
722 {
723     // [ES 3.2 spec] 7.4.1 Shader Interface Matching:
724     // Tessellation control shader per-vertex output variables and blocks and tessellation control,
725     // tessellation evaluation, and geometry shader per-vertex input variables and blocks are
726     // required to be declared as arrays, with each element representing input or output values for
727     // a single vertex of a multi-vertex primitive. For the purposes of interface matching, such
728     // variables and blocks are treated as though they were not declared as arrays.
729     bool treatOutputAsNonArray =
730         (frontShaderType == ShaderType::TessControl && !outputVarying.isPatch);
731     bool treatInputAsNonArray =
732         ((backShaderType == ShaderType::TessControl ||
733           backShaderType == ShaderType::TessEvaluation || backShaderType == ShaderType::Geometry) &&
734          !inputVarying.isPatch);
735 
736     // Skip the validation on the array sizes between a vertex output varying and a geometry input
737     // varying as it has been done before.
738     bool validatePrecision      = isSeparable && (shaderVersion > 100);
739     LinkMismatchError linkError = LinkValidateProgramVariables(
740         outputVarying, inputVarying, validatePrecision, treatOutputAsNonArray, treatInputAsNonArray,
741         mismatchedStructFieldName);
742     if (linkError != LinkMismatchError::NO_MISMATCH)
743     {
744         return linkError;
745     }
746 
747     // Explicit locations must match if the names match.
748     if (outputVarying.isSameNameAtLinkTime(inputVarying) &&
749         outputVarying.location != inputVarying.location)
750     {
751         return LinkMismatchError::LOCATION_MISMATCH;
752     }
753 
754     if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
755     {
756         return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
757     }
758 
759     if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
760     {
761         return LinkMismatchError::INVARIANCE_MISMATCH;
762     }
763 
764     return LinkMismatchError::NO_MISMATCH;
765 }
766 
DoShaderVariablesMatch(int frontShaderVersion,ShaderType frontShaderType,ShaderType backShaderType,const sh::ShaderVariable & input,const sh::ShaderVariable & output,bool isSeparable,gl::InfoLog & infoLog)767 bool DoShaderVariablesMatch(int frontShaderVersion,
768                             ShaderType frontShaderType,
769                             ShaderType backShaderType,
770                             const sh::ShaderVariable &input,
771                             const sh::ShaderVariable &output,
772                             bool isSeparable,
773                             gl::InfoLog &infoLog)
774 {
775     bool namesMatch     = input.isSameNameAtLinkTime(output);
776     bool locationsMatch = input.location != -1 && input.location == output.location;
777 
778     // An output block is considered to match an input block in the subsequent
779     // shader if the two blocks have the same block name, and the members of the
780     // block match exactly in name, type, qualification, and declaration order.
781     //
782     // - For the purposes of shader interface matching, the gl_PointSize
783     //   member of the intrinsically declared gl_PerVertex shader interface
784     //   block is ignored.
785     // - Output blocks that do not match in name, but have a location and match
786     //   in every other way listed above may be considered to match by some
787     //   implementations, but not all - so this behaviour should not be relied
788     //   upon.
789 
790     // An output variable is considered to match an input variable in the subsequent
791     // shader if:
792     //
793     // - the two variables match in name, type, and qualification; or
794     // - the two variables are declared with the same location qualifier and
795     //   match in type and qualification.
796 
797     if (namesMatch || locationsMatch)
798     {
799         std::string mismatchedStructFieldName;
800         LinkMismatchError linkError =
801             LinkValidateVaryings(output, input, frontShaderVersion, frontShaderType, backShaderType,
802                                  isSeparable, &mismatchedStructFieldName);
803         if (linkError != LinkMismatchError::NO_MISMATCH)
804         {
805             LogLinkMismatch(infoLog, input.name, "varying", linkError, mismatchedStructFieldName,
806                             frontShaderType, backShaderType);
807             return false;
808         }
809 
810         return true;
811     }
812 
813     return false;
814 }
815 
GetInterfaceBlockTypeString(sh::BlockType blockType)816 const char *GetInterfaceBlockTypeString(sh::BlockType blockType)
817 {
818     switch (blockType)
819     {
820         case sh::BlockType::kBlockUniform:
821             return "uniform block";
822         case sh::BlockType::kBlockBuffer:
823             return "shader storage block";
824         default:
825             UNREACHABLE();
826             return "";
827     }
828 }
829 
GetInterfaceBlockLimitName(ShaderType shaderType,sh::BlockType blockType)830 std::string GetInterfaceBlockLimitName(ShaderType shaderType, sh::BlockType blockType)
831 {
832     std::ostringstream stream;
833     stream << "GL_MAX_" << GetShaderTypeString(shaderType) << "_";
834 
835     switch (blockType)
836     {
837         case sh::BlockType::kBlockUniform:
838             stream << "UNIFORM_BUFFERS";
839             break;
840         case sh::BlockType::kBlockBuffer:
841             stream << "SHADER_STORAGE_BLOCKS";
842             break;
843         default:
844             UNREACHABLE();
845             return "";
846     }
847 
848     if (shaderType == ShaderType::Geometry)
849     {
850         stream << "_EXT";
851     }
852 
853     return stream.str();
854 }
855 
LogInterfaceBlocksExceedLimit(InfoLog & infoLog,ShaderType shaderType,sh::BlockType blockType,GLuint limit)856 void LogInterfaceBlocksExceedLimit(InfoLog &infoLog,
857                                    ShaderType shaderType,
858                                    sh::BlockType blockType,
859                                    GLuint limit)
860 {
861     infoLog << GetShaderTypeString(shaderType) << " shader "
862             << GetInterfaceBlockTypeString(blockType) << " count exceeds "
863             << GetInterfaceBlockLimitName(shaderType, blockType) << " (" << limit << ")";
864 }
865 
ValidateInterfaceBlocksCount(GLuint maxInterfaceBlocks,const std::vector<sh::InterfaceBlock> & interfaceBlocks,ShaderType shaderType,sh::BlockType blockType,GLuint * combinedInterfaceBlocksCount,InfoLog & infoLog)866 bool ValidateInterfaceBlocksCount(GLuint maxInterfaceBlocks,
867                                   const std::vector<sh::InterfaceBlock> &interfaceBlocks,
868                                   ShaderType shaderType,
869                                   sh::BlockType blockType,
870                                   GLuint *combinedInterfaceBlocksCount,
871                                   InfoLog &infoLog)
872 {
873     GLuint blockCount = 0;
874     for (const sh::InterfaceBlock &block : interfaceBlocks)
875     {
876         if (IsActiveInterfaceBlock(block))
877         {
878             blockCount += std::max(block.arraySize, 1u);
879             if (blockCount > maxInterfaceBlocks)
880             {
881                 LogInterfaceBlocksExceedLimit(infoLog, shaderType, blockType, maxInterfaceBlocks);
882                 return false;
883             }
884         }
885     }
886 
887     // [OpenGL ES 3.1] Chapter 7.6.2 Page 105:
888     // If a uniform block is used by multiple shader stages, each such use counts separately
889     // against this combined limit.
890     // [OpenGL ES 3.1] Chapter 7.8 Page 111:
891     // If a shader storage block in a program is referenced by multiple shaders, each such
892     // reference counts separately against this combined limit.
893     if (combinedInterfaceBlocksCount)
894     {
895         *combinedInterfaceBlocksCount += blockCount;
896     }
897 
898     return true;
899 }
900 }  // anonymous namespace
901 
902 // UsedUniform implementation
UsedUniform()903 UsedUniform::UsedUniform() {}
904 
UsedUniform(GLenum typeIn,GLenum precisionIn,const std::string & nameIn,const std::vector<unsigned int> & arraySizesIn,const int bindingIn,const int offsetIn,const int locationIn,const int bufferIndexIn,const sh::BlockMemberInfo & blockInfoIn)905 UsedUniform::UsedUniform(GLenum typeIn,
906                          GLenum precisionIn,
907                          const std::string &nameIn,
908                          const std::vector<unsigned int> &arraySizesIn,
909                          const int bindingIn,
910                          const int offsetIn,
911                          const int locationIn,
912                          const int bufferIndexIn,
913                          const sh::BlockMemberInfo &blockInfoIn)
914     : typeInfo(&GetUniformTypeInfo(typeIn)),
915       bufferIndex(bufferIndexIn),
916       blockInfo(blockInfoIn),
917       outerArrayOffset(0)
918 {
919     type       = typeIn;
920     precision  = precisionIn;
921     name       = nameIn;
922     arraySizes = arraySizesIn;
923     binding    = bindingIn;
924     offset     = offsetIn;
925     location   = locationIn;
926     ASSERT(!isArrayOfArrays());
927     ASSERT(!isArray() || !isStruct());
928 }
929 
UsedUniform(const UsedUniform & other)930 UsedUniform::UsedUniform(const UsedUniform &other)
931 {
932     *this = other;
933 }
934 
operator =(const UsedUniform & other)935 UsedUniform &UsedUniform::operator=(const UsedUniform &other)
936 {
937     if (this != &other)
938     {
939         sh::ShaderVariable::operator=(other);
940         activeVariable = other.activeVariable;
941 
942         typeInfo         = other.typeInfo;
943         bufferIndex      = other.bufferIndex;
944         blockInfo        = other.blockInfo;
945         outerArraySizes  = other.outerArraySizes;
946         outerArrayOffset = other.outerArrayOffset;
947     }
948     return *this;
949 }
950 
~UsedUniform()951 UsedUniform::~UsedUniform() {}
952 
953 // UniformLinker implementation
UniformLinker(const ShaderBitSet & activeShaderStages,const ShaderMap<std::vector<sh::ShaderVariable>> & shaderUniforms)954 UniformLinker::UniformLinker(const ShaderBitSet &activeShaderStages,
955                              const ShaderMap<std::vector<sh::ShaderVariable>> &shaderUniforms)
956     : mActiveShaderStages(activeShaderStages), mShaderUniforms(shaderUniforms)
957 {}
958 
959 UniformLinker::~UniformLinker() = default;
960 
getResults(std::vector<LinkedUniform> * uniforms,std::vector<std::string> * uniformNames,std::vector<std::string> * uniformMappedNames,std::vector<UnusedUniform> * unusedUniformsOutOrNull,std::vector<VariableLocation> * uniformLocationsOutOrNull)961 void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
962                                std::vector<std::string> *uniformNames,
963                                std::vector<std::string> *uniformMappedNames,
964                                std::vector<UnusedUniform> *unusedUniformsOutOrNull,
965                                std::vector<VariableLocation> *uniformLocationsOutOrNull)
966 {
967     uniforms->reserve(mUniforms.size());
968     uniformNames->reserve(mUniforms.size());
969     uniformMappedNames->reserve(mUniforms.size());
970     for (const UsedUniform &usedUniform : mUniforms)
971     {
972         uniforms->emplace_back(usedUniform);
973         uniformNames->emplace_back(usedUniform.name);
974         uniformMappedNames->emplace_back(usedUniform.mappedName);
975     }
976 
977     if (unusedUniformsOutOrNull)
978     {
979         unusedUniformsOutOrNull->swap(mUnusedUniforms);
980     }
981 
982     if (uniformLocationsOutOrNull)
983     {
984         uniformLocationsOutOrNull->swap(mUniformLocations);
985     }
986 }
987 
link(const Caps & caps,InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)988 bool UniformLinker::link(const Caps &caps,
989                          InfoLog &infoLog,
990                          const ProgramAliasedBindings &uniformLocationBindings)
991 {
992     if (mActiveShaderStages[ShaderType::Vertex] && mActiveShaderStages[ShaderType::Fragment])
993     {
994         if (!validateGraphicsUniforms(infoLog))
995         {
996             return false;
997         }
998     }
999 
1000     // Flatten the uniforms list (nested fields) into a simple list (no nesting).
1001     // Also check the maximum uniform vector and sampler counts.
1002     if (!flattenUniformsAndCheckCaps(caps, infoLog))
1003     {
1004         return false;
1005     }
1006 
1007     if (!checkMaxCombinedAtomicCounters(caps, infoLog))
1008     {
1009         return false;
1010     }
1011 
1012     if (!indexUniforms(infoLog, uniformLocationBindings))
1013     {
1014         return false;
1015     }
1016 
1017     return true;
1018 }
1019 
validateGraphicsUniforms(InfoLog & infoLog) const1020 bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
1021 {
1022     // Check that uniforms defined in the graphics shaders are identical
1023     std::map<std::string, ShaderUniform> linkedUniforms;
1024 
1025     for (const ShaderType shaderType : mActiveShaderStages)
1026     {
1027         if (shaderType == ShaderType::Vertex)
1028         {
1029             for (const sh::ShaderVariable &vertexUniform : mShaderUniforms[ShaderType::Vertex])
1030             {
1031                 linkedUniforms[vertexUniform.name] =
1032                     std::make_pair(ShaderType::Vertex, &vertexUniform);
1033             }
1034         }
1035         else
1036         {
1037             bool isLastShader = (shaderType == ShaderType::Fragment);
1038             if (!validateGraphicsUniformsPerShader(shaderType, !isLastShader, &linkedUniforms,
1039                                                    infoLog))
1040             {
1041                 return false;
1042             }
1043         }
1044     }
1045 
1046     return true;
1047 }
1048 
validateGraphicsUniformsPerShader(ShaderType shaderToLink,bool extendLinkedUniforms,std::map<std::string,ShaderUniform> * linkedUniforms,InfoLog & infoLog) const1049 bool UniformLinker::validateGraphicsUniformsPerShader(
1050     ShaderType shaderToLink,
1051     bool extendLinkedUniforms,
1052     std::map<std::string, ShaderUniform> *linkedUniforms,
1053     InfoLog &infoLog) const
1054 {
1055     ASSERT(mActiveShaderStages[shaderToLink] && linkedUniforms);
1056 
1057     for (const sh::ShaderVariable &uniform : mShaderUniforms[shaderToLink])
1058     {
1059         const auto &entry = linkedUniforms->find(uniform.name);
1060         if (entry != linkedUniforms->end())
1061         {
1062             const sh::ShaderVariable &linkedUniform = *(entry->second.second);
1063             std::string mismatchedStructFieldName;
1064             LinkMismatchError linkError =
1065                 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
1066             if (linkError != LinkMismatchError::NO_MISMATCH)
1067             {
1068                 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
1069                                 mismatchedStructFieldName, entry->second.first, shaderToLink);
1070                 return false;
1071             }
1072         }
1073         else if (extendLinkedUniforms)
1074         {
1075             (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink, &uniform);
1076         }
1077     }
1078 
1079     return true;
1080 }
1081 
indexUniforms(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)1082 bool UniformLinker::indexUniforms(InfoLog &infoLog,
1083                                   const ProgramAliasedBindings &uniformLocationBindings)
1084 {
1085     // Locations which have been allocated for an unused uniform.
1086     std::set<GLuint> ignoredLocations;
1087 
1088     int maxUniformLocation = -1;
1089 
1090     // Gather uniform locations that have been set either using the bindUniformLocationCHROMIUM API
1091     // or by using a location layout qualifier and check conflicts between them.
1092     if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
1093                                                  &ignoredLocations, &maxUniformLocation))
1094     {
1095         return false;
1096     }
1097 
1098     // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
1099     // the line relies on only having statically used uniforms in mUniforms.
1100     pruneUnusedUniforms();
1101 
1102     // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
1103     std::vector<VariableLocation> unlocatedUniforms;
1104     std::map<GLuint, VariableLocation> preLocatedUniforms;
1105 
1106     for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
1107     {
1108         const UsedUniform &uniform = mUniforms[uniformIndex];
1109 
1110         if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) ||
1111             IsAtomicCounterType(uniform.type) || uniform.isFragmentInOut)
1112         {
1113             continue;
1114         }
1115 
1116         int preSetLocation = uniformLocationBindings.getBinding(uniform);
1117         int shaderLocation = uniform.location;
1118 
1119         if (shaderLocation != -1)
1120         {
1121             preSetLocation = shaderLocation;
1122         }
1123 
1124         unsigned int elementCount = uniform.getBasicTypeElementCount();
1125         for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
1126         {
1127             VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
1128 
1129             if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
1130             {
1131                 int elementLocation                 = preSetLocation + arrayIndex;
1132                 preLocatedUniforms[elementLocation] = location;
1133             }
1134             else
1135             {
1136                 unlocatedUniforms.push_back(location);
1137             }
1138         }
1139     }
1140 
1141     // Make enough space for all uniforms, with pre-set locations or not.
1142     mUniformLocations.resize(
1143         std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
1144                  static_cast<size_t>(maxUniformLocation + 1)));
1145 
1146     // Assign uniforms with pre-set locations
1147     for (const auto &uniform : preLocatedUniforms)
1148     {
1149         mUniformLocations[uniform.first] = uniform.second;
1150     }
1151 
1152     // Assign ignored uniforms
1153     for (const auto &ignoredLocation : ignoredLocations)
1154     {
1155         mUniformLocations[ignoredLocation].markIgnored();
1156     }
1157 
1158     // Automatically assign locations for the rest of the uniforms
1159     size_t nextUniformLocation = 0;
1160     for (const auto &unlocatedUniform : unlocatedUniforms)
1161     {
1162         while (mUniformLocations[nextUniformLocation].used() ||
1163                mUniformLocations[nextUniformLocation].ignored)
1164         {
1165             nextUniformLocation++;
1166         }
1167 
1168         ASSERT(nextUniformLocation < mUniformLocations.size());
1169         mUniformLocations[nextUniformLocation] = unlocatedUniform;
1170         nextUniformLocation++;
1171     }
1172 
1173     return true;
1174 }
1175 
gatherUniformLocationsAndCheckConflicts(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings,std::set<GLuint> * ignoredLocations,int * maxUniformLocation)1176 bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
1177     InfoLog &infoLog,
1178     const ProgramAliasedBindings &uniformLocationBindings,
1179     std::set<GLuint> *ignoredLocations,
1180     int *maxUniformLocation)
1181 {
1182     // All the locations where another uniform can't be located.
1183     std::set<GLuint> reservedLocations;
1184 
1185     for (const UsedUniform &uniform : mUniforms)
1186     {
1187         if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) || uniform.isFragmentInOut)
1188         {
1189             // The uniform of the fragment inout is not a normal uniform type. So, in the case of
1190             // the fragment inout, this routine should be skipped.
1191             continue;
1192         }
1193 
1194         int apiBoundLocation = uniformLocationBindings.getBinding(uniform);
1195         int shaderLocation   = uniform.location;
1196 
1197         if (shaderLocation != -1)
1198         {
1199             unsigned int elementCount = uniform.getBasicTypeElementCount();
1200 
1201             for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
1202             {
1203                 // GLSL ES 3.10 section 4.4.3
1204                 int elementLocation = shaderLocation + arrayIndex;
1205                 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
1206                 if (reservedLocations.find(elementLocation) != reservedLocations.end())
1207                 {
1208                     infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
1209                     return false;
1210                 }
1211                 reservedLocations.insert(elementLocation);
1212                 if (!uniform.active)
1213                 {
1214                     ignoredLocations->insert(elementLocation);
1215                 }
1216             }
1217         }
1218         else if (apiBoundLocation != -1 && uniform.staticUse)
1219         {
1220             // Only the first location is reserved even if the uniform is an array.
1221             *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
1222             if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
1223             {
1224                 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
1225                 return false;
1226             }
1227             reservedLocations.insert(apiBoundLocation);
1228             if (!uniform.active)
1229             {
1230                 ignoredLocations->insert(apiBoundLocation);
1231             }
1232         }
1233     }
1234 
1235     // Record the uniform locations that were bound using the API for uniforms that were not found
1236     // from the shader. Other uniforms should not be assigned to those locations.
1237     for (const auto &locationBinding : uniformLocationBindings)
1238     {
1239         GLuint location = locationBinding.second.location;
1240         if (reservedLocations.find(location) == reservedLocations.end())
1241         {
1242             ignoredLocations->insert(location);
1243             *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
1244         }
1245     }
1246 
1247     return true;
1248 }
1249 
pruneUnusedUniforms()1250 void UniformLinker::pruneUnusedUniforms()
1251 {
1252     auto uniformIter = mUniforms.begin();
1253     while (uniformIter != mUniforms.end())
1254     {
1255         if (uniformIter->active)
1256         {
1257             ++uniformIter;
1258         }
1259         else
1260         {
1261             mUnusedUniforms.emplace_back(uniformIter->name, uniformIter->isSampler(),
1262                                          uniformIter->isImage(), uniformIter->isAtomicCounter(),
1263                                          uniformIter->isFragmentInOut);
1264             uniformIter = mUniforms.erase(uniformIter);
1265         }
1266     }
1267 }
1268 
flattenUniformsAndCheckCapsForShader(ShaderType shaderType,const Caps & caps,std::vector<UsedUniform> & samplerUniforms,std::vector<UsedUniform> & imageUniforms,std::vector<UsedUniform> & atomicCounterUniforms,std::vector<UsedUniform> & inputAttachmentUniforms,std::vector<UnusedUniform> & unusedUniforms,InfoLog & infoLog)1269 bool UniformLinker::flattenUniformsAndCheckCapsForShader(
1270     ShaderType shaderType,
1271     const Caps &caps,
1272     std::vector<UsedUniform> &samplerUniforms,
1273     std::vector<UsedUniform> &imageUniforms,
1274     std::vector<UsedUniform> &atomicCounterUniforms,
1275     std::vector<UsedUniform> &inputAttachmentUniforms,
1276     std::vector<UnusedUniform> &unusedUniforms,
1277     InfoLog &infoLog)
1278 {
1279     ShaderUniformCount shaderUniformCount;
1280     for (const sh::ShaderVariable &uniform : mShaderUniforms[shaderType])
1281     {
1282         FlattenUniformVisitor flattener(shaderType, uniform, &mUniforms, &samplerUniforms,
1283                                         &imageUniforms, &atomicCounterUniforms,
1284                                         &inputAttachmentUniforms, &unusedUniforms);
1285         sh::TraverseShaderVariable(uniform, false, &flattener);
1286 
1287         if (uniform.active)
1288         {
1289             shaderUniformCount += flattener.getCounts();
1290         }
1291         else
1292         {
1293             unusedUniforms.emplace_back(uniform.name, IsSamplerType(uniform.type),
1294                                         IsImageType(uniform.type),
1295                                         IsAtomicCounterType(uniform.type), uniform.isFragmentInOut);
1296         }
1297     }
1298 
1299     // This code does not do fine-grained component counting.
1300     GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
1301     if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
1302     {
1303         GLuint maxUniforms = 0u;
1304 
1305         // See comments in GetUniformResourceLimitName()
1306         if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
1307         {
1308             maxUniforms = maxUniformVectorsCount;
1309         }
1310         else
1311         {
1312             maxUniforms = maxUniformVectorsCount * 4;
1313         }
1314 
1315         LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
1316         return false;
1317     }
1318 
1319     if (shaderUniformCount.samplerCount >
1320         static_cast<GLuint>(caps.maxShaderTextureImageUnits[shaderType]))
1321     {
1322         LogUniformsExceedLimit(shaderType, UniformType::Sampler,
1323                                caps.maxShaderTextureImageUnits[shaderType], infoLog);
1324         return false;
1325     }
1326 
1327     if (shaderUniformCount.imageCount >
1328         static_cast<GLuint>(caps.maxShaderImageUniforms[shaderType]))
1329     {
1330         LogUniformsExceedLimit(shaderType, UniformType::Image,
1331                                caps.maxShaderImageUniforms[shaderType], infoLog);
1332         return false;
1333     }
1334 
1335     if (shaderUniformCount.atomicCounterCount >
1336         static_cast<GLuint>(caps.maxShaderAtomicCounters[shaderType]))
1337     {
1338         LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
1339                                caps.maxShaderAtomicCounters[shaderType], infoLog);
1340         return false;
1341     }
1342 
1343     return true;
1344 }
1345 
flattenUniformsAndCheckCaps(const Caps & caps,InfoLog & infoLog)1346 bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
1347 {
1348     std::vector<UsedUniform> samplerUniforms;
1349     std::vector<UsedUniform> imageUniforms;
1350     std::vector<UsedUniform> atomicCounterUniforms;
1351     std::vector<UsedUniform> inputAttachmentUniforms;
1352     std::vector<UnusedUniform> unusedUniforms;
1353 
1354     for (const ShaderType shaderType : mActiveShaderStages)
1355     {
1356         if (!flattenUniformsAndCheckCapsForShader(shaderType, caps, samplerUniforms, imageUniforms,
1357                                                   atomicCounterUniforms, inputAttachmentUniforms,
1358                                                   unusedUniforms, infoLog))
1359         {
1360             return false;
1361         }
1362     }
1363 
1364     mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
1365     mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
1366     mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
1367     mUniforms.insert(mUniforms.end(), inputAttachmentUniforms.begin(),
1368                      inputAttachmentUniforms.end());
1369     mUnusedUniforms.insert(mUnusedUniforms.end(), unusedUniforms.begin(), unusedUniforms.end());
1370     return true;
1371 }
1372 
checkMaxCombinedAtomicCounters(const Caps & caps,InfoLog & infoLog)1373 bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
1374 {
1375     unsigned int atomicCounterCount = 0;
1376     for (const auto &uniform : mUniforms)
1377     {
1378         if (IsAtomicCounterType(uniform.type) && uniform.active)
1379         {
1380             atomicCounterCount += uniform.getBasicTypeElementCount();
1381             if (atomicCounterCount > static_cast<GLuint>(caps.maxCombinedAtomicCounters))
1382             {
1383                 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
1384                         << caps.maxCombinedAtomicCounters << ").";
1385                 return false;
1386             }
1387         }
1388     }
1389     return true;
1390 }
1391 
1392 // InterfaceBlockLinker implementation.
1393 InterfaceBlockLinker::InterfaceBlockLinker() = default;
1394 
1395 InterfaceBlockLinker::~InterfaceBlockLinker() = default;
1396 
init(std::vector<InterfaceBlock> * blocksOut,std::vector<std::string> * unusedInterfaceBlocksOut)1397 void InterfaceBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1398                                 std::vector<std::string> *unusedInterfaceBlocksOut)
1399 {
1400     mBlocksOut                = blocksOut;
1401     mUnusedInterfaceBlocksOut = unusedInterfaceBlocksOut;
1402 }
1403 
addShaderBlocks(ShaderType shaderType,const std::vector<sh::InterfaceBlock> * blocks)1404 void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
1405                                            const std::vector<sh::InterfaceBlock> *blocks)
1406 {
1407     mShaderBlocks[shaderType] = blocks;
1408 }
1409 
linkBlocks(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo) const1410 void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
1411                                       const GetBlockMemberInfoFunc &getMemberInfo) const
1412 {
1413     ASSERT(mBlocksOut->empty());
1414 
1415     std::set<std::string> visitedList;
1416 
1417     for (const ShaderType shaderType : AllShaderTypes())
1418     {
1419         if (!mShaderBlocks[shaderType])
1420         {
1421             continue;
1422         }
1423 
1424         for (const sh::InterfaceBlock &block : *mShaderBlocks[shaderType])
1425         {
1426             if (!IsActiveInterfaceBlock(block))
1427             {
1428                 mUnusedInterfaceBlocksOut->push_back(block.name);
1429                 continue;
1430             }
1431 
1432             if (visitedList.count(block.name) == 0)
1433             {
1434                 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
1435                 visitedList.insert(block.name);
1436                 continue;
1437             }
1438 
1439             if (!block.active)
1440             {
1441                 mUnusedInterfaceBlocksOut->push_back(block.name);
1442                 continue;
1443             }
1444 
1445             for (InterfaceBlock &priorBlock : *mBlocksOut)
1446             {
1447                 if (block.name == priorBlock.name)
1448                 {
1449                     priorBlock.setActive(shaderType, true, block.id);
1450 
1451                     std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1452                         getVisitor(getMemberInfo, block.fieldPrefix(), block.fieldMappedPrefix(),
1453                                    shaderType, -1));
1454 
1455                     sh::TraverseShaderVariables(block.fields, false, visitor.get());
1456                 }
1457             }
1458         }
1459     }
1460 }
1461 
defineInterfaceBlock(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo,const sh::InterfaceBlock & interfaceBlock,ShaderType shaderType) const1462 void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
1463                                                 const GetBlockMemberInfoFunc &getMemberInfo,
1464                                                 const sh::InterfaceBlock &interfaceBlock,
1465                                                 ShaderType shaderType) const
1466 {
1467     size_t blockSize = 0;
1468     std::vector<unsigned int> blockIndexes;
1469 
1470     const int blockIndex = static_cast<int>(mBlocksOut->size());
1471     // Track the first and last block member index to determine the range of active block members in
1472     // the block.
1473     const size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1474 
1475     std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1476         getVisitor(getMemberInfo, interfaceBlock.fieldPrefix(), interfaceBlock.fieldMappedPrefix(),
1477                    shaderType, blockIndex));
1478     sh::TraverseShaderVariables(interfaceBlock.fields, false, visitor.get());
1479 
1480     const size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1481 
1482     for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1483          ++blockMemberIndex)
1484     {
1485         blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1486     }
1487 
1488     const unsigned int firstFieldArraySize = interfaceBlock.fields[0].getArraySizeProduct();
1489 
1490     for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1491          ++arrayElement)
1492     {
1493         std::string blockArrayName       = interfaceBlock.name;
1494         std::string blockMappedArrayName = interfaceBlock.mappedName;
1495         if (interfaceBlock.isArray())
1496         {
1497             blockArrayName += ArrayString(arrayElement);
1498             blockMappedArrayName += ArrayString(arrayElement);
1499         }
1500 
1501         // Don't define this block at all if it's not active in the implementation.
1502         if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1503         {
1504             continue;
1505         }
1506 
1507         // ESSL 3.10 section 4.4.4 page 58:
1508         // Any uniform or shader storage block declared without a binding qualifier is initially
1509         // assigned to block binding point zero.
1510         const int blockBinding =
1511             (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
1512         InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
1513                              interfaceBlock.isArray(), interfaceBlock.isReadOnly, arrayElement,
1514                              firstFieldArraySize, blockBinding);
1515         block.memberIndexes = blockIndexes;
1516         block.setActive(shaderType, interfaceBlock.active, interfaceBlock.id);
1517 
1518         // Since all block elements in an array share the same active interface blocks, they
1519         // will all be active once any block member is used. So, since interfaceBlock.name[0]
1520         // was active, here we will add every block element in the array.
1521         block.pod.dataSize = static_cast<unsigned int>(blockSize);
1522         mBlocksOut->push_back(block);
1523     }
1524 }
1525 
1526 // UniformBlockLinker implementation.
1527 UniformBlockLinker::UniformBlockLinker() = default;
1528 
~UniformBlockLinker()1529 UniformBlockLinker::~UniformBlockLinker() {}
1530 
init(std::vector<InterfaceBlock> * blocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * uniformNamesOut,std::vector<std::string> * uniformMappedNamesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1531 void UniformBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1532                               std::vector<LinkedUniform> *uniformsOut,
1533                               std::vector<std::string> *uniformNamesOut,
1534                               std::vector<std::string> *uniformMappedNamesOut,
1535                               std::vector<std::string> *unusedInterfaceBlocksOut)
1536 {
1537     InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1538     mUniformsOut           = uniformsOut;
1539     mUniformNamesOut       = uniformNamesOut;
1540     mUniformMappedNamesOut = uniformMappedNamesOut;
1541 }
1542 
getCurrentBlockMemberIndex() const1543 size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1544 {
1545     return mUniformsOut->size();
1546 }
1547 
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1548 sh::ShaderVariableVisitor *UniformBlockLinker::getVisitor(
1549     const GetBlockMemberInfoFunc &getMemberInfo,
1550     const std::string &namePrefix,
1551     const std::string &mappedNamePrefix,
1552     ShaderType shaderType,
1553     int blockIndex) const
1554 {
1555     return new UniformBlockEncodingVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1556                                            mUniformsOut, mUniformNamesOut, mUniformMappedNamesOut,
1557                                            shaderType, blockIndex);
1558 }
1559 
1560 // ShaderStorageBlockLinker implementation.
1561 ShaderStorageBlockLinker::ShaderStorageBlockLinker() = default;
1562 
1563 ShaderStorageBlockLinker::~ShaderStorageBlockLinker() = default;
1564 
init(std::vector<InterfaceBlock> * blocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1565 void ShaderStorageBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1566                                     std::vector<BufferVariable> *bufferVariablesOut,
1567                                     std::vector<std::string> *unusedInterfaceBlocksOut)
1568 {
1569     InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1570     mBufferVariablesOut = bufferVariablesOut;
1571 }
1572 
getCurrentBlockMemberIndex() const1573 size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1574 {
1575     return mBufferVariablesOut->size();
1576 }
1577 
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1578 sh::ShaderVariableVisitor *ShaderStorageBlockLinker::getVisitor(
1579     const GetBlockMemberInfoFunc &getMemberInfo,
1580     const std::string &namePrefix,
1581     const std::string &mappedNamePrefix,
1582     ShaderType shaderType,
1583     int blockIndex) const
1584 {
1585     return new ShaderStorageBlockVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1586                                          mBufferVariablesOut, shaderType, blockIndex);
1587 }
1588 
1589 // AtomicCounterBufferLinker implementation.
1590 AtomicCounterBufferLinker::AtomicCounterBufferLinker() = default;
1591 
1592 AtomicCounterBufferLinker::~AtomicCounterBufferLinker() = default;
1593 
init(std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1594 void AtomicCounterBufferLinker::init(std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1595 {
1596     mAtomicCounterBuffersOut = atomicCounterBuffersOut;
1597 }
1598 
link(const std::map<int,unsigned int> & sizeMap) const1599 void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1600 {
1601     for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1602     {
1603         auto bufferSize = sizeMap.find(atomicCounterBuffer.pod.inShaderBinding);
1604         ASSERT(bufferSize != sizeMap.end());
1605         atomicCounterBuffer.pod.dataSize = bufferSize->second;
1606     }
1607 }
1608 
1609 PixelLocalStorageLinker::PixelLocalStorageLinker() = default;
1610 
1611 PixelLocalStorageLinker::~PixelLocalStorageLinker() = default;
1612 
init(std::vector<ShPixelLocalStorageFormat> * pixelLocalStorageFormatsOut)1613 void PixelLocalStorageLinker::init(
1614     std::vector<ShPixelLocalStorageFormat> *pixelLocalStorageFormatsOut)
1615 {
1616     mPixelLocalStorageFormatsOut = pixelLocalStorageFormatsOut;
1617 }
1618 
link(const std::vector<ShPixelLocalStorageFormat> & pixelLocalStorageFormats) const1619 void PixelLocalStorageLinker::link(
1620     const std::vector<ShPixelLocalStorageFormat> &pixelLocalStorageFormats) const
1621 {
1622     *mPixelLocalStorageFormatsOut = pixelLocalStorageFormats;
1623 }
1624 
1625 LinkingVariables::LinkingVariables()  = default;
1626 LinkingVariables::~LinkingVariables() = default;
1627 
initForProgram(const ProgramState & state)1628 void LinkingVariables::initForProgram(const ProgramState &state)
1629 {
1630     for (ShaderType shaderType : kAllGraphicsShaderTypes)
1631     {
1632         const SharedCompiledShaderState &shader = state.getAttachedShader(shaderType);
1633         if (shader)
1634         {
1635             outputVaryings[shaderType] = shader->outputVaryings;
1636             inputVaryings[shaderType]  = shader->inputVaryings;
1637             uniforms[shaderType]       = shader->uniforms;
1638             uniformBlocks[shaderType]  = shader->uniformBlocks;
1639             isShaderStageUsedBitset.set(shaderType);
1640         }
1641     }
1642 }
1643 
initForProgramPipeline(const ProgramPipelineState & state)1644 void LinkingVariables::initForProgramPipeline(const ProgramPipelineState &state)
1645 {
1646     for (ShaderType shaderType : state.getExecutable().getLinkedShaderStages())
1647     {
1648         const SharedProgramExecutable &executable = state.getShaderProgramExecutable(shaderType);
1649         ASSERT(executable);
1650         outputVaryings[shaderType] = executable->getLinkedOutputVaryings(shaderType);
1651         inputVaryings[shaderType]  = executable->getLinkedInputVaryings(shaderType);
1652         uniforms[shaderType]       = executable->getLinkedUniforms(shaderType);
1653         uniformBlocks[shaderType]  = executable->getLinkedUniformBlocks(shaderType);
1654         isShaderStageUsedBitset.set(shaderType);
1655     }
1656 }
1657 
1658 ProgramLinkedResources::ProgramLinkedResources()  = default;
1659 ProgramLinkedResources::~ProgramLinkedResources() = default;
1660 
init(std::vector<InterfaceBlock> * uniformBlocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * uniformNamesOut,std::vector<std::string> * uniformMappedNamesOut,std::vector<InterfaceBlock> * shaderStorageBlocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut,std::vector<ShPixelLocalStorageFormat> * pixelLocalStorageFormatsOut)1661 void ProgramLinkedResources::init(
1662     std::vector<InterfaceBlock> *uniformBlocksOut,
1663     std::vector<LinkedUniform> *uniformsOut,
1664     std::vector<std::string> *uniformNamesOut,
1665     std::vector<std::string> *uniformMappedNamesOut,
1666     std::vector<InterfaceBlock> *shaderStorageBlocksOut,
1667     std::vector<BufferVariable> *bufferVariablesOut,
1668     std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut,
1669     std::vector<ShPixelLocalStorageFormat> *pixelLocalStorageFormatsOut)
1670 {
1671     uniformBlockLinker.init(uniformBlocksOut, uniformsOut, uniformNamesOut, uniformMappedNamesOut,
1672                             &unusedInterfaceBlocks);
1673     shaderStorageBlockLinker.init(shaderStorageBlocksOut, bufferVariablesOut,
1674                                   &unusedInterfaceBlocks);
1675     atomicCounterBufferLinker.init(atomicCounterBuffersOut);
1676     pixelLocalStorageLinker.init(pixelLocalStorageFormatsOut);
1677 }
1678 
linkResources(const ProgramState & programState,const ProgramLinkedResources & resources) const1679 void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
1680                                                  const ProgramLinkedResources &resources) const
1681 {
1682     // Gather uniform interface block info.
1683     InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory);
1684     for (const ShaderType shaderType : AllShaderTypes())
1685     {
1686         const SharedCompiledShaderState &shader = programState.getAttachedShader(shaderType);
1687         if (shader)
1688         {
1689             uniformBlockInfo.getShaderBlockInfo(shader->uniformBlocks);
1690         }
1691     }
1692 
1693     auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name,
1694                                                    const std::string &mappedName, size_t *sizeOut) {
1695         return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut);
1696     };
1697 
1698     auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name,
1699                                                          const std::string &mappedName,
1700                                                          sh::BlockMemberInfo *infoOut) {
1701         return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1702     };
1703 
1704     // Link uniform interface blocks.
1705     resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
1706 
1707     // Gather storage buffer interface block info.
1708     InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory);
1709     for (const ShaderType shaderType : AllShaderTypes())
1710     {
1711         const SharedCompiledShaderState &shader = programState.getAttachedShader(shaderType);
1712         if (shader)
1713         {
1714             shaderStorageBlockInfo.getShaderBlockInfo(shader->shaderStorageBlocks);
1715         }
1716     }
1717     auto getShaderStorageBlockSize = [&shaderStorageBlockInfo](const std::string &name,
1718                                                                const std::string &mappedName,
1719                                                                size_t *sizeOut) {
1720         return shaderStorageBlockInfo.getBlockSize(name, mappedName, sizeOut);
1721     };
1722 
1723     auto getShaderStorageBlockMemberInfo = [&shaderStorageBlockInfo](const std::string &name,
1724                                                                      const std::string &mappedName,
1725                                                                      sh::BlockMemberInfo *infoOut) {
1726         return shaderStorageBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1727     };
1728 
1729     // Link storage buffer interface blocks.
1730     resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
1731                                                   getShaderStorageBlockMemberInfo);
1732 
1733     // Gather and link atomic counter buffer interface blocks.
1734     std::map<int, unsigned int> sizeMap;
1735     getAtomicCounterBufferSizeMap(programState.getExecutable(), sizeMap);
1736     resources.atomicCounterBufferLinker.link(sizeMap);
1737 
1738     const gl::SharedCompiledShaderState &fragmentShader =
1739         programState.getAttachedShader(gl::ShaderType::Fragment);
1740     if (fragmentShader != nullptr)
1741     {
1742         resources.pixelLocalStorageLinker.link(fragmentShader->pixelLocalStorageFormats);
1743     }
1744 }
1745 
getAtomicCounterBufferSizeMap(const ProgramExecutable & executable,std::map<int,unsigned int> & sizeMapOut) const1746 void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
1747     const ProgramExecutable &executable,
1748     std::map<int, unsigned int> &sizeMapOut) const
1749 {
1750     for (unsigned int index : executable.getAtomicCounterUniformRange())
1751     {
1752         const LinkedUniform &glUniform = executable.getUniforms()[index];
1753 
1754         auto &bufferDataSize = sizeMapOut[glUniform.getBinding()];
1755 
1756         // Calculate the size of the buffer by finding the end of the last uniform with the same
1757         // binding. The end of the uniform is calculated by finding the initial offset of the
1758         // uniform and adding size of the uniform. For arrays, the size is the number of elements
1759         // times the element size (should always by 4 for atomic_units).
1760         unsigned dataOffset =
1761             glUniform.getOffset() + static_cast<unsigned int>(glUniform.getBasicTypeElementCount() *
1762                                                               glUniform.getElementSize());
1763         if (dataOffset > bufferDataSize)
1764         {
1765             bufferDataSize = dataOffset;
1766         }
1767     }
1768 }
1769 
LinkValidateProgramGlobalNames(InfoLog & infoLog,const ProgramExecutable & executable,const LinkingVariables & linkingVariables)1770 bool LinkValidateProgramGlobalNames(InfoLog &infoLog,
1771                                     const ProgramExecutable &executable,
1772                                     const LinkingVariables &linkingVariables)
1773 {
1774     angle::HashMap<std::string, const sh::ShaderVariable *> uniformMap;
1775     using BlockAndFieldPair = std::pair<const sh::InterfaceBlock *, const sh::ShaderVariable *>;
1776     angle::HashMap<std::string, std::vector<BlockAndFieldPair>> uniformBlockFieldMap;
1777 
1778     for (ShaderType shaderType : kAllGraphicsShaderTypes)
1779     {
1780         if (!linkingVariables.isShaderStageUsedBitset[shaderType])
1781         {
1782             continue;
1783         }
1784 
1785         // Build a map of Uniforms
1786         const std::vector<sh::ShaderVariable> &uniforms = linkingVariables.uniforms[shaderType];
1787         for (const auto &uniform : uniforms)
1788         {
1789             uniformMap[uniform.name] = &uniform;
1790         }
1791 
1792         // Build a map of Uniform Blocks
1793         // This will also detect any field name conflicts between Uniform Blocks without instance
1794         // names
1795         const std::vector<sh::InterfaceBlock> &uniformBlocks =
1796             linkingVariables.uniformBlocks[shaderType];
1797 
1798         for (const auto &uniformBlock : uniformBlocks)
1799         {
1800             // Only uniform blocks without an instance name can create a conflict with their field
1801             // names
1802             if (!uniformBlock.instanceName.empty())
1803             {
1804                 continue;
1805             }
1806 
1807             for (const auto &field : uniformBlock.fields)
1808             {
1809                 if (!uniformBlockFieldMap.count(field.name))
1810                 {
1811                     // First time we've seen this uniform block field name, so add the
1812                     // (Uniform Block, Field) pair immediately since there can't be a conflict yet
1813                     BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1814                     std::vector<BlockAndFieldPair> newUniformBlockList;
1815                     newUniformBlockList.push_back(blockAndFieldPair);
1816                     uniformBlockFieldMap[field.name] = newUniformBlockList;
1817                     continue;
1818                 }
1819 
1820                 // We've seen this name before.
1821                 // We need to check each of the uniform blocks that contain a field with this name
1822                 // to see if there's a conflict or not.
1823                 std::vector<BlockAndFieldPair> prevBlockFieldPairs =
1824                     uniformBlockFieldMap[field.name];
1825                 for (const auto &prevBlockFieldPair : prevBlockFieldPairs)
1826                 {
1827                     const sh::InterfaceBlock *prevUniformBlock      = prevBlockFieldPair.first;
1828                     const sh::ShaderVariable *prevUniformBlockField = prevBlockFieldPair.second;
1829 
1830                     if (uniformBlock.isSameInterfaceBlockAtLinkTime(*prevUniformBlock))
1831                     {
1832                         // The same uniform block should, by definition, contain the same field name
1833                         continue;
1834                     }
1835 
1836                     // The uniform blocks don't match, so check if the necessary field properties
1837                     // also match
1838                     if ((field.name == prevUniformBlockField->name) &&
1839                         (field.type == prevUniformBlockField->type) &&
1840                         (field.precision == prevUniformBlockField->precision))
1841                     {
1842                         infoLog << "Name conflicts between uniform block field names: "
1843                                 << field.name;
1844                         return false;
1845                     }
1846                 }
1847 
1848                 // No conflict, so record this pair
1849                 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1850                 uniformBlockFieldMap[field.name].push_back(blockAndFieldPair);
1851             }
1852         }
1853     }
1854 
1855     // Validate no uniform names conflict with attribute names
1856     if (linkingVariables.isShaderStageUsedBitset[ShaderType::Vertex])
1857     {
1858         // ESSL 3.00.6 section 4.3.5:
1859         // If a uniform variable name is declared in one stage (e.g., a vertex shader)
1860         // but not in another (e.g., a fragment shader), then that name is still
1861         // available in the other stage for a different use.
1862         std::unordered_set<std::string> uniforms;
1863         for (const sh::ShaderVariable &uniform : linkingVariables.uniforms[ShaderType::Vertex])
1864         {
1865             uniforms.insert(uniform.name);
1866         }
1867         for (const auto &attrib : executable.getProgramInputs())
1868         {
1869             if (uniforms.count(attrib.name))
1870             {
1871                 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
1872                 return false;
1873             }
1874         }
1875     }
1876 
1877     // Validate no Uniform Block fields conflict with other Uniforms
1878     for (const auto &uniformBlockField : uniformBlockFieldMap)
1879     {
1880         const std::string &fieldName = uniformBlockField.first;
1881         if (uniformMap.count(fieldName))
1882         {
1883             infoLog << "Name conflicts between a uniform and a uniform block field: " << fieldName;
1884             return false;
1885         }
1886     }
1887 
1888     return true;
1889 }
1890 
1891 // [OpenGL ES 3.2] Chapter 7.4.1 "Shader Interface Matching"
LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> & outputVaryings,const std::vector<sh::ShaderVariable> & inputVaryings,ShaderType frontShaderType,ShaderType backShaderType,int frontShaderVersion,int backShaderVersion,bool isSeparable,gl::InfoLog & infoLog)1892 bool LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> &outputVaryings,
1893                                          const std::vector<sh::ShaderVariable> &inputVaryings,
1894                                          ShaderType frontShaderType,
1895                                          ShaderType backShaderType,
1896                                          int frontShaderVersion,
1897                                          int backShaderVersion,
1898                                          bool isSeparable,
1899                                          gl::InfoLog &infoLog)
1900 {
1901     ASSERT(frontShaderVersion == backShaderVersion);
1902 
1903     std::vector<const sh::ShaderVariable *> filteredInputVaryings;
1904     std::vector<const sh::ShaderVariable *> filteredOutputVaryings;
1905 
1906     GetFilteredVaryings(inputVaryings, &filteredInputVaryings);
1907     GetFilteredVaryings(outputVaryings, &filteredOutputVaryings);
1908 
1909     // Separable programs require the number of inputs and outputs match
1910     if (isSeparable && filteredInputVaryings.size() < filteredOutputVaryings.size())
1911     {
1912         infoLog << GetShaderTypeString(backShaderType)
1913                 << " does not consume all varyings generated by "
1914                 << GetShaderTypeString(frontShaderType);
1915         return false;
1916     }
1917     if (isSeparable && filteredInputVaryings.size() > filteredOutputVaryings.size())
1918     {
1919         infoLog << GetShaderTypeString(frontShaderType)
1920                 << " does not generate all varyings consumed by "
1921                 << GetShaderTypeString(backShaderType);
1922         return false;
1923     }
1924 
1925     // All inputs must match all outputs
1926     for (const sh::ShaderVariable *input : filteredInputVaryings)
1927     {
1928         bool match = false;
1929         for (const sh::ShaderVariable *output : filteredOutputVaryings)
1930         {
1931             if (DoShaderVariablesMatch(frontShaderVersion, frontShaderType, backShaderType, *input,
1932                                        *output, isSeparable, infoLog))
1933             {
1934                 match = true;
1935                 break;
1936             }
1937         }
1938 
1939         // We permit unmatched, unreferenced varyings. Note that this specifically depends on
1940         // whether the input is statically used - a statically used input should fail this test even
1941         // if it is not active. GLSL ES 3.00.6 section 4.3.10.
1942         if (!match && input->staticUse)
1943         {
1944             const std::string &name =
1945                 input->isShaderIOBlock ? input->structOrBlockName : input->name;
1946             infoLog << GetShaderTypeString(backShaderType) << " varying " << name
1947                     << " does not match any " << GetShaderTypeString(frontShaderType) << " varying";
1948             return false;
1949         }
1950     }
1951 
1952     return true;
1953 }
1954 
LinkValidateProgramVariables(const sh::ShaderVariable & variable1,const sh::ShaderVariable & variable2,bool validatePrecision,bool treatVariable1AsNonArray,bool treatVariable2AsNonArray,std::string * mismatchedStructOrBlockMemberName)1955 LinkMismatchError LinkValidateProgramVariables(const sh::ShaderVariable &variable1,
1956                                                const sh::ShaderVariable &variable2,
1957                                                bool validatePrecision,
1958                                                bool treatVariable1AsNonArray,
1959                                                bool treatVariable2AsNonArray,
1960                                                std::string *mismatchedStructOrBlockMemberName)
1961 {
1962     if (variable1.type != variable2.type)
1963     {
1964         return LinkMismatchError::TYPE_MISMATCH;
1965     }
1966 
1967     bool variable1IsArray = variable1.isArray();
1968     bool variable2IsArray = variable2.isArray();
1969     if (treatVariable1AsNonArray)
1970     {
1971         ASSERT(variable1IsArray);
1972         variable1IsArray = false;
1973     }
1974     if (treatVariable2AsNonArray)
1975     {
1976         ASSERT(variable2IsArray);
1977         variable2IsArray = false;
1978     }
1979     // TODO(anglebug.com/42264094): Investigate interactions with arrays-of-arrays.
1980     if (variable1IsArray != variable2IsArray)
1981     {
1982         return LinkMismatchError::ARRAYNESS_MISMATCH;
1983     }
1984     if (!treatVariable1AsNonArray && !treatVariable2AsNonArray &&
1985         variable1.arraySizes != variable2.arraySizes)
1986     {
1987         return LinkMismatchError::ARRAY_SIZE_MISMATCH;
1988     }
1989     if (validatePrecision && variable1.precision != variable2.precision)
1990     {
1991         return LinkMismatchError::PRECISION_MISMATCH;
1992     }
1993     if (!variable1.isShaderIOBlock && !variable2.isShaderIOBlock &&
1994         variable1.structOrBlockName != variable2.structOrBlockName)
1995     {
1996         return LinkMismatchError::STRUCT_NAME_MISMATCH;
1997     }
1998     if (variable1.imageUnitFormat != variable2.imageUnitFormat)
1999     {
2000         return LinkMismatchError::FORMAT_MISMATCH;
2001     }
2002 
2003     if (variable1.fields.size() != variable2.fields.size())
2004     {
2005         return LinkMismatchError::FIELD_NUMBER_MISMATCH;
2006     }
2007     const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
2008     for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
2009     {
2010         const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
2011         const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
2012 
2013         if (member1.name != member2.name)
2014         {
2015             return LinkMismatchError::FIELD_NAME_MISMATCH;
2016         }
2017 
2018         if (member1.interpolation != member2.interpolation)
2019         {
2020             return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
2021         }
2022 
2023         if (variable1.isShaderIOBlock && variable2.isShaderIOBlock)
2024         {
2025             if (member1.location != member2.location)
2026             {
2027                 return LinkMismatchError::FIELD_LOCATION_MISMATCH;
2028             }
2029 
2030             if (member1.structOrBlockName != member2.structOrBlockName)
2031             {
2032                 return LinkMismatchError::FIELD_STRUCT_NAME_MISMATCH;
2033             }
2034         }
2035 
2036         LinkMismatchError linkErrorOnField = LinkValidateProgramVariables(
2037             member1, member2, validatePrecision, false, false, mismatchedStructOrBlockMemberName);
2038         if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
2039         {
2040             AddProgramVariableParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
2041             return linkErrorOnField;
2042         }
2043     }
2044 
2045     return LinkMismatchError::NO_MISMATCH;
2046 }
2047 
AddProgramVariableParentPrefix(const std::string & parentName,std::string * mismatchedFieldName)2048 void AddProgramVariableParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
2049 {
2050     ASSERT(mismatchedFieldName);
2051     if (mismatchedFieldName->empty())
2052     {
2053         *mismatchedFieldName = parentName;
2054     }
2055     else
2056     {
2057         std::ostringstream stream;
2058         stream << parentName << "." << *mismatchedFieldName;
2059         *mismatchedFieldName = stream.str();
2060     }
2061 }
2062 
LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> & vertexVaryings,const std::vector<sh::ShaderVariable> & fragmentVaryings,int vertexShaderVersion,InfoLog & infoLog)2063 bool LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> &vertexVaryings,
2064                                           const std::vector<sh::ShaderVariable> &fragmentVaryings,
2065                                           int vertexShaderVersion,
2066                                           InfoLog &infoLog)
2067 {
2068     bool glPositionIsInvariant   = false;
2069     bool glPointSizeIsInvariant  = false;
2070     bool glFragCoordIsInvariant  = false;
2071     bool glPointCoordIsInvariant = false;
2072 
2073     for (const sh::ShaderVariable &varying : vertexVaryings)
2074     {
2075         if (!varying.isBuiltIn())
2076         {
2077             continue;
2078         }
2079         if (varying.name.compare("gl_Position") == 0)
2080         {
2081             glPositionIsInvariant = varying.isInvariant;
2082         }
2083         else if (varying.name.compare("gl_PointSize") == 0)
2084         {
2085             glPointSizeIsInvariant = varying.isInvariant;
2086         }
2087     }
2088 
2089     for (const sh::ShaderVariable &varying : fragmentVaryings)
2090     {
2091         if (!varying.isBuiltIn())
2092         {
2093             continue;
2094         }
2095         if (varying.name.compare("gl_FragCoord") == 0)
2096         {
2097             glFragCoordIsInvariant = varying.isInvariant;
2098         }
2099         else if (varying.name.compare("gl_PointCoord") == 0)
2100         {
2101             glPointCoordIsInvariant = varying.isInvariant;
2102         }
2103     }
2104 
2105     // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
2106     // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
2107     // Not requiring invariance to match is supported by:
2108     // dEQP, WebGL CTS, Nexus 5X GLES
2109     if (glFragCoordIsInvariant && !glPositionIsInvariant)
2110     {
2111         infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
2112                    "declared invariant.";
2113         return false;
2114     }
2115     if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
2116     {
2117         infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
2118                    "declared invariant.";
2119         return false;
2120     }
2121 
2122     return true;
2123 }
2124 
LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> & outputVaryings,const std::vector<sh::ShaderVariable> & inputVaryings,ShaderType outputShaderType,ShaderType inputShaderType,int outputShaderVersion,int inputShaderVersion,InfoLog & infoLog)2125 bool LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &outputVaryings,
2126                                  const std::vector<sh::ShaderVariable> &inputVaryings,
2127                                  ShaderType outputShaderType,
2128                                  ShaderType inputShaderType,
2129                                  int outputShaderVersion,
2130                                  int inputShaderVersion,
2131                                  InfoLog &infoLog)
2132 {
2133     ASSERT(outputShaderVersion == inputShaderVersion);
2134 
2135     // Only ESSL 1.0 has restrictions on matching input and output invariance
2136     if (inputShaderVersion == 100 && outputShaderType == ShaderType::Vertex &&
2137         inputShaderType == ShaderType::Fragment)
2138     {
2139         return LinkValidateBuiltInVaryingsInvariant(outputVaryings, inputVaryings,
2140                                                     outputShaderVersion, infoLog);
2141     }
2142 
2143     uint32_t sizeClipDistance = 0;
2144     uint32_t sizeCullDistance = 0;
2145 
2146     for (const sh::ShaderVariable &varying : outputVaryings)
2147     {
2148         if (!varying.isBuiltIn())
2149         {
2150             continue;
2151         }
2152         if (varying.name.compare("gl_ClipDistance") == 0)
2153         {
2154             sizeClipDistance = varying.getOutermostArraySize();
2155         }
2156         else if (varying.name.compare("gl_CullDistance") == 0)
2157         {
2158             sizeCullDistance = varying.getOutermostArraySize();
2159         }
2160     }
2161 
2162     for (const sh::ShaderVariable &varying : inputVaryings)
2163     {
2164         if (!varying.isBuiltIn())
2165         {
2166             continue;
2167         }
2168         if (varying.name.compare("gl_ClipDistance") == 0)
2169         {
2170             if (sizeClipDistance != varying.getOutermostArraySize())
2171             {
2172                 infoLog
2173                     << "If a fragment shader statically uses the gl_ClipDistance built-in array, "
2174                        "the array must have the same size as in the previous shader stage. "
2175                     << "Output size " << sizeClipDistance << ", input size "
2176                     << varying.getOutermostArraySize() << ".";
2177                 return false;
2178             }
2179         }
2180         else if (varying.name.compare("gl_CullDistance") == 0)
2181         {
2182             if (sizeCullDistance != varying.getOutermostArraySize())
2183             {
2184                 infoLog
2185                     << "If a fragment shader statically uses the gl_ClipDistance built-in array, "
2186                        "the array must have the same size as in the previous shader stage. "
2187                     << "Output size " << sizeCullDistance << ", input size "
2188                     << varying.getOutermostArraySize() << ".";
2189 
2190                 return false;
2191             }
2192         }
2193     }
2194     return true;
2195 }
2196 
LogAmbiguousFieldLinkMismatch(InfoLog & infoLog,const std::string & blockName1,const std::string & blockName2,const std::string & fieldName,ShaderType shaderType1,ShaderType shaderType2)2197 void LogAmbiguousFieldLinkMismatch(InfoLog &infoLog,
2198                                    const std::string &blockName1,
2199                                    const std::string &blockName2,
2200                                    const std::string &fieldName,
2201                                    ShaderType shaderType1,
2202                                    ShaderType shaderType2)
2203 {
2204     infoLog << "Ambiguous field '" << fieldName << "' in blocks '" << blockName1 << "' ("
2205             << GetShaderTypeString(shaderType1) << " shader) and '" << blockName2 << "' ("
2206             << GetShaderTypeString(shaderType2) << " shader) which don't have instance names.";
2207 }
2208 
ValidateInstancelessGraphicsInterfaceBlocksPerShader(const std::vector<sh::InterfaceBlock> & interfaceBlocks,ShaderType shaderType,InterfaceBlockMap * instancelessBlocksFields,InfoLog & infoLog)2209 bool ValidateInstancelessGraphicsInterfaceBlocksPerShader(
2210     const std::vector<sh::InterfaceBlock> &interfaceBlocks,
2211     ShaderType shaderType,
2212     InterfaceBlockMap *instancelessBlocksFields,
2213     InfoLog &infoLog)
2214 {
2215     ASSERT(instancelessBlocksFields);
2216 
2217     for (const sh::InterfaceBlock &block : interfaceBlocks)
2218     {
2219         if (!block.instanceName.empty())
2220         {
2221             continue;
2222         }
2223 
2224         for (const sh::ShaderVariable &field : block.fields)
2225         {
2226             const auto &entry = instancelessBlocksFields->find(field.name);
2227             if (entry != instancelessBlocksFields->end())
2228             {
2229                 const sh::InterfaceBlock &linkedBlock = *(entry->second.second);
2230                 if (block.name != linkedBlock.name)
2231                 {
2232                     LogAmbiguousFieldLinkMismatch(infoLog, block.name, linkedBlock.name, field.name,
2233                                                   entry->second.first, shaderType);
2234                     return false;
2235                 }
2236             }
2237             else
2238             {
2239                 (*instancelessBlocksFields)[field.name] = std::make_pair(shaderType, &block);
2240             }
2241         }
2242     }
2243 
2244     return true;
2245 }
2246 
LinkValidateInterfaceBlockFields(const sh::ShaderVariable & blockField1,const sh::ShaderVariable & blockField2,bool webglCompatibility,std::string * mismatchedBlockFieldName)2247 LinkMismatchError LinkValidateInterfaceBlockFields(const sh::ShaderVariable &blockField1,
2248                                                    const sh::ShaderVariable &blockField2,
2249                                                    bool webglCompatibility,
2250                                                    std::string *mismatchedBlockFieldName)
2251 {
2252     if (blockField1.name != blockField2.name)
2253     {
2254         return LinkMismatchError::FIELD_NAME_MISMATCH;
2255     }
2256 
2257     // If webgl, validate precision of UBO fields, otherwise don't.  See Khronos bug 10287.
2258     LinkMismatchError linkError = LinkValidateProgramVariables(
2259         blockField1, blockField2, webglCompatibility, false, false, mismatchedBlockFieldName);
2260     if (linkError != LinkMismatchError::NO_MISMATCH)
2261     {
2262         AddProgramVariableParentPrefix(blockField1.name, mismatchedBlockFieldName);
2263         return linkError;
2264     }
2265 
2266     if (blockField1.isRowMajorLayout != blockField2.isRowMajorLayout)
2267     {
2268         AddProgramVariableParentPrefix(blockField1.name, mismatchedBlockFieldName);
2269         return LinkMismatchError::MATRIX_PACKING_MISMATCH;
2270     }
2271 
2272     return LinkMismatchError::NO_MISMATCH;
2273 }
2274 
AreMatchingInterfaceBlocks(const sh::InterfaceBlock & interfaceBlock1,const sh::InterfaceBlock & interfaceBlock2,bool webglCompatibility,std::string * mismatchedBlockFieldName)2275 LinkMismatchError AreMatchingInterfaceBlocks(const sh::InterfaceBlock &interfaceBlock1,
2276                                              const sh::InterfaceBlock &interfaceBlock2,
2277                                              bool webglCompatibility,
2278                                              std::string *mismatchedBlockFieldName)
2279 {
2280     // validate blocks for the same member types
2281     if (interfaceBlock1.fields.size() != interfaceBlock2.fields.size())
2282     {
2283         return LinkMismatchError::FIELD_NUMBER_MISMATCH;
2284     }
2285     if (interfaceBlock1.arraySize != interfaceBlock2.arraySize)
2286     {
2287         return LinkMismatchError::ARRAY_SIZE_MISMATCH;
2288     }
2289     if (interfaceBlock1.layout != interfaceBlock2.layout ||
2290         interfaceBlock1.binding != interfaceBlock2.binding)
2291     {
2292         return LinkMismatchError::LAYOUT_QUALIFIER_MISMATCH;
2293     }
2294     if (interfaceBlock1.instanceName.empty() != interfaceBlock2.instanceName.empty())
2295     {
2296         return LinkMismatchError::INSTANCE_NAME_MISMATCH;
2297     }
2298     const unsigned int numBlockMembers = static_cast<unsigned int>(interfaceBlock1.fields.size());
2299     for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
2300     {
2301         const sh::ShaderVariable &member1 = interfaceBlock1.fields[blockMemberIndex];
2302         const sh::ShaderVariable &member2 = interfaceBlock2.fields[blockMemberIndex];
2303 
2304         LinkMismatchError linkError = LinkValidateInterfaceBlockFields(
2305             member1, member2, webglCompatibility, mismatchedBlockFieldName);
2306         if (linkError != LinkMismatchError::NO_MISMATCH)
2307         {
2308             return linkError;
2309         }
2310     }
2311     return LinkMismatchError::NO_MISMATCH;
2312 }
2313 
InitializeInterfaceBlockMap(const std::vector<sh::InterfaceBlock> & interfaceBlocks,ShaderType shaderType,InterfaceBlockMap * linkedInterfaceBlocks)2314 void InitializeInterfaceBlockMap(const std::vector<sh::InterfaceBlock> &interfaceBlocks,
2315                                  ShaderType shaderType,
2316                                  InterfaceBlockMap *linkedInterfaceBlocks)
2317 {
2318     ASSERT(linkedInterfaceBlocks);
2319 
2320     for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
2321     {
2322         (*linkedInterfaceBlocks)[interfaceBlock.name] = std::make_pair(shaderType, &interfaceBlock);
2323     }
2324 }
2325 
ValidateGraphicsInterfaceBlocksPerShader(const std::vector<sh::InterfaceBlock> & interfaceBlocksToLink,ShaderType shaderType,bool webglCompatibility,InterfaceBlockMap * linkedBlocks,InfoLog & infoLog)2326 bool ValidateGraphicsInterfaceBlocksPerShader(
2327     const std::vector<sh::InterfaceBlock> &interfaceBlocksToLink,
2328     ShaderType shaderType,
2329     bool webglCompatibility,
2330     InterfaceBlockMap *linkedBlocks,
2331     InfoLog &infoLog)
2332 {
2333     ASSERT(linkedBlocks);
2334 
2335     for (const sh::InterfaceBlock &block : interfaceBlocksToLink)
2336     {
2337         const auto &entry = linkedBlocks->find(block.name);
2338         if (entry != linkedBlocks->end())
2339         {
2340             const sh::InterfaceBlock &linkedBlock = *(entry->second.second);
2341             std::string mismatchedStructFieldName;
2342             LinkMismatchError linkError = AreMatchingInterfaceBlocks(
2343                 block, linkedBlock, webglCompatibility, &mismatchedStructFieldName);
2344             if (linkError != LinkMismatchError::NO_MISMATCH)
2345             {
2346                 LogLinkMismatch(infoLog, block.name, GetInterfaceBlockTypeString(block.blockType),
2347                                 linkError, mismatchedStructFieldName, entry->second.first,
2348                                 shaderType);
2349                 return false;
2350             }
2351         }
2352         else
2353         {
2354             (*linkedBlocks)[block.name] = std::make_pair(shaderType, &block);
2355         }
2356     }
2357 
2358     return true;
2359 }
2360 
ValidateInterfaceBlocksMatch(GLuint numShadersHasInterfaceBlocks,const ShaderMap<const std::vector<sh::InterfaceBlock> * > & shaderInterfaceBlocks,InfoLog & infoLog,bool webglCompatibility,InterfaceBlockMap * instancelessInterfaceBlocksFields)2361 bool ValidateInterfaceBlocksMatch(
2362     GLuint numShadersHasInterfaceBlocks,
2363     const ShaderMap<const std::vector<sh::InterfaceBlock> *> &shaderInterfaceBlocks,
2364     InfoLog &infoLog,
2365     bool webglCompatibility,
2366     InterfaceBlockMap *instancelessInterfaceBlocksFields)
2367 {
2368     for (ShaderType shaderType : kAllGraphicsShaderTypes)
2369     {
2370         // Validate that instanceless blocks of different names don't have fields of the same name.
2371         if (shaderInterfaceBlocks[shaderType] &&
2372             !ValidateInstancelessGraphicsInterfaceBlocksPerShader(
2373                 *shaderInterfaceBlocks[shaderType], shaderType, instancelessInterfaceBlocksFields,
2374                 infoLog))
2375         {
2376             return false;
2377         }
2378     }
2379 
2380     if (numShadersHasInterfaceBlocks < 2u)
2381     {
2382         return true;
2383     }
2384 
2385     ASSERT(!shaderInterfaceBlocks[ShaderType::Compute]);
2386 
2387     // Check that interface blocks defined in the graphics shaders are identical
2388 
2389     InterfaceBlockMap linkedInterfaceBlocks;
2390 
2391     bool interfaceBlockMapInitialized = false;
2392     for (ShaderType shaderType : kAllGraphicsShaderTypes)
2393     {
2394         if (!shaderInterfaceBlocks[shaderType])
2395         {
2396             continue;
2397         }
2398 
2399         if (!interfaceBlockMapInitialized)
2400         {
2401             InitializeInterfaceBlockMap(*shaderInterfaceBlocks[shaderType], shaderType,
2402                                         &linkedInterfaceBlocks);
2403             interfaceBlockMapInitialized = true;
2404         }
2405         else if (!ValidateGraphicsInterfaceBlocksPerShader(*shaderInterfaceBlocks[shaderType],
2406                                                            shaderType, webglCompatibility,
2407                                                            &linkedInterfaceBlocks, infoLog))
2408         {
2409             return false;
2410         }
2411     }
2412 
2413     return true;
2414 }
2415 
LinkValidateProgramInterfaceBlocks(const Caps & caps,const Version & clientVersion,bool webglCompatibility,ShaderBitSet activeProgramStages,const ProgramLinkedResources & resources,InfoLog & infoLog,GLuint * combinedShaderStorageBlocksCountOut)2416 bool LinkValidateProgramInterfaceBlocks(const Caps &caps,
2417                                         const Version &clientVersion,
2418                                         bool webglCompatibility,
2419                                         ShaderBitSet activeProgramStages,
2420                                         const ProgramLinkedResources &resources,
2421                                         InfoLog &infoLog,
2422                                         GLuint *combinedShaderStorageBlocksCountOut)
2423 {
2424     ASSERT(combinedShaderStorageBlocksCountOut);
2425 
2426     GLuint combinedUniformBlocksCount                                         = 0u;
2427     GLuint numShadersHasUniformBlocks                                         = 0u;
2428     ShaderMap<const std::vector<sh::InterfaceBlock> *> allShaderUniformBlocks = {};
2429     InterfaceBlockMap instancelessInterfaceBlocksFields;
2430 
2431     for (ShaderType shaderType : activeProgramStages)
2432     {
2433         const std::vector<sh::InterfaceBlock> &uniformBlocks =
2434             resources.uniformBlockLinker.getShaderBlocks(shaderType);
2435         if (!uniformBlocks.empty())
2436         {
2437             if (!ValidateInterfaceBlocksCount(
2438                     static_cast<GLuint>(caps.maxShaderUniformBlocks[shaderType]), uniformBlocks,
2439                     shaderType, sh::BlockType::kBlockUniform, &combinedUniformBlocksCount, infoLog))
2440             {
2441                 return false;
2442             }
2443 
2444             allShaderUniformBlocks[shaderType] = &uniformBlocks;
2445             ++numShadersHasUniformBlocks;
2446         }
2447     }
2448 
2449     if (combinedUniformBlocksCount > static_cast<GLuint>(caps.maxCombinedUniformBlocks))
2450     {
2451         infoLog << "The sum of the number of active uniform blocks exceeds "
2452                    "MAX_COMBINED_UNIFORM_BLOCKS ("
2453                 << caps.maxCombinedUniformBlocks << ").";
2454         return false;
2455     }
2456 
2457     if (!ValidateInterfaceBlocksMatch(numShadersHasUniformBlocks, allShaderUniformBlocks, infoLog,
2458                                       webglCompatibility, &instancelessInterfaceBlocksFields))
2459     {
2460         return false;
2461     }
2462 
2463     if (clientVersion >= Version(3, 1))
2464     {
2465         *combinedShaderStorageBlocksCountOut                                      = 0u;
2466         GLuint numShadersHasShaderStorageBlocks                                   = 0u;
2467         ShaderMap<const std::vector<sh::InterfaceBlock> *> allShaderStorageBlocks = {};
2468         for (ShaderType shaderType : activeProgramStages)
2469         {
2470             const std::vector<sh::InterfaceBlock> &shaderStorageBlocks =
2471                 resources.shaderStorageBlockLinker.getShaderBlocks(shaderType);
2472             if (!shaderStorageBlocks.empty())
2473             {
2474                 if (!ValidateInterfaceBlocksCount(
2475                         static_cast<GLuint>(caps.maxShaderStorageBlocks[shaderType]),
2476                         shaderStorageBlocks, shaderType, sh::BlockType::kBlockBuffer,
2477                         combinedShaderStorageBlocksCountOut, infoLog))
2478                 {
2479                     return false;
2480                 }
2481 
2482                 allShaderStorageBlocks[shaderType] = &shaderStorageBlocks;
2483                 ++numShadersHasShaderStorageBlocks;
2484             }
2485         }
2486 
2487         if (*combinedShaderStorageBlocksCountOut >
2488             static_cast<GLuint>(caps.maxCombinedShaderStorageBlocks))
2489         {
2490             infoLog << "The sum of the number of active shader storage blocks exceeds "
2491                        "MAX_COMBINED_SHADER_STORAGE_BLOCKS ("
2492                     << caps.maxCombinedShaderStorageBlocks << ").";
2493             return false;
2494         }
2495 
2496         if (!ValidateInterfaceBlocksMatch(numShadersHasShaderStorageBlocks, allShaderStorageBlocks,
2497                                           infoLog, webglCompatibility,
2498                                           &instancelessInterfaceBlocksFields))
2499         {
2500             return false;
2501         }
2502     }
2503 
2504     return true;
2505 }
2506 
2507 }  // namespace gl
2508