• 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 
88 using ShaderUniform = std::pair<ShaderType, const sh::ShaderVariable *>;
89 
ValidateGraphicsUniformsPerShader(Shader * shaderToLink,bool extendLinkedUniforms,std::map<std::string,ShaderUniform> * linkedUniforms,InfoLog & infoLog)90 bool ValidateGraphicsUniformsPerShader(Shader *shaderToLink,
91                                        bool extendLinkedUniforms,
92                                        std::map<std::string, ShaderUniform> *linkedUniforms,
93                                        InfoLog &infoLog)
94 {
95     ASSERT(shaderToLink && linkedUniforms);
96 
97     for (const sh::ShaderVariable &uniform : shaderToLink->getUniforms())
98     {
99         const auto &entry = linkedUniforms->find(uniform.name);
100         if (entry != linkedUniforms->end())
101         {
102             const sh::ShaderVariable &linkedUniform = *(entry->second.second);
103             std::string mismatchedStructFieldName;
104             LinkMismatchError linkError =
105                 LinkValidateUniforms(uniform, linkedUniform, &mismatchedStructFieldName);
106             if (linkError != LinkMismatchError::NO_MISMATCH)
107             {
108                 LogLinkMismatch(infoLog, uniform.name, "uniform", linkError,
109                                 mismatchedStructFieldName, entry->second.first,
110                                 shaderToLink->getType());
111                 return false;
112             }
113         }
114         else if (extendLinkedUniforms)
115         {
116             (*linkedUniforms)[uniform.name] = std::make_pair(shaderToLink->getType(), &uniform);
117         }
118     }
119 
120     return true;
121 }
122 
GetMaximumShaderUniformVectors(ShaderType shaderType,const Caps & caps)123 GLuint GetMaximumShaderUniformVectors(ShaderType shaderType, const Caps &caps)
124 {
125     switch (shaderType)
126     {
127         case ShaderType::Vertex:
128             return static_cast<GLuint>(caps.maxVertexUniformVectors);
129         case ShaderType::Fragment:
130             return static_cast<GLuint>(caps.maxFragmentUniformVectors);
131 
132         case ShaderType::Compute:
133         case ShaderType::Geometry:
134         case ShaderType::TessControl:
135         case ShaderType::TessEvaluation:
136             return static_cast<GLuint>(caps.maxShaderUniformComponents[shaderType]) / 4;
137 
138         default:
139             UNREACHABLE();
140             return 0u;
141     }
142 }
143 
144 enum class UniformType : uint8_t
145 {
146     Variable      = 0,
147     Sampler       = 1,
148     Image         = 2,
149     AtomicCounter = 3,
150 
151     InvalidEnum = 4,
152     EnumCount   = 4,
153 };
154 
GetUniformResourceNameString(UniformType uniformType)155 const char *GetUniformResourceNameString(UniformType uniformType)
156 {
157     switch (uniformType)
158     {
159         case UniformType::Variable:
160             return "uniform";
161         case UniformType::Sampler:
162             return "texture image unit";
163         case UniformType::Image:
164             return "image uniform";
165         case UniformType::AtomicCounter:
166             return "atomic counter";
167         default:
168             UNREACHABLE();
169             return "";
170     }
171 }
172 
GetUniformResourceLimitName(ShaderType shaderType,UniformType uniformType)173 std::string GetUniformResourceLimitName(ShaderType shaderType, UniformType uniformType)
174 {
175     // Special case: MAX_TEXTURE_IMAGE_UNITS (no "MAX_FRAGMENT_TEXTURE_IMAGE_UNITS")
176     if (shaderType == ShaderType::Fragment && uniformType == UniformType::Sampler)
177     {
178         return "MAX_TEXTURE_IMAGE_UNITS";
179     }
180 
181     std::ostringstream ostream;
182     ostream << "MAX_" << GetShaderTypeString(shaderType) << "_";
183 
184     switch (uniformType)
185     {
186         case UniformType::Variable:
187             // For vertex and fragment shaders, ES 2.0 only defines MAX_VERTEX_UNIFORM_VECTORS and
188             // MAX_FRAGMENT_UNIFORM_VECTORS ([OpenGL ES 2.0] Table 6.20).
189             if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
190             {
191                 ostream << "UNIFORM_VECTORS";
192                 break;
193             }
194             // For compute and geometry shaders, there are no definitions on
195             // "MAX_COMPUTE_UNIFORM_VECTORS" or "MAX_GEOMETRY_UNIFORM_VECTORS_EXT"
196             // ([OpenGL ES 3.1] Table 20.45, [EXT_geometry_shader] Table 20.43gs).
197             else
198             {
199                 ostream << "UNIFORM_COMPONENTS";
200             }
201             break;
202         case UniformType::Sampler:
203             ostream << "TEXTURE_IMAGE_UNITS";
204             break;
205         case UniformType::Image:
206             ostream << "IMAGE_UNIFORMS";
207             break;
208         case UniformType::AtomicCounter:
209             ostream << "ATOMIC_COUNTERS";
210             break;
211         default:
212             UNREACHABLE();
213             return "";
214     }
215 
216     if (shaderType == ShaderType::Geometry)
217     {
218         ostream << "_EXT";
219     }
220 
221     return ostream.str();
222 }
223 
LogUniformsExceedLimit(ShaderType shaderType,UniformType uniformType,GLuint limit,InfoLog & infoLog)224 void LogUniformsExceedLimit(ShaderType shaderType,
225                             UniformType uniformType,
226                             GLuint limit,
227                             InfoLog &infoLog)
228 {
229     infoLog << GetShaderTypeString(shaderType) << " shader "
230             << GetUniformResourceNameString(uniformType) << "s count exceeds "
231             << GetUniformResourceLimitName(shaderType, uniformType) << "(" << limit << ")";
232 }
233 
234 // The purpose of this visitor is to capture the uniforms in a uniform block. Each new uniform is
235 // added to "uniformsOut".
236 class UniformBlockEncodingVisitor : public sh::VariableNameVisitor
237 {
238   public:
UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<LinkedUniform> * uniformsOut,ShaderType shaderType,int blockIndex)239     UniformBlockEncodingVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
240                                 const std::string &namePrefix,
241                                 const std::string &mappedNamePrefix,
242                                 std::vector<LinkedUniform> *uniformsOut,
243                                 ShaderType shaderType,
244                                 int blockIndex)
245         : sh::VariableNameVisitor(namePrefix, mappedNamePrefix),
246           mGetMemberInfo(getMemberInfo),
247           mUniformsOut(uniformsOut),
248           mShaderType(shaderType),
249           mBlockIndex(blockIndex)
250     {}
251 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)252     void visitNamedVariable(const sh::ShaderVariable &variable,
253                             bool isRowMajor,
254                             const std::string &name,
255                             const std::string &mappedName,
256                             const std::vector<unsigned int> &arraySizes) override
257     {
258         // If getBlockMemberInfo returns false, the variable is optimized out.
259         sh::BlockMemberInfo variableInfo;
260         if (!mGetMemberInfo(name, mappedName, &variableInfo))
261             return;
262 
263         std::string nameWithArrayIndex       = name;
264         std::string mappedNameWithArrayIndex = mappedName;
265 
266         if (variable.isArray())
267         {
268             nameWithArrayIndex += "[0]";
269             mappedNameWithArrayIndex += "[0]";
270         }
271 
272         if (mBlockIndex == -1)
273         {
274             SetActive(mUniformsOut, nameWithArrayIndex, mShaderType, variable.active);
275             return;
276         }
277 
278         LinkedUniform newUniform(variable.type, variable.precision, nameWithArrayIndex,
279                                  variable.arraySizes, -1, -1, -1, mBlockIndex, variableInfo);
280         newUniform.mappedName = mappedNameWithArrayIndex;
281         newUniform.setActive(mShaderType, variable.active);
282 
283         // Since block uniforms have no location, we don't need to store them in the uniform
284         // locations list.
285         mUniformsOut->push_back(newUniform);
286     }
287 
288   private:
289     const GetBlockMemberInfoFunc &mGetMemberInfo;
290     std::vector<LinkedUniform> *mUniformsOut;
291     const ShaderType mShaderType;
292     const int mBlockIndex;
293 };
294 
295 // The purpose of this visitor is to capture the buffer variables in a shader storage block. Each
296 // new buffer variable is stored in "bufferVariablesOut".
297 class ShaderStorageBlockVisitor : public sh::BlockEncoderVisitor
298 {
299   public:
ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,std::vector<BufferVariable> * bufferVariablesOut,ShaderType shaderType,int blockIndex)300     ShaderStorageBlockVisitor(const GetBlockMemberInfoFunc &getMemberInfo,
301                               const std::string &namePrefix,
302                               const std::string &mappedNamePrefix,
303                               std::vector<BufferVariable> *bufferVariablesOut,
304                               ShaderType shaderType,
305                               int blockIndex)
306         : sh::BlockEncoderVisitor(namePrefix, mappedNamePrefix, &mStubEncoder),
307           mGetMemberInfo(getMemberInfo),
308           mBufferVariablesOut(bufferVariablesOut),
309           mShaderType(shaderType),
310           mBlockIndex(blockIndex)
311     {}
312 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)313     void visitNamedVariable(const sh::ShaderVariable &variable,
314                             bool isRowMajor,
315                             const std::string &name,
316                             const std::string &mappedName,
317                             const std::vector<unsigned int> &arraySizes) override
318     {
319         if (mSkipEnabled)
320             return;
321 
322         // If getBlockMemberInfo returns false, the variable is optimized out.
323         sh::BlockMemberInfo variableInfo;
324         if (!mGetMemberInfo(name, mappedName, &variableInfo))
325             return;
326 
327         std::string nameWithArrayIndex       = name;
328         std::string mappedNameWithArrayIndex = mappedName;
329 
330         if (variable.isArray())
331         {
332             nameWithArrayIndex += "[0]";
333             mappedNameWithArrayIndex += "[0]";
334         }
335 
336         if (mBlockIndex == -1)
337         {
338             SetActive(mBufferVariablesOut, nameWithArrayIndex, mShaderType, variable.active);
339             return;
340         }
341 
342         BufferVariable newBufferVariable(variable.type, variable.precision, nameWithArrayIndex,
343                                          variable.arraySizes, mBlockIndex, variableInfo);
344         newBufferVariable.mappedName = mappedNameWithArrayIndex;
345         newBufferVariable.setActive(mShaderType, variable.active);
346 
347         newBufferVariable.topLevelArraySize = mTopLevelArraySize;
348 
349         mBufferVariablesOut->push_back(newBufferVariable);
350     }
351 
352   private:
353     const GetBlockMemberInfoFunc &mGetMemberInfo;
354     std::vector<BufferVariable> *mBufferVariablesOut;
355     const ShaderType mShaderType;
356     const int mBlockIndex;
357     sh::StubBlockEncoder mStubEncoder;
358 };
359 
360 struct ShaderUniformCount
361 {
362     unsigned int vectorCount        = 0;
363     unsigned int samplerCount       = 0;
364     unsigned int imageCount         = 0;
365     unsigned int atomicCounterCount = 0;
366     unsigned int fragmentInOutCount = 0;
367 };
368 
operator +=(ShaderUniformCount & lhs,const ShaderUniformCount & rhs)369 ShaderUniformCount &operator+=(ShaderUniformCount &lhs, const ShaderUniformCount &rhs)
370 {
371     lhs.vectorCount += rhs.vectorCount;
372     lhs.samplerCount += rhs.samplerCount;
373     lhs.imageCount += rhs.imageCount;
374     lhs.atomicCounterCount += rhs.atomicCounterCount;
375     lhs.fragmentInOutCount += rhs.fragmentInOutCount;
376     return lhs;
377 }
378 
379 // The purpose of this visitor is to flatten struct and array uniforms into a list of singleton
380 // uniforms. They are stored in separate lists by uniform type so they can be sorted in order.
381 // Counts for each uniform category are stored and can be queried with "getCounts".
382 class FlattenUniformVisitor : public sh::VariableNameVisitor
383 {
384   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)385     FlattenUniformVisitor(ShaderType shaderType,
386                           const sh::ShaderVariable &uniform,
387                           std::vector<LinkedUniform> *uniforms,
388                           std::vector<LinkedUniform> *samplerUniforms,
389                           std::vector<LinkedUniform> *imageUniforms,
390                           std::vector<LinkedUniform> *atomicCounterUniforms,
391                           std::vector<LinkedUniform> *inputAttachmentUniforms,
392                           std::vector<UnusedUniform> *unusedUniforms)
393         : sh::VariableNameVisitor("", ""),
394           mShaderType(shaderType),
395           mMarkActive(uniform.active),
396           mMarkStaticUse(uniform.staticUse),
397           mBinding(uniform.binding),
398           mOffset(uniform.offset),
399           mLocation(uniform.location),
400           mUniforms(uniforms),
401           mSamplerUniforms(samplerUniforms),
402           mImageUniforms(imageUniforms),
403           mAtomicCounterUniforms(atomicCounterUniforms),
404           mInputAttachmentUniforms(inputAttachmentUniforms),
405           mUnusedUniforms(unusedUniforms)
406     {}
407 
visitNamedOpaqueObject(const sh::ShaderVariable & variable,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)408     void visitNamedOpaqueObject(const sh::ShaderVariable &variable,
409                                 const std::string &name,
410                                 const std::string &mappedName,
411                                 const std::vector<unsigned int> &arraySizes) override
412     {
413         visitNamedVariable(variable, false, name, mappedName, arraySizes);
414     }
415 
visitNamedVariable(const sh::ShaderVariable & variable,bool isRowMajor,const std::string & name,const std::string & mappedName,const std::vector<unsigned int> & arraySizes)416     void visitNamedVariable(const sh::ShaderVariable &variable,
417                             bool isRowMajor,
418                             const std::string &name,
419                             const std::string &mappedName,
420                             const std::vector<unsigned int> &arraySizes) override
421     {
422         bool isSampler                          = IsSamplerType(variable.type);
423         bool isImage                            = IsImageType(variable.type);
424         bool isAtomicCounter                    = IsAtomicCounterType(variable.type);
425         bool isFragmentInOut                    = variable.isFragmentInOut;
426         std::vector<LinkedUniform> *uniformList = mUniforms;
427         if (isSampler)
428         {
429             uniformList = mSamplerUniforms;
430         }
431         else if (isImage)
432         {
433             uniformList = mImageUniforms;
434         }
435         else if (isAtomicCounter)
436         {
437             uniformList = mAtomicCounterUniforms;
438         }
439         else if (isFragmentInOut)
440         {
441             uniformList = mInputAttachmentUniforms;
442         }
443 
444         std::string fullNameWithArrayIndex(name);
445         std::string fullMappedNameWithArrayIndex(mappedName);
446 
447         if (variable.isArray())
448         {
449             // We're following the GLES 3.1 November 2016 spec section 7.3.1.1 Naming Active
450             // Resources and including [0] at the end of array variable names.
451             fullNameWithArrayIndex += "[0]";
452             fullMappedNameWithArrayIndex += "[0]";
453         }
454 
455         LinkedUniform *existingUniform = FindUniform(*uniformList, fullNameWithArrayIndex);
456         if (existingUniform)
457         {
458             if (getBinding() != -1)
459             {
460                 existingUniform->binding = getBinding();
461             }
462             if (getOffset() != -1)
463             {
464                 existingUniform->offset = getOffset();
465             }
466             if (mLocation != -1)
467             {
468                 existingUniform->location = mLocation;
469             }
470             if (mMarkActive)
471             {
472                 existingUniform->active = true;
473                 existingUniform->setActive(mShaderType, true);
474             }
475             if (mMarkStaticUse)
476             {
477                 existingUniform->staticUse = true;
478             }
479         }
480         else
481         {
482             LinkedUniform linkedUniform(variable.type, variable.precision, fullNameWithArrayIndex,
483                                         variable.arraySizes, getBinding(), getOffset(), mLocation,
484                                         -1, sh::kDefaultBlockMemberInfo);
485             linkedUniform.mappedName          = fullMappedNameWithArrayIndex;
486             linkedUniform.active              = mMarkActive;
487             linkedUniform.staticUse           = mMarkStaticUse;
488             linkedUniform.outerArraySizes     = arraySizes;
489             linkedUniform.texelFetchStaticUse = variable.texelFetchStaticUse;
490             linkedUniform.imageUnitFormat     = variable.imageUnitFormat;
491             linkedUniform.isFragmentInOut     = variable.isFragmentInOut;
492             if (variable.hasParentArrayIndex())
493             {
494                 linkedUniform.setParentArrayIndex(variable.parentArrayIndex());
495             }
496             if (mMarkActive)
497             {
498                 linkedUniform.setActive(mShaderType, true);
499             }
500             else
501             {
502                 mUnusedUniforms->emplace_back(
503                     linkedUniform.name, linkedUniform.isSampler(), linkedUniform.isImage(),
504                     linkedUniform.isAtomicCounter(), linkedUniform.isFragmentInOut);
505             }
506 
507             uniformList->push_back(linkedUniform);
508         }
509 
510         unsigned int elementCount = variable.getBasicTypeElementCount();
511 
512         // Samplers and images aren't "real" uniforms, so they don't count towards register usage.
513         // Likewise, don't count "real" uniforms towards opaque count.
514 
515         if (!IsOpaqueType(variable.type) && !isFragmentInOut)
516         {
517             mUniformCount.vectorCount += VariableRegisterCount(variable.type) * elementCount;
518         }
519 
520         mUniformCount.samplerCount += (isSampler ? elementCount : 0);
521         mUniformCount.imageCount += (isImage ? elementCount : 0);
522         mUniformCount.atomicCounterCount += (isAtomicCounter ? elementCount : 0);
523         mUniformCount.fragmentInOutCount += (isFragmentInOut ? elementCount : 0);
524 
525         if (mLocation != -1)
526         {
527             mLocation += elementCount;
528         }
529     }
530 
enterStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)531     void enterStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
532     {
533         mStructStackSize++;
534         sh::VariableNameVisitor::enterStructAccess(structVar, isRowMajor);
535     }
536 
exitStructAccess(const sh::ShaderVariable & structVar,bool isRowMajor)537     void exitStructAccess(const sh::ShaderVariable &structVar, bool isRowMajor) override
538     {
539         mStructStackSize--;
540         sh::VariableNameVisitor::exitStructAccess(structVar, isRowMajor);
541     }
542 
getCounts() const543     ShaderUniformCount getCounts() const { return mUniformCount; }
544 
545   private:
getBinding() const546     int getBinding() const { return mStructStackSize == 0 ? mBinding : -1; }
getOffset() const547     int getOffset() const { return mStructStackSize == 0 ? mOffset : -1; }
548 
549     ShaderType mShaderType;
550 
551     // Active and StaticUse are given separately because they are tracked at struct granularity.
552     bool mMarkActive;
553     bool mMarkStaticUse;
554     int mBinding;
555     int mOffset;
556     int mLocation;
557     std::vector<LinkedUniform> *mUniforms;
558     std::vector<LinkedUniform> *mSamplerUniforms;
559     std::vector<LinkedUniform> *mImageUniforms;
560     std::vector<LinkedUniform> *mAtomicCounterUniforms;
561     std::vector<LinkedUniform> *mInputAttachmentUniforms;
562     std::vector<UnusedUniform> *mUnusedUniforms;
563     ShaderUniformCount mUniformCount;
564     unsigned int mStructStackSize = 0;
565 };
566 
567 class InterfaceBlockInfo final : angle::NonCopyable
568 {
569   public:
InterfaceBlockInfo(CustomBlockLayoutEncoderFactory * customEncoderFactory)570     InterfaceBlockInfo(CustomBlockLayoutEncoderFactory *customEncoderFactory)
571         : mCustomEncoderFactory(customEncoderFactory)
572     {}
573 
574     void getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks);
575 
576     bool getBlockSize(const std::string &name, const std::string &mappedName, size_t *sizeOut);
577     bool getBlockMemberInfo(const std::string &name,
578                             const std::string &mappedName,
579                             sh::BlockMemberInfo *infoOut);
580 
581   private:
582     size_t getBlockInfo(const sh::InterfaceBlock &interfaceBlock);
583 
584     std::map<std::string, size_t> mBlockSizes;
585     sh::BlockLayoutMap mBlockLayout;
586     // Based on the interface block layout, the std140 or std430 encoders are used.  On some
587     // platforms (currently only D3D), there could be another non-standard encoder used.
588     CustomBlockLayoutEncoderFactory *mCustomEncoderFactory;
589 };
590 
getShaderBlockInfo(const std::vector<sh::InterfaceBlock> & interfaceBlocks)591 void InterfaceBlockInfo::getShaderBlockInfo(const std::vector<sh::InterfaceBlock> &interfaceBlocks)
592 {
593     for (const sh::InterfaceBlock &interfaceBlock : interfaceBlocks)
594     {
595         if (!IsActiveInterfaceBlock(interfaceBlock))
596             continue;
597 
598         if (mBlockSizes.count(interfaceBlock.name) > 0)
599             continue;
600 
601         size_t dataSize                  = getBlockInfo(interfaceBlock);
602         mBlockSizes[interfaceBlock.name] = dataSize;
603     }
604 }
605 
getBlockInfo(const sh::InterfaceBlock & interfaceBlock)606 size_t InterfaceBlockInfo::getBlockInfo(const sh::InterfaceBlock &interfaceBlock)
607 {
608     ASSERT(IsActiveInterfaceBlock(interfaceBlock));
609 
610     // define member uniforms
611     sh::Std140BlockEncoder std140Encoder;
612     sh::Std430BlockEncoder std430Encoder;
613     sh::BlockLayoutEncoder *customEncoder = nullptr;
614     sh::BlockLayoutEncoder *encoder       = nullptr;
615 
616     if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD140)
617     {
618         encoder = &std140Encoder;
619     }
620     else if (interfaceBlock.layout == sh::BLOCKLAYOUT_STD430)
621     {
622         encoder = &std430Encoder;
623     }
624     else if (mCustomEncoderFactory)
625     {
626         encoder = customEncoder = mCustomEncoderFactory->makeEncoder();
627     }
628     else
629     {
630         UNREACHABLE();
631         return 0;
632     }
633 
634     sh::GetInterfaceBlockInfo(interfaceBlock.fields, interfaceBlock.fieldPrefix(), encoder,
635                               &mBlockLayout);
636 
637     size_t offset = encoder->getCurrentOffset();
638 
639     SafeDelete(customEncoder);
640 
641     return offset;
642 }
643 
getBlockSize(const std::string & name,const std::string & mappedName,size_t * sizeOut)644 bool InterfaceBlockInfo::getBlockSize(const std::string &name,
645                                       const std::string &mappedName,
646                                       size_t *sizeOut)
647 {
648     size_t nameLengthWithoutArrayIndex;
649     ParseArrayIndex(name, &nameLengthWithoutArrayIndex);
650     std::string baseName = name.substr(0u, nameLengthWithoutArrayIndex);
651     auto sizeIter        = mBlockSizes.find(baseName);
652     if (sizeIter == mBlockSizes.end())
653     {
654         *sizeOut = 0;
655         return false;
656     }
657 
658     *sizeOut = sizeIter->second;
659     return true;
660 }
661 
getBlockMemberInfo(const std::string & name,const std::string & mappedName,sh::BlockMemberInfo * infoOut)662 bool InterfaceBlockInfo::getBlockMemberInfo(const std::string &name,
663                                             const std::string &mappedName,
664                                             sh::BlockMemberInfo *infoOut)
665 {
666     auto infoIter = mBlockLayout.find(name);
667     if (infoIter == mBlockLayout.end())
668     {
669         *infoOut = sh::kDefaultBlockMemberInfo;
670         return false;
671     }
672 
673     *infoOut = infoIter->second;
674     return true;
675 }
676 
GetFilteredVaryings(const std::vector<sh::ShaderVariable> & varyings,std::vector<const sh::ShaderVariable * > * filteredVaryingsOut)677 void GetFilteredVaryings(const std::vector<sh::ShaderVariable> &varyings,
678                          std::vector<const sh::ShaderVariable *> *filteredVaryingsOut)
679 {
680     for (const sh::ShaderVariable &varying : varyings)
681     {
682         // Built-in varyings obey special rules
683         if (varying.isBuiltIn())
684         {
685             continue;
686         }
687 
688         filteredVaryingsOut->push_back(&varying);
689     }
690 }
691 
LinkValidateVaryings(const sh::ShaderVariable & outputVarying,const sh::ShaderVariable & inputVarying,int shaderVersion,ShaderType frontShaderType,ShaderType backShaderType,bool isSeparable,std::string * mismatchedStructFieldName)692 LinkMismatchError LinkValidateVaryings(const sh::ShaderVariable &outputVarying,
693                                        const sh::ShaderVariable &inputVarying,
694                                        int shaderVersion,
695                                        ShaderType frontShaderType,
696                                        ShaderType backShaderType,
697                                        bool isSeparable,
698                                        std::string *mismatchedStructFieldName)
699 {
700     // [ES 3.2 spec] 7.4.1 Shader Interface Matching:
701     // Tessellation control shader per-vertex output variables and blocks and tessellation control,
702     // tessellation evaluation, and geometry shader per-vertex input variables and blocks are
703     // required to be declared as arrays, with each element representing input or output values for
704     // a single vertex of a multi-vertex primitive. For the purposes of interface matching, such
705     // variables and blocks are treated as though they were not declared as arrays.
706     bool treatOutputAsNonArray =
707         (frontShaderType == ShaderType::TessControl && !outputVarying.isPatch);
708     bool treatInputAsNonArray =
709         ((backShaderType == ShaderType::TessControl ||
710           backShaderType == ShaderType::TessEvaluation || backShaderType == ShaderType::Geometry) &&
711          !inputVarying.isPatch);
712 
713     // Skip the validation on the array sizes between a vertex output varying and a geometry input
714     // varying as it has been done before.
715     bool validatePrecision      = isSeparable && (shaderVersion > 100);
716     LinkMismatchError linkError = LinkValidateProgramVariables(
717         outputVarying, inputVarying, validatePrecision, treatOutputAsNonArray, treatInputAsNonArray,
718         mismatchedStructFieldName);
719     if (linkError != LinkMismatchError::NO_MISMATCH)
720     {
721         return linkError;
722     }
723 
724     // Explicit locations must match if the names match.
725     if (outputVarying.isSameNameAtLinkTime(inputVarying) &&
726         outputVarying.location != inputVarying.location)
727     {
728         return LinkMismatchError::LOCATION_MISMATCH;
729     }
730 
731     if (!sh::InterpolationTypesMatch(outputVarying.interpolation, inputVarying.interpolation))
732     {
733         return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
734     }
735 
736     if (shaderVersion == 100 && outputVarying.isInvariant != inputVarying.isInvariant)
737     {
738         return LinkMismatchError::INVARIANCE_MISMATCH;
739     }
740 
741     return LinkMismatchError::NO_MISMATCH;
742 }
743 
DoShaderVariablesMatch(int frontShaderVersion,ShaderType frontShaderType,ShaderType backShaderType,const sh::ShaderVariable & input,const sh::ShaderVariable & output,bool isSeparable,gl::InfoLog & infoLog)744 bool DoShaderVariablesMatch(int frontShaderVersion,
745                             ShaderType frontShaderType,
746                             ShaderType backShaderType,
747                             const sh::ShaderVariable &input,
748                             const sh::ShaderVariable &output,
749                             bool isSeparable,
750                             gl::InfoLog &infoLog)
751 {
752     bool namesMatch     = input.isSameNameAtLinkTime(output);
753     bool locationsMatch = input.location != -1 && input.location == output.location;
754 
755     // An output block is considered to match an input block in the subsequent
756     // shader if the two blocks have the same block name, and the members of the
757     // block match exactly in name, type, qualification, and declaration order.
758     //
759     // - For the purposes of shader interface matching, the gl_PointSize
760     //   member of the intrinsically declared gl_PerVertex shader interface
761     //   block is ignored.
762     // - Output blocks that do not match in name, but have a location and match
763     //   in every other way listed above may be considered to match by some
764     //   implementations, but not all - so this behaviour should not be relied
765     //   upon.
766 
767     // An output variable is considered to match an input variable in the subsequent
768     // shader if:
769     //
770     // - the two variables match in name, type, and qualification; or
771     // - the two variables are declared with the same location qualifier and
772     //   match in type and qualification.
773 
774     if (namesMatch || locationsMatch)
775     {
776         std::string mismatchedStructFieldName;
777         LinkMismatchError linkError =
778             LinkValidateVaryings(output, input, frontShaderVersion, frontShaderType, backShaderType,
779                                  isSeparable, &mismatchedStructFieldName);
780         if (linkError != LinkMismatchError::NO_MISMATCH)
781         {
782             LogLinkMismatch(infoLog, input.name, "varying", linkError, mismatchedStructFieldName,
783                             frontShaderType, backShaderType);
784             return false;
785         }
786 
787         return true;
788     }
789 
790     return false;
791 }
792 }  // anonymous namespace
793 
UniformLinker(const ProgramState & state)794 UniformLinker::UniformLinker(const ProgramState &state) : mState(state) {}
795 
796 UniformLinker::~UniformLinker() = default;
797 
getResults(std::vector<LinkedUniform> * uniforms,std::vector<UnusedUniform> * unusedUniforms,std::vector<VariableLocation> * uniformLocations)798 void UniformLinker::getResults(std::vector<LinkedUniform> *uniforms,
799                                std::vector<UnusedUniform> *unusedUniforms,
800                                std::vector<VariableLocation> *uniformLocations)
801 {
802     uniforms->swap(mUniforms);
803     unusedUniforms->swap(mUnusedUniforms);
804     uniformLocations->swap(mUniformLocations);
805 }
806 
link(const Caps & caps,InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)807 bool UniformLinker::link(const Caps &caps,
808                          InfoLog &infoLog,
809                          const ProgramAliasedBindings &uniformLocationBindings)
810 {
811     if (mState.getAttachedShader(ShaderType::Vertex) &&
812         mState.getAttachedShader(ShaderType::Fragment))
813     {
814         ASSERT(mState.getAttachedShader(ShaderType::Compute) == nullptr);
815         if (!validateGraphicsUniforms(infoLog))
816         {
817             return false;
818         }
819     }
820 
821     // Flatten the uniforms list (nested fields) into a simple list (no nesting).
822     // Also check the maximum uniform vector and sampler counts.
823     if (!flattenUniformsAndCheckCaps(caps, infoLog))
824     {
825         return false;
826     }
827 
828     if (!checkMaxCombinedAtomicCounters(caps, infoLog))
829     {
830         return false;
831     }
832 
833     if (!indexUniforms(infoLog, uniformLocationBindings))
834     {
835         return false;
836     }
837 
838     return true;
839 }
840 
validateGraphicsUniforms(InfoLog & infoLog) const841 bool UniformLinker::validateGraphicsUniforms(InfoLog &infoLog) const
842 {
843     // Check that uniforms defined in the graphics shaders are identical
844     std::map<std::string, ShaderUniform> linkedUniforms;
845 
846     for (const ShaderType shaderType : kAllGraphicsShaderTypes)
847     {
848         Shader *currentShader = mState.getAttachedShader(shaderType);
849         if (currentShader)
850         {
851             if (shaderType == ShaderType::Vertex)
852             {
853                 for (const sh::ShaderVariable &vertexUniform : currentShader->getUniforms())
854                 {
855                     linkedUniforms[vertexUniform.name] =
856                         std::make_pair(ShaderType::Vertex, &vertexUniform);
857                 }
858             }
859             else
860             {
861                 bool isLastShader = (shaderType == ShaderType::Fragment);
862                 if (!ValidateGraphicsUniformsPerShader(currentShader, !isLastShader,
863                                                        &linkedUniforms, infoLog))
864                 {
865                     return false;
866                 }
867             }
868         }
869     }
870 
871     return true;
872 }
873 
indexUniforms(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings)874 bool UniformLinker::indexUniforms(InfoLog &infoLog,
875                                   const ProgramAliasedBindings &uniformLocationBindings)
876 {
877     // Locations which have been allocated for an unused uniform.
878     std::set<GLuint> ignoredLocations;
879 
880     int maxUniformLocation = -1;
881 
882     // Gather uniform locations that have been set either using the bindUniformLocation API or by
883     // using a location layout qualifier and check conflicts between them.
884     if (!gatherUniformLocationsAndCheckConflicts(infoLog, uniformLocationBindings,
885                                                  &ignoredLocations, &maxUniformLocation))
886     {
887         return false;
888     }
889 
890     // Conflicts have been checked, now we can prune non-statically used uniforms. Code further down
891     // the line relies on only having statically used uniforms in mUniforms.
892     pruneUnusedUniforms();
893 
894     // Gather uniforms that have their location pre-set and uniforms that don't yet have a location.
895     std::vector<VariableLocation> unlocatedUniforms;
896     std::map<GLuint, VariableLocation> preLocatedUniforms;
897 
898     for (size_t uniformIndex = 0; uniformIndex < mUniforms.size(); uniformIndex++)
899     {
900         const LinkedUniform &uniform = mUniforms[uniformIndex];
901 
902         if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) ||
903             IsAtomicCounterType(uniform.type) || uniform.isFragmentInOut)
904         {
905             continue;
906         }
907 
908         int preSetLocation = uniformLocationBindings.getBinding(uniform);
909         int shaderLocation = uniform.location;
910 
911         if (shaderLocation != -1)
912         {
913             preSetLocation = shaderLocation;
914         }
915 
916         unsigned int elementCount = uniform.getBasicTypeElementCount();
917         for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
918         {
919             VariableLocation location(arrayIndex, static_cast<unsigned int>(uniformIndex));
920 
921             if ((arrayIndex == 0 && preSetLocation != -1) || shaderLocation != -1)
922             {
923                 int elementLocation                 = preSetLocation + arrayIndex;
924                 preLocatedUniforms[elementLocation] = location;
925             }
926             else
927             {
928                 unlocatedUniforms.push_back(location);
929             }
930         }
931     }
932 
933     // Make enough space for all uniforms, with pre-set locations or not.
934     mUniformLocations.resize(
935         std::max(unlocatedUniforms.size() + preLocatedUniforms.size() + ignoredLocations.size(),
936                  static_cast<size_t>(maxUniformLocation + 1)));
937 
938     // Assign uniforms with pre-set locations
939     for (const auto &uniform : preLocatedUniforms)
940     {
941         mUniformLocations[uniform.first] = uniform.second;
942     }
943 
944     // Assign ignored uniforms
945     for (const auto &ignoredLocation : ignoredLocations)
946     {
947         mUniformLocations[ignoredLocation].markIgnored();
948     }
949 
950     // Automatically assign locations for the rest of the uniforms
951     size_t nextUniformLocation = 0;
952     for (const auto &unlocatedUniform : unlocatedUniforms)
953     {
954         while (mUniformLocations[nextUniformLocation].used() ||
955                mUniformLocations[nextUniformLocation].ignored)
956         {
957             nextUniformLocation++;
958         }
959 
960         ASSERT(nextUniformLocation < mUniformLocations.size());
961         mUniformLocations[nextUniformLocation] = unlocatedUniform;
962         nextUniformLocation++;
963     }
964 
965     return true;
966 }
967 
gatherUniformLocationsAndCheckConflicts(InfoLog & infoLog,const ProgramAliasedBindings & uniformLocationBindings,std::set<GLuint> * ignoredLocations,int * maxUniformLocation)968 bool UniformLinker::gatherUniformLocationsAndCheckConflicts(
969     InfoLog &infoLog,
970     const ProgramAliasedBindings &uniformLocationBindings,
971     std::set<GLuint> *ignoredLocations,
972     int *maxUniformLocation)
973 {
974     // All the locations where another uniform can't be located.
975     std::set<GLuint> reservedLocations;
976 
977     for (const LinkedUniform &uniform : mUniforms)
978     {
979         if ((uniform.isBuiltIn() && !uniform.isEmulatedBuiltIn()) || uniform.isFragmentInOut)
980         {
981             // The uniform of the fragment inout is not a normal uniform type. So, in the case of
982             // the fragment inout, this routine should be skipped.
983             continue;
984         }
985 
986         int apiBoundLocation = uniformLocationBindings.getBinding(uniform);
987         int shaderLocation   = uniform.location;
988 
989         if (shaderLocation != -1)
990         {
991             unsigned int elementCount = uniform.getBasicTypeElementCount();
992 
993             for (unsigned int arrayIndex = 0; arrayIndex < elementCount; arrayIndex++)
994             {
995                 // GLSL ES 3.10 section 4.4.3
996                 int elementLocation = shaderLocation + arrayIndex;
997                 *maxUniformLocation = std::max(*maxUniformLocation, elementLocation);
998                 if (reservedLocations.find(elementLocation) != reservedLocations.end())
999                 {
1000                     infoLog << "Multiple uniforms bound to location " << elementLocation << ".";
1001                     return false;
1002                 }
1003                 reservedLocations.insert(elementLocation);
1004                 if (!uniform.active)
1005                 {
1006                     ignoredLocations->insert(elementLocation);
1007                 }
1008             }
1009         }
1010         else if (apiBoundLocation != -1 && uniform.staticUse)
1011         {
1012             // Only the first location is reserved even if the uniform is an array.
1013             *maxUniformLocation = std::max(*maxUniformLocation, apiBoundLocation);
1014             if (reservedLocations.find(apiBoundLocation) != reservedLocations.end())
1015             {
1016                 infoLog << "Multiple uniforms bound to location " << apiBoundLocation << ".";
1017                 return false;
1018             }
1019             reservedLocations.insert(apiBoundLocation);
1020             if (!uniform.active)
1021             {
1022                 ignoredLocations->insert(apiBoundLocation);
1023             }
1024         }
1025     }
1026 
1027     // Record the uniform locations that were bound using the API for uniforms that were not found
1028     // from the shader. Other uniforms should not be assigned to those locations.
1029     for (const auto &locationBinding : uniformLocationBindings)
1030     {
1031         GLuint location = locationBinding.second.location;
1032         if (reservedLocations.find(location) == reservedLocations.end())
1033         {
1034             ignoredLocations->insert(location);
1035             *maxUniformLocation = std::max(*maxUniformLocation, static_cast<int>(location));
1036         }
1037     }
1038 
1039     return true;
1040 }
1041 
pruneUnusedUniforms()1042 void UniformLinker::pruneUnusedUniforms()
1043 {
1044     auto uniformIter = mUniforms.begin();
1045     while (uniformIter != mUniforms.end())
1046     {
1047         if (uniformIter->active)
1048         {
1049             ++uniformIter;
1050         }
1051         else
1052         {
1053             mUnusedUniforms.emplace_back(uniformIter->name, uniformIter->isSampler(),
1054                                          uniformIter->isImage(), uniformIter->isAtomicCounter(),
1055                                          uniformIter->isFragmentInOut);
1056             uniformIter = mUniforms.erase(uniformIter);
1057         }
1058     }
1059 }
1060 
flattenUniformsAndCheckCapsForShader(Shader * shader,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)1061 bool UniformLinker::flattenUniformsAndCheckCapsForShader(
1062     Shader *shader,
1063     const Caps &caps,
1064     std::vector<LinkedUniform> &samplerUniforms,
1065     std::vector<LinkedUniform> &imageUniforms,
1066     std::vector<LinkedUniform> &atomicCounterUniforms,
1067     std::vector<LinkedUniform> &inputAttachmentUniforms,
1068     std::vector<UnusedUniform> &unusedUniforms,
1069     InfoLog &infoLog)
1070 {
1071     ShaderUniformCount shaderUniformCount;
1072     for (const sh::ShaderVariable &uniform : shader->getUniforms())
1073     {
1074         FlattenUniformVisitor flattener(shader->getType(), uniform, &mUniforms, &samplerUniforms,
1075                                         &imageUniforms, &atomicCounterUniforms,
1076                                         &inputAttachmentUniforms, &unusedUniforms);
1077         sh::TraverseShaderVariable(uniform, false, &flattener);
1078 
1079         if (uniform.active)
1080         {
1081             shaderUniformCount += flattener.getCounts();
1082         }
1083         else
1084         {
1085             unusedUniforms.emplace_back(uniform.name, IsSamplerType(uniform.type),
1086                                         IsImageType(uniform.type),
1087                                         IsAtomicCounterType(uniform.type), uniform.isFragmentInOut);
1088         }
1089     }
1090 
1091     ShaderType shaderType = shader->getType();
1092 
1093     // TODO (jiawei.shao@intel.com): check whether we need finer-grained component counting
1094     GLuint maxUniformVectorsCount = GetMaximumShaderUniformVectors(shaderType, caps);
1095     if (shaderUniformCount.vectorCount > maxUniformVectorsCount)
1096     {
1097         GLuint maxUniforms = 0u;
1098 
1099         // See comments in GetUniformResourceLimitName()
1100         if (shaderType == ShaderType::Vertex || shaderType == ShaderType::Fragment)
1101         {
1102             maxUniforms = maxUniformVectorsCount;
1103         }
1104         else
1105         {
1106             maxUniforms = maxUniformVectorsCount * 4;
1107         }
1108 
1109         LogUniformsExceedLimit(shaderType, UniformType::Variable, maxUniforms, infoLog);
1110         return false;
1111     }
1112 
1113     if (shaderUniformCount.samplerCount >
1114         static_cast<GLuint>(caps.maxShaderTextureImageUnits[shaderType]))
1115     {
1116         LogUniformsExceedLimit(shaderType, UniformType::Sampler,
1117                                caps.maxShaderTextureImageUnits[shaderType], infoLog);
1118         return false;
1119     }
1120 
1121     if (shaderUniformCount.imageCount >
1122         static_cast<GLuint>(caps.maxShaderImageUniforms[shaderType]))
1123     {
1124         LogUniformsExceedLimit(shaderType, UniformType::Image,
1125                                caps.maxShaderImageUniforms[shaderType], infoLog);
1126         return false;
1127     }
1128 
1129     if (shaderUniformCount.atomicCounterCount >
1130         static_cast<GLuint>(caps.maxShaderAtomicCounters[shaderType]))
1131     {
1132         LogUniformsExceedLimit(shaderType, UniformType::AtomicCounter,
1133                                caps.maxShaderAtomicCounters[shaderType], infoLog);
1134         return false;
1135     }
1136 
1137     return true;
1138 }
1139 
flattenUniformsAndCheckCaps(const Caps & caps,InfoLog & infoLog)1140 bool UniformLinker::flattenUniformsAndCheckCaps(const Caps &caps, InfoLog &infoLog)
1141 {
1142     std::vector<LinkedUniform> samplerUniforms;
1143     std::vector<LinkedUniform> imageUniforms;
1144     std::vector<LinkedUniform> atomicCounterUniforms;
1145     std::vector<LinkedUniform> inputAttachmentUniforms;
1146     std::vector<UnusedUniform> unusedUniforms;
1147 
1148     for (const ShaderType shaderType : AllShaderTypes())
1149     {
1150         Shader *shader = mState.getAttachedShader(shaderType);
1151         if (!shader)
1152         {
1153             continue;
1154         }
1155 
1156         if (!flattenUniformsAndCheckCapsForShader(shader, caps, samplerUniforms, imageUniforms,
1157                                                   atomicCounterUniforms, inputAttachmentUniforms,
1158                                                   unusedUniforms, infoLog))
1159         {
1160             return false;
1161         }
1162     }
1163 
1164     mUniforms.insert(mUniforms.end(), samplerUniforms.begin(), samplerUniforms.end());
1165     mUniforms.insert(mUniforms.end(), imageUniforms.begin(), imageUniforms.end());
1166     mUniforms.insert(mUniforms.end(), atomicCounterUniforms.begin(), atomicCounterUniforms.end());
1167     mUniforms.insert(mUniforms.end(), inputAttachmentUniforms.begin(),
1168                      inputAttachmentUniforms.end());
1169     mUnusedUniforms.insert(mUnusedUniforms.end(), unusedUniforms.begin(), unusedUniforms.end());
1170     return true;
1171 }
1172 
checkMaxCombinedAtomicCounters(const Caps & caps,InfoLog & infoLog)1173 bool UniformLinker::checkMaxCombinedAtomicCounters(const Caps &caps, InfoLog &infoLog)
1174 {
1175     unsigned int atomicCounterCount = 0;
1176     for (const auto &uniform : mUniforms)
1177     {
1178         if (IsAtomicCounterType(uniform.type) && uniform.active)
1179         {
1180             atomicCounterCount += uniform.getBasicTypeElementCount();
1181             if (atomicCounterCount > static_cast<GLuint>(caps.maxCombinedAtomicCounters))
1182             {
1183                 infoLog << "atomic counter count exceeds MAX_COMBINED_ATOMIC_COUNTERS"
1184                         << caps.maxCombinedAtomicCounters << ").";
1185                 return false;
1186             }
1187         }
1188     }
1189     return true;
1190 }
1191 
1192 // InterfaceBlockLinker implementation.
1193 InterfaceBlockLinker::InterfaceBlockLinker() = default;
1194 
1195 InterfaceBlockLinker::~InterfaceBlockLinker() = default;
1196 
init(std::vector<InterfaceBlock> * blocksOut,std::vector<std::string> * unusedInterfaceBlocksOut)1197 void InterfaceBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1198                                 std::vector<std::string> *unusedInterfaceBlocksOut)
1199 {
1200     mBlocksOut                = blocksOut;
1201     mUnusedInterfaceBlocksOut = unusedInterfaceBlocksOut;
1202 }
1203 
addShaderBlocks(ShaderType shaderType,const std::vector<sh::InterfaceBlock> * blocks)1204 void InterfaceBlockLinker::addShaderBlocks(ShaderType shaderType,
1205                                            const std::vector<sh::InterfaceBlock> *blocks)
1206 {
1207     mShaderBlocks[shaderType] = blocks;
1208 }
1209 
linkBlocks(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo) const1210 void InterfaceBlockLinker::linkBlocks(const GetBlockSizeFunc &getBlockSize,
1211                                       const GetBlockMemberInfoFunc &getMemberInfo) const
1212 {
1213     ASSERT(mBlocksOut->empty());
1214 
1215     std::set<std::string> visitedList;
1216 
1217     for (const ShaderType shaderType : AllShaderTypes())
1218     {
1219         if (!mShaderBlocks[shaderType])
1220         {
1221             continue;
1222         }
1223 
1224         for (const sh::InterfaceBlock &block : *mShaderBlocks[shaderType])
1225         {
1226             if (!IsActiveInterfaceBlock(block))
1227             {
1228                 mUnusedInterfaceBlocksOut->push_back(block.name);
1229                 continue;
1230             }
1231 
1232             if (visitedList.count(block.name) == 0)
1233             {
1234                 defineInterfaceBlock(getBlockSize, getMemberInfo, block, shaderType);
1235                 visitedList.insert(block.name);
1236                 continue;
1237             }
1238 
1239             if (!block.active)
1240             {
1241                 mUnusedInterfaceBlocksOut->push_back(block.name);
1242                 continue;
1243             }
1244 
1245             for (InterfaceBlock &priorBlock : *mBlocksOut)
1246             {
1247                 if (block.name == priorBlock.name)
1248                 {
1249                     priorBlock.setActive(shaderType, true);
1250 
1251                     std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1252                         getVisitor(getMemberInfo, block.fieldPrefix(), block.fieldMappedPrefix(),
1253                                    shaderType, -1));
1254 
1255                     sh::TraverseShaderVariables(block.fields, false, visitor.get());
1256                 }
1257             }
1258         }
1259     }
1260 }
1261 
defineInterfaceBlock(const GetBlockSizeFunc & getBlockSize,const GetBlockMemberInfoFunc & getMemberInfo,const sh::InterfaceBlock & interfaceBlock,ShaderType shaderType) const1262 void InterfaceBlockLinker::defineInterfaceBlock(const GetBlockSizeFunc &getBlockSize,
1263                                                 const GetBlockMemberInfoFunc &getMemberInfo,
1264                                                 const sh::InterfaceBlock &interfaceBlock,
1265                                                 ShaderType shaderType) const
1266 {
1267     size_t blockSize = 0;
1268     std::vector<unsigned int> blockIndexes;
1269 
1270     int blockIndex = static_cast<int>(mBlocksOut->size());
1271     // Track the first and last block member index to determine the range of active block members in
1272     // the block.
1273     size_t firstBlockMemberIndex = getCurrentBlockMemberIndex();
1274 
1275     std::unique_ptr<sh::ShaderVariableVisitor> visitor(
1276         getVisitor(getMemberInfo, interfaceBlock.fieldPrefix(), interfaceBlock.fieldMappedPrefix(),
1277                    shaderType, blockIndex));
1278     sh::TraverseShaderVariables(interfaceBlock.fields, false, visitor.get());
1279 
1280     size_t lastBlockMemberIndex = getCurrentBlockMemberIndex();
1281 
1282     for (size_t blockMemberIndex = firstBlockMemberIndex; blockMemberIndex < lastBlockMemberIndex;
1283          ++blockMemberIndex)
1284     {
1285         blockIndexes.push_back(static_cast<unsigned int>(blockMemberIndex));
1286     }
1287 
1288     unsigned int firstFieldArraySize = interfaceBlock.fields[0].getArraySizeProduct();
1289 
1290     for (unsigned int arrayElement = 0; arrayElement < interfaceBlock.elementCount();
1291          ++arrayElement)
1292     {
1293         std::string blockArrayName       = interfaceBlock.name;
1294         std::string blockMappedArrayName = interfaceBlock.mappedName;
1295         if (interfaceBlock.isArray())
1296         {
1297             blockArrayName += ArrayString(arrayElement);
1298             blockMappedArrayName += ArrayString(arrayElement);
1299         }
1300 
1301         // Don't define this block at all if it's not active in the implementation.
1302         if (!getBlockSize(blockArrayName, blockMappedArrayName, &blockSize))
1303         {
1304             continue;
1305         }
1306 
1307         // ESSL 3.10 section 4.4.4 page 58:
1308         // Any uniform or shader storage block declared without a binding qualifier is initially
1309         // assigned to block binding point zero.
1310         int blockBinding =
1311             (interfaceBlock.binding == -1 ? 0 : interfaceBlock.binding + arrayElement);
1312         InterfaceBlock block(interfaceBlock.name, interfaceBlock.mappedName,
1313                              interfaceBlock.isArray(), arrayElement, firstFieldArraySize,
1314                              blockBinding);
1315         block.memberIndexes = blockIndexes;
1316         block.setActive(shaderType, interfaceBlock.active);
1317 
1318         // Since all block elements in an array share the same active interface blocks, they
1319         // will all be active once any block member is used. So, since interfaceBlock.name[0]
1320         // was active, here we will add every block element in the array.
1321         block.dataSize = static_cast<unsigned int>(blockSize);
1322         mBlocksOut->push_back(block);
1323     }
1324 }
1325 
1326 // UniformBlockLinker implementation.
1327 UniformBlockLinker::UniformBlockLinker() = default;
1328 
~UniformBlockLinker()1329 UniformBlockLinker::~UniformBlockLinker() {}
1330 
init(std::vector<InterfaceBlock> * blocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<std::string> * unusedInterfaceBlocksOut)1331 void UniformBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1332                               std::vector<LinkedUniform> *uniformsOut,
1333                               std::vector<std::string> *unusedInterfaceBlocksOut)
1334 {
1335     InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1336     mUniformsOut = uniformsOut;
1337 }
1338 
getCurrentBlockMemberIndex() const1339 size_t UniformBlockLinker::getCurrentBlockMemberIndex() const
1340 {
1341     return mUniformsOut->size();
1342 }
1343 
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1344 sh::ShaderVariableVisitor *UniformBlockLinker::getVisitor(
1345     const GetBlockMemberInfoFunc &getMemberInfo,
1346     const std::string &namePrefix,
1347     const std::string &mappedNamePrefix,
1348     ShaderType shaderType,
1349     int blockIndex) const
1350 {
1351     return new UniformBlockEncodingVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1352                                            mUniformsOut, shaderType, blockIndex);
1353 }
1354 
1355 // ShaderStorageBlockLinker implementation.
1356 ShaderStorageBlockLinker::ShaderStorageBlockLinker() = default;
1357 
1358 ShaderStorageBlockLinker::~ShaderStorageBlockLinker() = default;
1359 
init(std::vector<InterfaceBlock> * blocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<std::string> * unusedInterfaceBlocksOut)1360 void ShaderStorageBlockLinker::init(std::vector<InterfaceBlock> *blocksOut,
1361                                     std::vector<BufferVariable> *bufferVariablesOut,
1362                                     std::vector<std::string> *unusedInterfaceBlocksOut)
1363 {
1364     InterfaceBlockLinker::init(blocksOut, unusedInterfaceBlocksOut);
1365     mBufferVariablesOut = bufferVariablesOut;
1366 }
1367 
getCurrentBlockMemberIndex() const1368 size_t ShaderStorageBlockLinker::getCurrentBlockMemberIndex() const
1369 {
1370     return mBufferVariablesOut->size();
1371 }
1372 
getVisitor(const GetBlockMemberInfoFunc & getMemberInfo,const std::string & namePrefix,const std::string & mappedNamePrefix,ShaderType shaderType,int blockIndex) const1373 sh::ShaderVariableVisitor *ShaderStorageBlockLinker::getVisitor(
1374     const GetBlockMemberInfoFunc &getMemberInfo,
1375     const std::string &namePrefix,
1376     const std::string &mappedNamePrefix,
1377     ShaderType shaderType,
1378     int blockIndex) const
1379 {
1380     return new ShaderStorageBlockVisitor(getMemberInfo, namePrefix, mappedNamePrefix,
1381                                          mBufferVariablesOut, shaderType, blockIndex);
1382 }
1383 
1384 // AtomicCounterBufferLinker implementation.
1385 AtomicCounterBufferLinker::AtomicCounterBufferLinker() = default;
1386 
1387 AtomicCounterBufferLinker::~AtomicCounterBufferLinker() = default;
1388 
init(std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1389 void AtomicCounterBufferLinker::init(std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1390 {
1391     mAtomicCounterBuffersOut = atomicCounterBuffersOut;
1392 }
1393 
link(const std::map<int,unsigned int> & sizeMap) const1394 void AtomicCounterBufferLinker::link(const std::map<int, unsigned int> &sizeMap) const
1395 {
1396     for (auto &atomicCounterBuffer : *mAtomicCounterBuffersOut)
1397     {
1398         auto bufferSize = sizeMap.find(atomicCounterBuffer.binding);
1399         ASSERT(bufferSize != sizeMap.end());
1400         atomicCounterBuffer.dataSize = bufferSize->second;
1401     }
1402 }
1403 
1404 ProgramLinkedResources::ProgramLinkedResources() = default;
1405 
1406 ProgramLinkedResources::~ProgramLinkedResources() = default;
1407 
init(std::vector<InterfaceBlock> * uniformBlocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<InterfaceBlock> * shaderStorageBlocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1408 void ProgramLinkedResources::init(std::vector<InterfaceBlock> *uniformBlocksOut,
1409                                   std::vector<LinkedUniform> *uniformsOut,
1410                                   std::vector<InterfaceBlock> *shaderStorageBlocksOut,
1411                                   std::vector<BufferVariable> *bufferVariablesOut,
1412                                   std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1413 {
1414     uniformBlockLinker.init(uniformBlocksOut, uniformsOut, &unusedInterfaceBlocks);
1415     shaderStorageBlockLinker.init(shaderStorageBlocksOut, bufferVariablesOut,
1416                                   &unusedInterfaceBlocks);
1417     atomicCounterBufferLinker.init(atomicCounterBuffersOut);
1418 }
1419 
linkResources(const ProgramState & programState,const ProgramLinkedResources & resources) const1420 void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
1421                                                  const ProgramLinkedResources &resources) const
1422 {
1423     // Gather uniform interface block info.
1424     InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory);
1425     for (const ShaderType shaderType : AllShaderTypes())
1426     {
1427         Shader *shader = programState.getAttachedShader(shaderType);
1428         if (shader)
1429         {
1430             uniformBlockInfo.getShaderBlockInfo(shader->getUniformBlocks());
1431         }
1432     }
1433 
1434     auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name,
1435                                                    const std::string &mappedName, size_t *sizeOut) {
1436         return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut);
1437     };
1438 
1439     auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name,
1440                                                          const std::string &mappedName,
1441                                                          sh::BlockMemberInfo *infoOut) {
1442         return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1443     };
1444 
1445     // Link uniform interface blocks.
1446     resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
1447 
1448     // Gather storage buffer interface block info.
1449     InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory);
1450     for (const ShaderType shaderType : AllShaderTypes())
1451     {
1452         Shader *shader = programState.getAttachedShader(shaderType);
1453         if (shader)
1454         {
1455             shaderStorageBlockInfo.getShaderBlockInfo(shader->getShaderStorageBlocks());
1456         }
1457     }
1458     auto getShaderStorageBlockSize = [&shaderStorageBlockInfo](const std::string &name,
1459                                                                const std::string &mappedName,
1460                                                                size_t *sizeOut) {
1461         return shaderStorageBlockInfo.getBlockSize(name, mappedName, sizeOut);
1462     };
1463 
1464     auto getShaderStorageBlockMemberInfo = [&shaderStorageBlockInfo](const std::string &name,
1465                                                                      const std::string &mappedName,
1466                                                                      sh::BlockMemberInfo *infoOut) {
1467         return shaderStorageBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1468     };
1469 
1470     // Link storage buffer interface blocks.
1471     resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
1472                                                   getShaderStorageBlockMemberInfo);
1473 
1474     // Gather and link atomic counter buffer interface blocks.
1475     std::map<int, unsigned int> sizeMap;
1476     getAtomicCounterBufferSizeMap(programState, sizeMap);
1477     resources.atomicCounterBufferLinker.link(sizeMap);
1478 }
1479 
getAtomicCounterBufferSizeMap(const ProgramState & programState,std::map<int,unsigned int> & sizeMapOut) const1480 void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
1481     const ProgramState &programState,
1482     std::map<int, unsigned int> &sizeMapOut) const
1483 {
1484     for (unsigned int index : programState.getAtomicCounterUniformRange())
1485     {
1486         const LinkedUniform &glUniform = programState.getUniforms()[index];
1487 
1488         auto &bufferDataSize = sizeMapOut[glUniform.binding];
1489 
1490         // Calculate the size of the buffer by finding the end of the last uniform with the same
1491         // binding. The end of the uniform is calculated by finding the initial offset of the
1492         // uniform and adding size of the uniform. For arrays, the size is the number of elements
1493         // times the element size (should always by 4 for atomic_units).
1494         unsigned dataOffset =
1495             glUniform.offset + static_cast<unsigned int>(glUniform.getBasicTypeElementCount() *
1496                                                          glUniform.getElementSize());
1497         if (dataOffset > bufferDataSize)
1498         {
1499             bufferDataSize = dataOffset;
1500         }
1501     }
1502 }
1503 
1504 // Note: this is broken for pipelines with modified/discarded shaders. http://anglebug.com/5506
LinkValidateProgramGlobalNames(InfoLog & infoLog,const HasAttachedShaders & programOrPipeline)1505 bool LinkValidateProgramGlobalNames(InfoLog &infoLog, const HasAttachedShaders &programOrPipeline)
1506 {
1507     angle::HashMap<std::string, const sh::ShaderVariable *> uniformMap;
1508     using BlockAndFieldPair = std::pair<const sh::InterfaceBlock *, const sh::ShaderVariable *>;
1509     angle::HashMap<std::string, std::vector<BlockAndFieldPair>> uniformBlockFieldMap;
1510 
1511     for (ShaderType shaderType : kAllGraphicsShaderTypes)
1512     {
1513         Shader *shader = programOrPipeline.getAttachedShader(shaderType);
1514         if (!shader)
1515         {
1516             continue;
1517         }
1518 
1519         // Build a map of Uniforms
1520         const std::vector<sh::ShaderVariable> uniforms = shader->getUniforms();
1521         for (const auto &uniform : uniforms)
1522         {
1523             uniformMap[uniform.name] = &uniform;
1524         }
1525 
1526         // Build a map of Uniform Blocks
1527         // This will also detect any field name conflicts between Uniform Blocks without instance
1528         // names
1529         const std::vector<sh::InterfaceBlock> &uniformBlocks = shader->getUniformBlocks();
1530         for (const auto &uniformBlock : uniformBlocks)
1531         {
1532             // Only uniform blocks without an instance name can create a conflict with their field
1533             // names
1534             if (!uniformBlock.instanceName.empty())
1535             {
1536                 continue;
1537             }
1538 
1539             for (const auto &field : uniformBlock.fields)
1540             {
1541                 if (!uniformBlockFieldMap.count(field.name))
1542                 {
1543                     // First time we've seen this uniform block field name, so add the
1544                     // (Uniform Block, Field) pair immediately since there can't be a conflict yet
1545                     BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1546                     std::vector<BlockAndFieldPair> newUniformBlockList;
1547                     newUniformBlockList.push_back(blockAndFieldPair);
1548                     uniformBlockFieldMap[field.name] = newUniformBlockList;
1549                     continue;
1550                 }
1551 
1552                 // We've seen this name before.
1553                 // We need to check each of the uniform blocks that contain a field with this name
1554                 // to see if there's a conflict or not.
1555                 std::vector<BlockAndFieldPair> prevBlockFieldPairs =
1556                     uniformBlockFieldMap[field.name];
1557                 for (const auto &prevBlockFieldPair : prevBlockFieldPairs)
1558                 {
1559                     const sh::InterfaceBlock *prevUniformBlock      = prevBlockFieldPair.first;
1560                     const sh::ShaderVariable *prevUniformBlockField = prevBlockFieldPair.second;
1561 
1562                     if (uniformBlock.isSameInterfaceBlockAtLinkTime(*prevUniformBlock))
1563                     {
1564                         // The same uniform block should, by definition, contain the same field name
1565                         continue;
1566                     }
1567 
1568                     // The uniform blocks don't match, so check if the necessary field properties
1569                     // also match
1570                     if ((field.name == prevUniformBlockField->name) &&
1571                         (field.type == prevUniformBlockField->type) &&
1572                         (field.precision == prevUniformBlockField->precision))
1573                     {
1574                         infoLog << "Name conflicts between uniform block field names: "
1575                                 << field.name;
1576                         return false;
1577                     }
1578                 }
1579 
1580                 // No conflict, so record this pair
1581                 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1582                 uniformBlockFieldMap[field.name].push_back(blockAndFieldPair);
1583             }
1584         }
1585     }
1586 
1587     // Validate no uniform names conflict with attribute names
1588     Shader *vertexShader = programOrPipeline.getAttachedShader(ShaderType::Vertex);
1589     if (vertexShader)
1590     {
1591         // ESSL 3.00.6 section 4.3.5:
1592         // If a uniform variable name is declared in one stage (e.g., a vertex shader)
1593         // but not in another (e.g., a fragment shader), then that name is still
1594         // available in the other stage for a different use.
1595         std::unordered_set<std::string> uniforms;
1596         for (const sh::ShaderVariable &uniform : vertexShader->getUniforms())
1597         {
1598             uniforms.insert(uniform.name);
1599         }
1600         for (const auto &attrib : vertexShader->getActiveAttributes())
1601         {
1602             if (uniforms.count(attrib.name))
1603             {
1604                 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
1605                 return false;
1606             }
1607         }
1608     }
1609 
1610     // Validate no Uniform Block fields conflict with other Uniforms
1611     for (const auto &uniformBlockField : uniformBlockFieldMap)
1612     {
1613         const std::string &fieldName = uniformBlockField.first;
1614         if (uniformMap.count(fieldName))
1615         {
1616             infoLog << "Name conflicts between a uniform and a uniform block field: " << fieldName;
1617             return false;
1618         }
1619     }
1620 
1621     return true;
1622 }
1623 
1624 // [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)1625 bool LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> &outputVaryings,
1626                                          const std::vector<sh::ShaderVariable> &inputVaryings,
1627                                          ShaderType frontShaderType,
1628                                          ShaderType backShaderType,
1629                                          int frontShaderVersion,
1630                                          int backShaderVersion,
1631                                          bool isSeparable,
1632                                          gl::InfoLog &infoLog)
1633 {
1634     ASSERT(frontShaderVersion == backShaderVersion);
1635 
1636     std::vector<const sh::ShaderVariable *> filteredInputVaryings;
1637     std::vector<const sh::ShaderVariable *> filteredOutputVaryings;
1638 
1639     GetFilteredVaryings(inputVaryings, &filteredInputVaryings);
1640     GetFilteredVaryings(outputVaryings, &filteredOutputVaryings);
1641 
1642     // Separable programs require the number of inputs and outputs match
1643     if (isSeparable && filteredInputVaryings.size() < filteredOutputVaryings.size())
1644     {
1645         infoLog << GetShaderTypeString(backShaderType)
1646                 << " does not consume all varyings generated by "
1647                 << GetShaderTypeString(frontShaderType);
1648         return false;
1649     }
1650     if (isSeparable && filteredInputVaryings.size() > filteredOutputVaryings.size())
1651     {
1652         infoLog << GetShaderTypeString(frontShaderType)
1653                 << " does not generate all varyings consumed by "
1654                 << GetShaderTypeString(backShaderType);
1655         return false;
1656     }
1657 
1658     // All inputs must match all outputs
1659     for (const sh::ShaderVariable *input : filteredInputVaryings)
1660     {
1661         bool match = false;
1662         for (const sh::ShaderVariable *output : filteredOutputVaryings)
1663         {
1664             if (DoShaderVariablesMatch(frontShaderVersion, frontShaderType, backShaderType, *input,
1665                                        *output, isSeparable, infoLog))
1666             {
1667                 match = true;
1668                 break;
1669             }
1670         }
1671 
1672         // We permit unmatched, unreferenced varyings. Note that this specifically depends on
1673         // whether the input is statically used - a statically used input should fail this test even
1674         // if it is not active. GLSL ES 3.00.6 section 4.3.10.
1675         if (!match && input->staticUse)
1676         {
1677             const std::string &name =
1678                 input->isShaderIOBlock ? input->structOrBlockName : input->name;
1679             infoLog << GetShaderTypeString(backShaderType) << " varying " << name
1680                     << " does not match any " << GetShaderTypeString(frontShaderType) << " varying";
1681             return false;
1682         }
1683     }
1684 
1685     return true;
1686 }
1687 
LinkValidateProgramVariables(const sh::ShaderVariable & variable1,const sh::ShaderVariable & variable2,bool validatePrecision,bool treatVariable1AsNonArray,bool treatVariable2AsNonArray,std::string * mismatchedStructOrBlockMemberName)1688 LinkMismatchError LinkValidateProgramVariables(const sh::ShaderVariable &variable1,
1689                                                const sh::ShaderVariable &variable2,
1690                                                bool validatePrecision,
1691                                                bool treatVariable1AsNonArray,
1692                                                bool treatVariable2AsNonArray,
1693                                                std::string *mismatchedStructOrBlockMemberName)
1694 {
1695     if (variable1.type != variable2.type)
1696     {
1697         return LinkMismatchError::TYPE_MISMATCH;
1698     }
1699 
1700     bool variable1IsArray = variable1.isArray();
1701     bool variable2IsArray = variable2.isArray();
1702     if (treatVariable1AsNonArray)
1703     {
1704         ASSERT(variable1IsArray);
1705         variable1IsArray = false;
1706     }
1707     if (treatVariable2AsNonArray)
1708     {
1709         ASSERT(variable2IsArray);
1710         variable2IsArray = false;
1711     }
1712     // TODO(anglebug.com/5557): Investigate interactions with arrays-of-arrays.
1713     if (variable1IsArray != variable2IsArray)
1714     {
1715         return LinkMismatchError::ARRAYNESS_MISMATCH;
1716     }
1717     if (!treatVariable1AsNonArray && !treatVariable2AsNonArray &&
1718         variable1.arraySizes != variable2.arraySizes)
1719     {
1720         return LinkMismatchError::ARRAY_SIZE_MISMATCH;
1721     }
1722     if (validatePrecision && variable1.precision != variable2.precision)
1723     {
1724         return LinkMismatchError::PRECISION_MISMATCH;
1725     }
1726     if (!variable1.isShaderIOBlock && !variable2.isShaderIOBlock &&
1727         variable1.structOrBlockName != variable2.structOrBlockName)
1728     {
1729         return LinkMismatchError::STRUCT_NAME_MISMATCH;
1730     }
1731     if (variable1.imageUnitFormat != variable2.imageUnitFormat)
1732     {
1733         return LinkMismatchError::FORMAT_MISMATCH;
1734     }
1735 
1736     if (variable1.fields.size() != variable2.fields.size())
1737     {
1738         return LinkMismatchError::FIELD_NUMBER_MISMATCH;
1739     }
1740     const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
1741     for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1742     {
1743         const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
1744         const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
1745 
1746         if (member1.name != member2.name)
1747         {
1748             return LinkMismatchError::FIELD_NAME_MISMATCH;
1749         }
1750 
1751         if (member1.interpolation != member2.interpolation)
1752         {
1753             return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
1754         }
1755 
1756         if (variable1.isShaderIOBlock && variable2.isShaderIOBlock)
1757         {
1758             if (member1.location != member2.location)
1759             {
1760                 return LinkMismatchError::FIELD_LOCATION_MISMATCH;
1761             }
1762 
1763             if (member1.structOrBlockName != member2.structOrBlockName)
1764             {
1765                 return LinkMismatchError::FIELD_STRUCT_NAME_MISMATCH;
1766             }
1767         }
1768 
1769         LinkMismatchError linkErrorOnField = LinkValidateProgramVariables(
1770             member1, member2, validatePrecision, false, false, mismatchedStructOrBlockMemberName);
1771         if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
1772         {
1773             AddProgramVariableParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
1774             return linkErrorOnField;
1775         }
1776     }
1777 
1778     return LinkMismatchError::NO_MISMATCH;
1779 }
1780 
AddProgramVariableParentPrefix(const std::string & parentName,std::string * mismatchedFieldName)1781 void AddProgramVariableParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
1782 {
1783     ASSERT(mismatchedFieldName);
1784     if (mismatchedFieldName->empty())
1785     {
1786         *mismatchedFieldName = parentName;
1787     }
1788     else
1789     {
1790         std::ostringstream stream;
1791         stream << parentName << "." << *mismatchedFieldName;
1792         *mismatchedFieldName = stream.str();
1793     }
1794 }
1795 
LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> & vertexVaryings,const std::vector<sh::ShaderVariable> & fragmentVaryings,int vertexShaderVersion,InfoLog & infoLog)1796 bool LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> &vertexVaryings,
1797                                           const std::vector<sh::ShaderVariable> &fragmentVaryings,
1798                                           int vertexShaderVersion,
1799                                           InfoLog &infoLog)
1800 {
1801     bool glPositionIsInvariant   = false;
1802     bool glPointSizeIsInvariant  = false;
1803     bool glFragCoordIsInvariant  = false;
1804     bool glPointCoordIsInvariant = false;
1805 
1806     for (const sh::ShaderVariable &varying : vertexVaryings)
1807     {
1808         if (!varying.isBuiltIn())
1809         {
1810             continue;
1811         }
1812         if (varying.name.compare("gl_Position") == 0)
1813         {
1814             glPositionIsInvariant = varying.isInvariant;
1815         }
1816         else if (varying.name.compare("gl_PointSize") == 0)
1817         {
1818             glPointSizeIsInvariant = varying.isInvariant;
1819         }
1820     }
1821 
1822     for (const sh::ShaderVariable &varying : fragmentVaryings)
1823     {
1824         if (!varying.isBuiltIn())
1825         {
1826             continue;
1827         }
1828         if (varying.name.compare("gl_FragCoord") == 0)
1829         {
1830             glFragCoordIsInvariant = varying.isInvariant;
1831         }
1832         else if (varying.name.compare("gl_PointCoord") == 0)
1833         {
1834             glPointCoordIsInvariant = varying.isInvariant;
1835         }
1836     }
1837 
1838     // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
1839     // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
1840     // Not requiring invariance to match is supported by:
1841     // dEQP, WebGL CTS, Nexus 5X GLES
1842     if (glFragCoordIsInvariant && !glPositionIsInvariant)
1843     {
1844         infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
1845                    "declared invariant.";
1846         return false;
1847     }
1848     if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
1849     {
1850         infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
1851                    "declared invariant.";
1852         return false;
1853     }
1854 
1855     return true;
1856 }
1857 
LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> & outputVaryings,const std::vector<sh::ShaderVariable> & inputVaryings,ShaderType outputShaderType,ShaderType inputShaderType,int outputShaderVersion,int inputShaderVersion,InfoLog & infoLog)1858 bool LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &outputVaryings,
1859                                  const std::vector<sh::ShaderVariable> &inputVaryings,
1860                                  ShaderType outputShaderType,
1861                                  ShaderType inputShaderType,
1862                                  int outputShaderVersion,
1863                                  int inputShaderVersion,
1864                                  InfoLog &infoLog)
1865 {
1866     ASSERT(outputShaderVersion == inputShaderVersion);
1867 
1868     // Only ESSL 1.0 has restrictions on matching input and output invariance
1869     if (inputShaderVersion == 100 && outputShaderType == ShaderType::Vertex &&
1870         inputShaderType == ShaderType::Fragment)
1871     {
1872         return LinkValidateBuiltInVaryingsInvariant(outputVaryings, inputVaryings,
1873                                                     outputShaderVersion, infoLog);
1874     }
1875 
1876     uint32_t sizeClipDistance = 0;
1877     uint32_t sizeCullDistance = 0;
1878 
1879     for (const sh::ShaderVariable &varying : outputVaryings)
1880     {
1881         if (!varying.isBuiltIn())
1882         {
1883             continue;
1884         }
1885         if (varying.name.compare("gl_ClipDistance") == 0)
1886         {
1887             sizeClipDistance = varying.getOutermostArraySize();
1888         }
1889         else if (varying.name.compare("gl_CullDistance") == 0)
1890         {
1891             sizeCullDistance = varying.getOutermostArraySize();
1892         }
1893     }
1894 
1895     for (const sh::ShaderVariable &varying : inputVaryings)
1896     {
1897         if (!varying.isBuiltIn())
1898         {
1899             continue;
1900         }
1901         if (varying.name.compare("gl_ClipDistance") == 0)
1902         {
1903             if (sizeClipDistance != varying.getOutermostArraySize())
1904             {
1905                 infoLog << "If either shader redeclares the built-in arrays gl_ClipDistance[] the "
1906                            "array must have the same size in both shaders.";
1907                 return false;
1908             }
1909         }
1910         else if (varying.name.compare("gl_CullDistance") == 0)
1911         {
1912             if (sizeCullDistance != varying.getOutermostArraySize())
1913             {
1914                 infoLog << "If either shader redeclares the built-in arrays gl_CullDistance[] the "
1915                            "array must have the same size in both shaders.";
1916                 return false;
1917             }
1918         }
1919     }
1920     return true;
1921 }
1922 }  // namespace gl
1923