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