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