• 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 bindUniformLocationCHROMIUM API
883     // or by 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 
LinkingVariables(const ProgramState & state)1408 LinkingVariables::LinkingVariables(const ProgramState &state)
1409 {
1410     for (ShaderType shaderType : kAllGraphicsShaderTypes)
1411     {
1412         Shader *shader = state.getAttachedShader(shaderType);
1413         if (shader)
1414         {
1415             outputVaryings[shaderType] = shader->getOutputVaryings();
1416             inputVaryings[shaderType]  = shader->getInputVaryings();
1417             uniforms[shaderType]       = shader->getUniforms();
1418             uniformBlocks[shaderType]  = shader->getUniformBlocks();
1419             isShaderStageUsedBitset.set(shaderType);
1420         }
1421     }
1422 }
1423 
LinkingVariables(const ProgramPipelineState & state)1424 LinkingVariables::LinkingVariables(const ProgramPipelineState &state)
1425 {
1426     for (ShaderType shaderType : state.getExecutable().getLinkedShaderStages())
1427     {
1428         const Program *program = state.getShaderProgram(shaderType);
1429         ASSERT(program);
1430         outputVaryings[shaderType] = program->getExecutable().getLinkedOutputVaryings(shaderType);
1431         inputVaryings[shaderType]  = program->getExecutable().getLinkedInputVaryings(shaderType);
1432         uniforms[shaderType] = program->getState().getExecutable().getLinkedUniforms(shaderType);
1433         uniformBlocks[shaderType] =
1434             program->getState().getExecutable().getLinkedUniformBlocks(shaderType);
1435         isShaderStageUsedBitset.set(shaderType);
1436     }
1437 }
1438 
1439 LinkingVariables::~LinkingVariables() = default;
1440 
init(std::vector<InterfaceBlock> * uniformBlocksOut,std::vector<LinkedUniform> * uniformsOut,std::vector<InterfaceBlock> * shaderStorageBlocksOut,std::vector<BufferVariable> * bufferVariablesOut,std::vector<AtomicCounterBuffer> * atomicCounterBuffersOut)1441 void ProgramLinkedResources::init(std::vector<InterfaceBlock> *uniformBlocksOut,
1442                                   std::vector<LinkedUniform> *uniformsOut,
1443                                   std::vector<InterfaceBlock> *shaderStorageBlocksOut,
1444                                   std::vector<BufferVariable> *bufferVariablesOut,
1445                                   std::vector<AtomicCounterBuffer> *atomicCounterBuffersOut)
1446 {
1447     uniformBlockLinker.init(uniformBlocksOut, uniformsOut, &unusedInterfaceBlocks);
1448     shaderStorageBlockLinker.init(shaderStorageBlocksOut, bufferVariablesOut,
1449                                   &unusedInterfaceBlocks);
1450     atomicCounterBufferLinker.init(atomicCounterBuffersOut);
1451 }
1452 
linkResources(const ProgramState & programState,const ProgramLinkedResources & resources) const1453 void ProgramLinkedResourcesLinker::linkResources(const ProgramState &programState,
1454                                                  const ProgramLinkedResources &resources) const
1455 {
1456     // Gather uniform interface block info.
1457     InterfaceBlockInfo uniformBlockInfo(mCustomEncoderFactory);
1458     for (const ShaderType shaderType : AllShaderTypes())
1459     {
1460         Shader *shader = programState.getAttachedShader(shaderType);
1461         if (shader)
1462         {
1463             uniformBlockInfo.getShaderBlockInfo(shader->getUniformBlocks());
1464         }
1465     }
1466 
1467     auto getUniformBlockSize = [&uniformBlockInfo](const std::string &name,
1468                                                    const std::string &mappedName, size_t *sizeOut) {
1469         return uniformBlockInfo.getBlockSize(name, mappedName, sizeOut);
1470     };
1471 
1472     auto getUniformBlockMemberInfo = [&uniformBlockInfo](const std::string &name,
1473                                                          const std::string &mappedName,
1474                                                          sh::BlockMemberInfo *infoOut) {
1475         return uniformBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1476     };
1477 
1478     // Link uniform interface blocks.
1479     resources.uniformBlockLinker.linkBlocks(getUniformBlockSize, getUniformBlockMemberInfo);
1480 
1481     // Gather storage buffer interface block info.
1482     InterfaceBlockInfo shaderStorageBlockInfo(mCustomEncoderFactory);
1483     for (const ShaderType shaderType : AllShaderTypes())
1484     {
1485         Shader *shader = programState.getAttachedShader(shaderType);
1486         if (shader)
1487         {
1488             shaderStorageBlockInfo.getShaderBlockInfo(shader->getShaderStorageBlocks());
1489         }
1490     }
1491     auto getShaderStorageBlockSize = [&shaderStorageBlockInfo](const std::string &name,
1492                                                                const std::string &mappedName,
1493                                                                size_t *sizeOut) {
1494         return shaderStorageBlockInfo.getBlockSize(name, mappedName, sizeOut);
1495     };
1496 
1497     auto getShaderStorageBlockMemberInfo = [&shaderStorageBlockInfo](const std::string &name,
1498                                                                      const std::string &mappedName,
1499                                                                      sh::BlockMemberInfo *infoOut) {
1500         return shaderStorageBlockInfo.getBlockMemberInfo(name, mappedName, infoOut);
1501     };
1502 
1503     // Link storage buffer interface blocks.
1504     resources.shaderStorageBlockLinker.linkBlocks(getShaderStorageBlockSize,
1505                                                   getShaderStorageBlockMemberInfo);
1506 
1507     // Gather and link atomic counter buffer interface blocks.
1508     std::map<int, unsigned int> sizeMap;
1509     getAtomicCounterBufferSizeMap(programState, sizeMap);
1510     resources.atomicCounterBufferLinker.link(sizeMap);
1511 }
1512 
getAtomicCounterBufferSizeMap(const ProgramState & programState,std::map<int,unsigned int> & sizeMapOut) const1513 void ProgramLinkedResourcesLinker::getAtomicCounterBufferSizeMap(
1514     const ProgramState &programState,
1515     std::map<int, unsigned int> &sizeMapOut) const
1516 {
1517     for (unsigned int index : programState.getAtomicCounterUniformRange())
1518     {
1519         const LinkedUniform &glUniform = programState.getUniforms()[index];
1520 
1521         auto &bufferDataSize = sizeMapOut[glUniform.binding];
1522 
1523         // Calculate the size of the buffer by finding the end of the last uniform with the same
1524         // binding. The end of the uniform is calculated by finding the initial offset of the
1525         // uniform and adding size of the uniform. For arrays, the size is the number of elements
1526         // times the element size (should always by 4 for atomic_units).
1527         unsigned dataOffset =
1528             glUniform.offset + static_cast<unsigned int>(glUniform.getBasicTypeElementCount() *
1529                                                          glUniform.getElementSize());
1530         if (dataOffset > bufferDataSize)
1531         {
1532             bufferDataSize = dataOffset;
1533         }
1534     }
1535 }
1536 
LinkValidateProgramGlobalNames(InfoLog & infoLog,const ProgramExecutable & executable,const LinkingVariables & linkingVariables)1537 bool LinkValidateProgramGlobalNames(InfoLog &infoLog,
1538                                     const ProgramExecutable &executable,
1539                                     const LinkingVariables &linkingVariables)
1540 {
1541     angle::HashMap<std::string, const sh::ShaderVariable *> uniformMap;
1542     using BlockAndFieldPair = std::pair<const sh::InterfaceBlock *, const sh::ShaderVariable *>;
1543     angle::HashMap<std::string, std::vector<BlockAndFieldPair>> uniformBlockFieldMap;
1544 
1545     for (ShaderType shaderType : kAllGraphicsShaderTypes)
1546     {
1547         if (!linkingVariables.isShaderStageUsedBitset[shaderType])
1548         {
1549             continue;
1550         }
1551 
1552         // Build a map of Uniforms
1553         const std::vector<sh::ShaderVariable> &uniforms = linkingVariables.uniforms[shaderType];
1554         for (const auto &uniform : uniforms)
1555         {
1556             uniformMap[uniform.name] = &uniform;
1557         }
1558 
1559         // Build a map of Uniform Blocks
1560         // This will also detect any field name conflicts between Uniform Blocks without instance
1561         // names
1562         const std::vector<sh::InterfaceBlock> &uniformBlocks =
1563             linkingVariables.uniformBlocks[shaderType];
1564 
1565         for (const auto &uniformBlock : uniformBlocks)
1566         {
1567             // Only uniform blocks without an instance name can create a conflict with their field
1568             // names
1569             if (!uniformBlock.instanceName.empty())
1570             {
1571                 continue;
1572             }
1573 
1574             for (const auto &field : uniformBlock.fields)
1575             {
1576                 if (!uniformBlockFieldMap.count(field.name))
1577                 {
1578                     // First time we've seen this uniform block field name, so add the
1579                     // (Uniform Block, Field) pair immediately since there can't be a conflict yet
1580                     BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1581                     std::vector<BlockAndFieldPair> newUniformBlockList;
1582                     newUniformBlockList.push_back(blockAndFieldPair);
1583                     uniformBlockFieldMap[field.name] = newUniformBlockList;
1584                     continue;
1585                 }
1586 
1587                 // We've seen this name before.
1588                 // We need to check each of the uniform blocks that contain a field with this name
1589                 // to see if there's a conflict or not.
1590                 std::vector<BlockAndFieldPair> prevBlockFieldPairs =
1591                     uniformBlockFieldMap[field.name];
1592                 for (const auto &prevBlockFieldPair : prevBlockFieldPairs)
1593                 {
1594                     const sh::InterfaceBlock *prevUniformBlock      = prevBlockFieldPair.first;
1595                     const sh::ShaderVariable *prevUniformBlockField = prevBlockFieldPair.second;
1596 
1597                     if (uniformBlock.isSameInterfaceBlockAtLinkTime(*prevUniformBlock))
1598                     {
1599                         // The same uniform block should, by definition, contain the same field name
1600                         continue;
1601                     }
1602 
1603                     // The uniform blocks don't match, so check if the necessary field properties
1604                     // also match
1605                     if ((field.name == prevUniformBlockField->name) &&
1606                         (field.type == prevUniformBlockField->type) &&
1607                         (field.precision == prevUniformBlockField->precision))
1608                     {
1609                         infoLog << "Name conflicts between uniform block field names: "
1610                                 << field.name;
1611                         return false;
1612                     }
1613                 }
1614 
1615                 // No conflict, so record this pair
1616                 BlockAndFieldPair blockAndFieldPair(&uniformBlock, &field);
1617                 uniformBlockFieldMap[field.name].push_back(blockAndFieldPair);
1618             }
1619         }
1620     }
1621 
1622     // Validate no uniform names conflict with attribute names
1623     if (linkingVariables.isShaderStageUsedBitset[ShaderType::Vertex])
1624     {
1625         // ESSL 3.00.6 section 4.3.5:
1626         // If a uniform variable name is declared in one stage (e.g., a vertex shader)
1627         // but not in another (e.g., a fragment shader), then that name is still
1628         // available in the other stage for a different use.
1629         std::unordered_set<std::string> uniforms;
1630         for (const sh::ShaderVariable &uniform : linkingVariables.uniforms[ShaderType::Vertex])
1631         {
1632             uniforms.insert(uniform.name);
1633         }
1634         for (const auto &attrib : executable.getProgramInputs())
1635         {
1636             if (uniforms.count(attrib.name))
1637             {
1638                 infoLog << "Name conflicts between a uniform and an attribute: " << attrib.name;
1639                 return false;
1640             }
1641         }
1642     }
1643 
1644     // Validate no Uniform Block fields conflict with other Uniforms
1645     for (const auto &uniformBlockField : uniformBlockFieldMap)
1646     {
1647         const std::string &fieldName = uniformBlockField.first;
1648         if (uniformMap.count(fieldName))
1649         {
1650             infoLog << "Name conflicts between a uniform and a uniform block field: " << fieldName;
1651             return false;
1652         }
1653     }
1654 
1655     return true;
1656 }
1657 
1658 // [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)1659 bool LinkValidateShaderInterfaceMatching(const std::vector<sh::ShaderVariable> &outputVaryings,
1660                                          const std::vector<sh::ShaderVariable> &inputVaryings,
1661                                          ShaderType frontShaderType,
1662                                          ShaderType backShaderType,
1663                                          int frontShaderVersion,
1664                                          int backShaderVersion,
1665                                          bool isSeparable,
1666                                          gl::InfoLog &infoLog)
1667 {
1668     ASSERT(frontShaderVersion == backShaderVersion);
1669 
1670     std::vector<const sh::ShaderVariable *> filteredInputVaryings;
1671     std::vector<const sh::ShaderVariable *> filteredOutputVaryings;
1672 
1673     GetFilteredVaryings(inputVaryings, &filteredInputVaryings);
1674     GetFilteredVaryings(outputVaryings, &filteredOutputVaryings);
1675 
1676     // Separable programs require the number of inputs and outputs match
1677     if (isSeparable && filteredInputVaryings.size() < filteredOutputVaryings.size())
1678     {
1679         infoLog << GetShaderTypeString(backShaderType)
1680                 << " does not consume all varyings generated by "
1681                 << GetShaderTypeString(frontShaderType);
1682         return false;
1683     }
1684     if (isSeparable && filteredInputVaryings.size() > filteredOutputVaryings.size())
1685     {
1686         infoLog << GetShaderTypeString(frontShaderType)
1687                 << " does not generate all varyings consumed by "
1688                 << GetShaderTypeString(backShaderType);
1689         return false;
1690     }
1691 
1692     // All inputs must match all outputs
1693     for (const sh::ShaderVariable *input : filteredInputVaryings)
1694     {
1695         bool match = false;
1696         for (const sh::ShaderVariable *output : filteredOutputVaryings)
1697         {
1698             if (DoShaderVariablesMatch(frontShaderVersion, frontShaderType, backShaderType, *input,
1699                                        *output, isSeparable, infoLog))
1700             {
1701                 match = true;
1702                 break;
1703             }
1704         }
1705 
1706         // We permit unmatched, unreferenced varyings. Note that this specifically depends on
1707         // whether the input is statically used - a statically used input should fail this test even
1708         // if it is not active. GLSL ES 3.00.6 section 4.3.10.
1709         if (!match && input->staticUse)
1710         {
1711             const std::string &name =
1712                 input->isShaderIOBlock ? input->structOrBlockName : input->name;
1713             infoLog << GetShaderTypeString(backShaderType) << " varying " << name
1714                     << " does not match any " << GetShaderTypeString(frontShaderType) << " varying";
1715             return false;
1716         }
1717     }
1718 
1719     return true;
1720 }
1721 
LinkValidateProgramVariables(const sh::ShaderVariable & variable1,const sh::ShaderVariable & variable2,bool validatePrecision,bool treatVariable1AsNonArray,bool treatVariable2AsNonArray,std::string * mismatchedStructOrBlockMemberName)1722 LinkMismatchError LinkValidateProgramVariables(const sh::ShaderVariable &variable1,
1723                                                const sh::ShaderVariable &variable2,
1724                                                bool validatePrecision,
1725                                                bool treatVariable1AsNonArray,
1726                                                bool treatVariable2AsNonArray,
1727                                                std::string *mismatchedStructOrBlockMemberName)
1728 {
1729     if (variable1.type != variable2.type)
1730     {
1731         return LinkMismatchError::TYPE_MISMATCH;
1732     }
1733 
1734     bool variable1IsArray = variable1.isArray();
1735     bool variable2IsArray = variable2.isArray();
1736     if (treatVariable1AsNonArray)
1737     {
1738         ASSERT(variable1IsArray);
1739         variable1IsArray = false;
1740     }
1741     if (treatVariable2AsNonArray)
1742     {
1743         ASSERT(variable2IsArray);
1744         variable2IsArray = false;
1745     }
1746     // TODO(anglebug.com/5557): Investigate interactions with arrays-of-arrays.
1747     if (variable1IsArray != variable2IsArray)
1748     {
1749         return LinkMismatchError::ARRAYNESS_MISMATCH;
1750     }
1751     if (!treatVariable1AsNonArray && !treatVariable2AsNonArray &&
1752         variable1.arraySizes != variable2.arraySizes)
1753     {
1754         return LinkMismatchError::ARRAY_SIZE_MISMATCH;
1755     }
1756     if (validatePrecision && variable1.precision != variable2.precision)
1757     {
1758         return LinkMismatchError::PRECISION_MISMATCH;
1759     }
1760     if (!variable1.isShaderIOBlock && !variable2.isShaderIOBlock &&
1761         variable1.structOrBlockName != variable2.structOrBlockName)
1762     {
1763         return LinkMismatchError::STRUCT_NAME_MISMATCH;
1764     }
1765     if (variable1.imageUnitFormat != variable2.imageUnitFormat)
1766     {
1767         return LinkMismatchError::FORMAT_MISMATCH;
1768     }
1769 
1770     if (variable1.fields.size() != variable2.fields.size())
1771     {
1772         return LinkMismatchError::FIELD_NUMBER_MISMATCH;
1773     }
1774     const unsigned int numMembers = static_cast<unsigned int>(variable1.fields.size());
1775     for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
1776     {
1777         const sh::ShaderVariable &member1 = variable1.fields[memberIndex];
1778         const sh::ShaderVariable &member2 = variable2.fields[memberIndex];
1779 
1780         if (member1.name != member2.name)
1781         {
1782             return LinkMismatchError::FIELD_NAME_MISMATCH;
1783         }
1784 
1785         if (member1.interpolation != member2.interpolation)
1786         {
1787             return LinkMismatchError::INTERPOLATION_TYPE_MISMATCH;
1788         }
1789 
1790         if (variable1.isShaderIOBlock && variable2.isShaderIOBlock)
1791         {
1792             if (member1.location != member2.location)
1793             {
1794                 return LinkMismatchError::FIELD_LOCATION_MISMATCH;
1795             }
1796 
1797             if (member1.structOrBlockName != member2.structOrBlockName)
1798             {
1799                 return LinkMismatchError::FIELD_STRUCT_NAME_MISMATCH;
1800             }
1801         }
1802 
1803         LinkMismatchError linkErrorOnField = LinkValidateProgramVariables(
1804             member1, member2, validatePrecision, false, false, mismatchedStructOrBlockMemberName);
1805         if (linkErrorOnField != LinkMismatchError::NO_MISMATCH)
1806         {
1807             AddProgramVariableParentPrefix(member1.name, mismatchedStructOrBlockMemberName);
1808             return linkErrorOnField;
1809         }
1810     }
1811 
1812     return LinkMismatchError::NO_MISMATCH;
1813 }
1814 
AddProgramVariableParentPrefix(const std::string & parentName,std::string * mismatchedFieldName)1815 void AddProgramVariableParentPrefix(const std::string &parentName, std::string *mismatchedFieldName)
1816 {
1817     ASSERT(mismatchedFieldName);
1818     if (mismatchedFieldName->empty())
1819     {
1820         *mismatchedFieldName = parentName;
1821     }
1822     else
1823     {
1824         std::ostringstream stream;
1825         stream << parentName << "." << *mismatchedFieldName;
1826         *mismatchedFieldName = stream.str();
1827     }
1828 }
1829 
LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> & vertexVaryings,const std::vector<sh::ShaderVariable> & fragmentVaryings,int vertexShaderVersion,InfoLog & infoLog)1830 bool LinkValidateBuiltInVaryingsInvariant(const std::vector<sh::ShaderVariable> &vertexVaryings,
1831                                           const std::vector<sh::ShaderVariable> &fragmentVaryings,
1832                                           int vertexShaderVersion,
1833                                           InfoLog &infoLog)
1834 {
1835     bool glPositionIsInvariant   = false;
1836     bool glPointSizeIsInvariant  = false;
1837     bool glFragCoordIsInvariant  = false;
1838     bool glPointCoordIsInvariant = false;
1839 
1840     for (const sh::ShaderVariable &varying : vertexVaryings)
1841     {
1842         if (!varying.isBuiltIn())
1843         {
1844             continue;
1845         }
1846         if (varying.name.compare("gl_Position") == 0)
1847         {
1848             glPositionIsInvariant = varying.isInvariant;
1849         }
1850         else if (varying.name.compare("gl_PointSize") == 0)
1851         {
1852             glPointSizeIsInvariant = varying.isInvariant;
1853         }
1854     }
1855 
1856     for (const sh::ShaderVariable &varying : fragmentVaryings)
1857     {
1858         if (!varying.isBuiltIn())
1859         {
1860             continue;
1861         }
1862         if (varying.name.compare("gl_FragCoord") == 0)
1863         {
1864             glFragCoordIsInvariant = varying.isInvariant;
1865         }
1866         else if (varying.name.compare("gl_PointCoord") == 0)
1867         {
1868             glPointCoordIsInvariant = varying.isInvariant;
1869         }
1870     }
1871 
1872     // There is some ambiguity in ESSL 1.00.17 paragraph 4.6.4 interpretation,
1873     // for example, https://cvs.khronos.org/bugzilla/show_bug.cgi?id=13842.
1874     // Not requiring invariance to match is supported by:
1875     // dEQP, WebGL CTS, Nexus 5X GLES
1876     if (glFragCoordIsInvariant && !glPositionIsInvariant)
1877     {
1878         infoLog << "gl_FragCoord can only be declared invariant if and only if gl_Position is "
1879                    "declared invariant.";
1880         return false;
1881     }
1882     if (glPointCoordIsInvariant && !glPointSizeIsInvariant)
1883     {
1884         infoLog << "gl_PointCoord can only be declared invariant if and only if gl_PointSize is "
1885                    "declared invariant.";
1886         return false;
1887     }
1888 
1889     return true;
1890 }
1891 
LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> & outputVaryings,const std::vector<sh::ShaderVariable> & inputVaryings,ShaderType outputShaderType,ShaderType inputShaderType,int outputShaderVersion,int inputShaderVersion,InfoLog & infoLog)1892 bool LinkValidateBuiltInVaryings(const std::vector<sh::ShaderVariable> &outputVaryings,
1893                                  const std::vector<sh::ShaderVariable> &inputVaryings,
1894                                  ShaderType outputShaderType,
1895                                  ShaderType inputShaderType,
1896                                  int outputShaderVersion,
1897                                  int inputShaderVersion,
1898                                  InfoLog &infoLog)
1899 {
1900     ASSERT(outputShaderVersion == inputShaderVersion);
1901 
1902     // Only ESSL 1.0 has restrictions on matching input and output invariance
1903     if (inputShaderVersion == 100 && outputShaderType == ShaderType::Vertex &&
1904         inputShaderType == ShaderType::Fragment)
1905     {
1906         return LinkValidateBuiltInVaryingsInvariant(outputVaryings, inputVaryings,
1907                                                     outputShaderVersion, infoLog);
1908     }
1909 
1910     uint32_t sizeClipDistance = 0;
1911     uint32_t sizeCullDistance = 0;
1912 
1913     for (const sh::ShaderVariable &varying : outputVaryings)
1914     {
1915         if (!varying.isBuiltIn())
1916         {
1917             continue;
1918         }
1919         if (varying.name.compare("gl_ClipDistance") == 0)
1920         {
1921             sizeClipDistance = varying.getOutermostArraySize();
1922         }
1923         else if (varying.name.compare("gl_CullDistance") == 0)
1924         {
1925             sizeCullDistance = varying.getOutermostArraySize();
1926         }
1927     }
1928 
1929     for (const sh::ShaderVariable &varying : inputVaryings)
1930     {
1931         if (!varying.isBuiltIn())
1932         {
1933             continue;
1934         }
1935         if (varying.name.compare("gl_ClipDistance") == 0)
1936         {
1937             if (sizeClipDistance != varying.getOutermostArraySize())
1938             {
1939                 infoLog << "If either shader redeclares the built-in arrays gl_ClipDistance[] the "
1940                            "array must have the same size in both shaders.";
1941                 return false;
1942             }
1943         }
1944         else if (varying.name.compare("gl_CullDistance") == 0)
1945         {
1946             if (sizeCullDistance != varying.getOutermostArraySize())
1947             {
1948                 infoLog << "If either shader redeclares the built-in arrays gl_CullDistance[] the "
1949                            "array must have the same size in both shaders.";
1950                 return false;
1951             }
1952         }
1953     }
1954     return true;
1955 }
1956 }  // namespace gl
1957