• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 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 // CollectVariables.cpp: Collect lists of shader interface variables based on the AST.
7 
8 #include "compiler/translator/CollectVariables.h"
9 
10 #include "angle_gl.h"
11 #include "common/utilities.h"
12 #include "compiler/translator/HashNames.h"
13 #include "compiler/translator/SymbolTable.h"
14 #include "compiler/translator/tree_util/IntermTraverse.h"
15 #include "compiler/translator/util.h"
16 
17 namespace sh
18 {
19 
20 namespace
21 {
22 
GetBlockLayoutType(TLayoutBlockStorage blockStorage)23 BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
24 {
25     switch (blockStorage)
26     {
27         case EbsPacked:
28             return BLOCKLAYOUT_PACKED;
29         case EbsShared:
30             return BLOCKLAYOUT_SHARED;
31         case EbsStd140:
32             return BLOCKLAYOUT_STD140;
33         case EbsStd430:
34             return BLOCKLAYOUT_STD430;
35         default:
36             UNREACHABLE();
37             return BLOCKLAYOUT_SHARED;
38     }
39 }
40 
GetBlockType(TQualifier qualifier)41 BlockType GetBlockType(TQualifier qualifier)
42 {
43     switch (qualifier)
44     {
45         case EvqUniform:
46             return BlockType::BLOCK_UNIFORM;
47         case EvqBuffer:
48             return BlockType::BLOCK_BUFFER;
49         default:
50             UNREACHABLE();
51             return BlockType::BLOCK_UNIFORM;
52     }
53 }
54 
55 template <class VarT>
FindVariable(const ImmutableString & name,std::vector<VarT> * infoList)56 VarT *FindVariable(const ImmutableString &name, std::vector<VarT> *infoList)
57 {
58     // TODO(zmo): optimize this function.
59     for (size_t ii = 0; ii < infoList->size(); ++ii)
60     {
61         if (name == (*infoList)[ii].name)
62             return &((*infoList)[ii]);
63     }
64 
65     return nullptr;
66 }
67 
MarkActive(ShaderVariable * variable)68 void MarkActive(ShaderVariable *variable)
69 {
70     if (!variable->active)
71     {
72         if (variable->isStruct())
73         {
74             // Conservatively assume all fields are statically used as well.
75             for (auto &field : variable->fields)
76             {
77                 MarkActive(&field);
78             }
79         }
80         variable->staticUse = true;
81         variable->active    = true;
82     }
83 }
84 
FindVariableInInterfaceBlock(const ImmutableString & name,const TInterfaceBlock * interfaceBlock,std::vector<InterfaceBlock> * infoList)85 ShaderVariable *FindVariableInInterfaceBlock(const ImmutableString &name,
86                                              const TInterfaceBlock *interfaceBlock,
87                                              std::vector<InterfaceBlock> *infoList)
88 {
89     ASSERT(interfaceBlock);
90     InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList);
91     ASSERT(namedBlock);
92 
93     // Set static use on the parent interface block here
94     namedBlock->staticUse = true;
95     namedBlock->active    = true;
96     return FindVariable(name, &namedBlock->fields);
97 }
98 
FindShaderIOBlockVariable(const ImmutableString & blockName,std::vector<ShaderVariable> * infoList)99 ShaderVariable *FindShaderIOBlockVariable(const ImmutableString &blockName,
100                                           std::vector<ShaderVariable> *infoList)
101 {
102     for (size_t index = 0; index < infoList->size(); ++index)
103     {
104         if (blockName == (*infoList)[index].structOrBlockName)
105             return &(*infoList)[index];
106     }
107 
108     return nullptr;
109 }
110 
111 // Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
112 // shared data and interface blocks.
113 class CollectVariablesTraverser : public TIntermTraverser
114 {
115   public:
116     CollectVariablesTraverser(std::vector<ShaderVariable> *attribs,
117                               std::vector<ShaderVariable> *outputVariables,
118                               std::vector<ShaderVariable> *uniforms,
119                               std::vector<ShaderVariable> *inputVaryings,
120                               std::vector<ShaderVariable> *outputVaryings,
121                               std::vector<ShaderVariable> *sharedVariables,
122                               std::vector<InterfaceBlock> *uniformBlocks,
123                               std::vector<InterfaceBlock> *shaderStorageBlocks,
124                               ShHashFunction64 hashFunction,
125                               TSymbolTable *symbolTable,
126                               GLenum shaderType,
127                               const TExtensionBehavior &extensionBehavior,
128                               const ShBuiltInResources &resources,
129                               int tessControlShaderOutputVertices);
130 
131     bool visitGlobalQualifierDeclaration(Visit visit,
132                                          TIntermGlobalQualifierDeclaration *node) override;
133     void visitSymbol(TIntermSymbol *symbol) override;
134     bool visitDeclaration(Visit, TIntermDeclaration *node) override;
135     bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
136 
137   private:
138     std::string getMappedName(const TSymbol *symbol) const;
139 
140     void setFieldOrVariableProperties(const TType &type,
141                                       bool staticUse,
142                                       bool isShaderIOBlock,
143                                       bool isPatch,
144                                       ShaderVariable *variableOut) const;
145     void setFieldProperties(const TType &type,
146                             const ImmutableString &name,
147                             bool staticUse,
148                             bool isShaderIOBlock,
149                             bool isPatch,
150                             SymbolType symbolType,
151                             ShaderVariable *variableOut) const;
152     void setCommonVariableProperties(const TType &type,
153                                      const TVariable &variable,
154                                      ShaderVariable *variableOut) const;
155 
156     ShaderVariable recordAttribute(const TIntermSymbol &variable) const;
157     ShaderVariable recordOutputVariable(const TIntermSymbol &variable) const;
158     ShaderVariable recordVarying(const TIntermSymbol &variable) const;
159     void recordInterfaceBlock(const char *instanceName,
160                               const TType &interfaceBlockType,
161                               InterfaceBlock *interfaceBlock) const;
162     ShaderVariable recordUniform(const TIntermSymbol &variable) const;
163 
164     void setBuiltInInfoFromSymbol(const TVariable &variable, ShaderVariable *info);
165 
166     void recordBuiltInVaryingUsed(const TVariable &variable,
167                                   bool *addedFlag,
168                                   std::vector<ShaderVariable> *varyings);
169     void recordBuiltInFragmentOutputUsed(const TVariable &variable, bool *addedFlag);
170     void recordBuiltInAttributeUsed(const TVariable &variable, bool *addedFlag);
171     InterfaceBlock *findNamedInterfaceBlock(const ImmutableString &name) const;
172 
173     std::vector<ShaderVariable> *mAttribs;
174     std::vector<ShaderVariable> *mOutputVariables;
175     std::vector<ShaderVariable> *mUniforms;
176     std::vector<ShaderVariable> *mInputVaryings;
177     std::vector<ShaderVariable> *mOutputVaryings;
178     std::vector<ShaderVariable> *mSharedVariables;
179     std::vector<InterfaceBlock> *mUniformBlocks;
180     std::vector<InterfaceBlock> *mShaderStorageBlocks;
181 
182     std::map<std::string, ShaderVariable *> mInterfaceBlockFields;
183 
184     // Shader uniforms
185     bool mDepthRangeAdded;
186     bool mNumSamplesAdded;
187 
188     // Compute Shader builtins
189     bool mNumWorkGroupsAdded;
190     bool mWorkGroupIDAdded;
191     bool mLocalInvocationIDAdded;
192     bool mGlobalInvocationIDAdded;
193     bool mLocalInvocationIndexAdded;
194 
195     // Vertex Shader builtins
196     bool mInstanceIDAdded;
197     bool mVertexIDAdded;
198     bool mPointSizeAdded;
199     bool mDrawIDAdded;
200 
201     // Vertex Shader and Geometry Shader builtins
202     bool mPositionAdded;
203     bool mClipDistanceAdded;
204     bool mCullDistanceAdded;
205 
206     // Fragment Shader builtins
207     bool mPointCoordAdded;
208     bool mFrontFacingAdded;
209     bool mHelperInvocationAdded;
210     bool mFragCoordAdded;
211     bool mLastFragDataAdded;
212     bool mFragColorAdded;
213     bool mFragDataAdded;
214     bool mFragDepthAdded;
215     bool mSecondaryFragColorEXTAdded;
216     bool mSecondaryFragDataEXTAdded;
217     bool mSampleIDAdded;
218     bool mSamplePositionAdded;
219     bool mSampleMaskAdded;
220     bool mSampleMaskInAdded;
221 
222     // Geometry and Tessellation Shader builtins
223     bool mPerVertexInAdded;
224     bool mPerVertexOutAdded;
225 
226     // Geometry Shader builtins
227     bool mPrimitiveIDInAdded;
228     bool mInvocationIDAdded;
229 
230     // Geometry Shader and Fragment Shader builtins
231     bool mPrimitiveIDAdded;
232     bool mLayerAdded;
233 
234     // Shared memory variables
235     bool mSharedVariableAdded;
236 
237     // Tessellation Shader builtins
238     bool mPatchVerticesInAdded;
239     bool mTessLevelOuterAdded;
240     bool mTessLevelInnerAdded;
241     bool mBoundingBoxAdded;
242     bool mTessCoordAdded;
243     const int mTessControlShaderOutputVertices;
244 
245     ShHashFunction64 mHashFunction;
246 
247     GLenum mShaderType;
248     const TExtensionBehavior &mExtensionBehavior;
249     const ShBuiltInResources &mResources;
250 };
251 
CollectVariablesTraverser(std::vector<sh::ShaderVariable> * attribs,std::vector<sh::ShaderVariable> * outputVariables,std::vector<sh::ShaderVariable> * uniforms,std::vector<sh::ShaderVariable> * inputVaryings,std::vector<sh::ShaderVariable> * outputVaryings,std::vector<sh::ShaderVariable> * sharedVariables,std::vector<sh::InterfaceBlock> * uniformBlocks,std::vector<sh::InterfaceBlock> * shaderStorageBlocks,ShHashFunction64 hashFunction,TSymbolTable * symbolTable,GLenum shaderType,const TExtensionBehavior & extensionBehavior,const ShBuiltInResources & resources,int tessControlShaderOutputVertices)252 CollectVariablesTraverser::CollectVariablesTraverser(
253     std::vector<sh::ShaderVariable> *attribs,
254     std::vector<sh::ShaderVariable> *outputVariables,
255     std::vector<sh::ShaderVariable> *uniforms,
256     std::vector<sh::ShaderVariable> *inputVaryings,
257     std::vector<sh::ShaderVariable> *outputVaryings,
258     std::vector<sh::ShaderVariable> *sharedVariables,
259     std::vector<sh::InterfaceBlock> *uniformBlocks,
260     std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
261     ShHashFunction64 hashFunction,
262     TSymbolTable *symbolTable,
263     GLenum shaderType,
264     const TExtensionBehavior &extensionBehavior,
265     const ShBuiltInResources &resources,
266     int tessControlShaderOutputVertices)
267     : TIntermTraverser(true, false, false, symbolTable),
268       mAttribs(attribs),
269       mOutputVariables(outputVariables),
270       mUniforms(uniforms),
271       mInputVaryings(inputVaryings),
272       mOutputVaryings(outputVaryings),
273       mSharedVariables(sharedVariables),
274       mUniformBlocks(uniformBlocks),
275       mShaderStorageBlocks(shaderStorageBlocks),
276       mDepthRangeAdded(false),
277       mNumSamplesAdded(false),
278       mNumWorkGroupsAdded(false),
279       mWorkGroupIDAdded(false),
280       mLocalInvocationIDAdded(false),
281       mGlobalInvocationIDAdded(false),
282       mLocalInvocationIndexAdded(false),
283       mInstanceIDAdded(false),
284       mVertexIDAdded(false),
285       mPointSizeAdded(false),
286       mDrawIDAdded(false),
287       mPositionAdded(false),
288       mClipDistanceAdded(false),
289       mCullDistanceAdded(false),
290       mPointCoordAdded(false),
291       mFrontFacingAdded(false),
292       mHelperInvocationAdded(false),
293       mFragCoordAdded(false),
294       mLastFragDataAdded(false),
295       mFragColorAdded(false),
296       mFragDataAdded(false),
297       mFragDepthAdded(false),
298       mSecondaryFragColorEXTAdded(false),
299       mSecondaryFragDataEXTAdded(false),
300       mSampleIDAdded(false),
301       mSamplePositionAdded(false),
302       mSampleMaskAdded(false),
303       mSampleMaskInAdded(false),
304       mPerVertexInAdded(false),
305       mPerVertexOutAdded(false),
306       mPrimitiveIDInAdded(false),
307       mInvocationIDAdded(false),
308       mPrimitiveIDAdded(false),
309       mLayerAdded(false),
310       mSharedVariableAdded(false),
311       mPatchVerticesInAdded(false),
312       mTessLevelOuterAdded(false),
313       mTessLevelInnerAdded(false),
314       mBoundingBoxAdded(false),
315       mTessCoordAdded(false),
316       mTessControlShaderOutputVertices(tessControlShaderOutputVertices),
317       mHashFunction(hashFunction),
318       mShaderType(shaderType),
319       mExtensionBehavior(extensionBehavior),
320       mResources(resources)
321 {}
322 
getMappedName(const TSymbol * symbol) const323 std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const
324 {
325     return HashName(symbol, mHashFunction, nullptr).data();
326 }
327 
setBuiltInInfoFromSymbol(const TVariable & variable,ShaderVariable * info)328 void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variable,
329                                                          ShaderVariable *info)
330 {
331     const TType &type = variable.getType();
332 
333     info->name       = variable.name().data();
334     info->mappedName = variable.name().data();
335 
336     bool isShaderIOBlock =
337         IsShaderIoBlock(type.getQualifier()) && type.getInterfaceBlock() != nullptr;
338     bool isPatch = type.getQualifier() == EvqTessLevelInner ||
339                    type.getQualifier() == EvqTessLevelOuter ||
340                    type.getQualifier() == EvqBoundingBox;
341 
342     setFieldOrVariableProperties(type, true, isShaderIOBlock, isPatch, info);
343 }
344 
recordBuiltInVaryingUsed(const TVariable & variable,bool * addedFlag,std::vector<ShaderVariable> * varyings)345 void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable,
346                                                          bool *addedFlag,
347                                                          std::vector<ShaderVariable> *varyings)
348 {
349     ASSERT(varyings);
350     if (!(*addedFlag))
351     {
352         ShaderVariable info;
353         setBuiltInInfoFromSymbol(variable, &info);
354         info.active      = true;
355         info.isInvariant = mSymbolTable->isVaryingInvariant(variable);
356 
357         varyings->push_back(info);
358         (*addedFlag) = true;
359     }
360 }
361 
recordBuiltInFragmentOutputUsed(const TVariable & variable,bool * addedFlag)362 void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const TVariable &variable,
363                                                                 bool *addedFlag)
364 {
365     if (!(*addedFlag))
366     {
367         ShaderVariable info;
368         setBuiltInInfoFromSymbol(variable, &info);
369         info.active = true;
370         mOutputVariables->push_back(info);
371         (*addedFlag) = true;
372     }
373 }
374 
recordBuiltInAttributeUsed(const TVariable & variable,bool * addedFlag)375 void CollectVariablesTraverser::recordBuiltInAttributeUsed(const TVariable &variable,
376                                                            bool *addedFlag)
377 {
378     if (!(*addedFlag))
379     {
380         ShaderVariable info;
381         setBuiltInInfoFromSymbol(variable, &info);
382         info.active   = true;
383         info.location = -1;
384         mAttribs->push_back(info);
385         (*addedFlag) = true;
386     }
387 }
388 
visitGlobalQualifierDeclaration(Visit visit,TIntermGlobalQualifierDeclaration * node)389 bool CollectVariablesTraverser::visitGlobalQualifierDeclaration(
390     Visit visit,
391     TIntermGlobalQualifierDeclaration *node)
392 {
393     // We should not mark variables as active just based on an invariant/precise declaration, so we
394     // don't traverse the symbols declared invariant.
395     return false;
396 }
397 
398 // We want to check whether a uniform/varying is active because we need to skip updating inactive
399 // ones. We also only count the active ones in packing computing. Also, gl_FragCoord, gl_PointCoord,
400 // and gl_FrontFacing count toward varying counting if they are active in a fragment shader.
visitSymbol(TIntermSymbol * symbol)401 void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
402 {
403     ASSERT(symbol != nullptr);
404 
405     if (symbol->variable().symbolType() == SymbolType::AngleInternal ||
406         symbol->variable().symbolType() == SymbolType::Empty)
407     {
408         // Internal variables or nameless variables are not collected.
409         return;
410     }
411 
412     ShaderVariable *var = nullptr;
413 
414     const ImmutableString &symbolName = symbol->getName();
415 
416     // Check the qualifier from the variable, not from the symbol node. The node may have a
417     // different qualifier if it's the result of a folded ternary node.
418     TQualifier qualifier                  = symbol->variable().getType().getQualifier();
419     const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
420 
421     if (IsVaryingIn(qualifier))
422     {
423         if (interfaceBlock)
424         {
425             var = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);
426         }
427         else
428         {
429             var = FindVariable(symbolName, mInputVaryings);
430         }
431     }
432     else if (IsVaryingOut(qualifier))
433     {
434         if (interfaceBlock)
435         {
436             var = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
437         }
438         else
439         {
440             var = FindVariable(symbolName, mOutputVaryings);
441         }
442     }
443     else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
444     {
445         UNREACHABLE();
446     }
447     else if (symbolName == "gl_DepthRange")
448     {
449         ASSERT(qualifier == EvqUniform);
450 
451         if (!mDepthRangeAdded)
452         {
453             ShaderVariable info;
454             const char kName[] = "gl_DepthRange";
455             info.name          = kName;
456             info.mappedName    = kName;
457             info.type          = GL_NONE;
458             info.precision     = GL_NONE;
459             info.staticUse     = true;
460             info.active        = true;
461 
462             ShaderVariable nearInfo(GL_FLOAT);
463             const char kNearName[] = "near";
464             nearInfo.name          = kNearName;
465             nearInfo.mappedName    = kNearName;
466             nearInfo.precision     = GL_HIGH_FLOAT;
467             nearInfo.staticUse     = true;
468             nearInfo.active        = true;
469 
470             ShaderVariable farInfo(GL_FLOAT);
471             const char kFarName[] = "far";
472             farInfo.name          = kFarName;
473             farInfo.mappedName    = kFarName;
474             farInfo.precision     = GL_HIGH_FLOAT;
475             farInfo.staticUse     = true;
476             farInfo.active        = true;
477 
478             ShaderVariable diffInfo(GL_FLOAT);
479             const char kDiffName[] = "diff";
480             diffInfo.name          = kDiffName;
481             diffInfo.mappedName    = kDiffName;
482             diffInfo.precision     = GL_HIGH_FLOAT;
483             diffInfo.staticUse     = true;
484             diffInfo.active        = true;
485 
486             info.fields.push_back(nearInfo);
487             info.fields.push_back(farInfo);
488             info.fields.push_back(diffInfo);
489 
490             mUniforms->push_back(info);
491             mDepthRangeAdded = true;
492         }
493     }
494     else if (symbolName == "gl_NumSamples")
495     {
496         ASSERT(qualifier == EvqUniform);
497 
498         if (!mNumSamplesAdded)
499         {
500             ShaderVariable info;
501             const char kName[] = "gl_NumSamples";
502             info.name          = kName;
503             info.mappedName    = kName;
504             info.type          = GL_INT;
505             info.precision     = GL_LOW_INT;
506             info.staticUse     = true;
507             info.active        = true;
508 
509             mUniforms->push_back(info);
510             mNumSamplesAdded = true;
511         }
512     }
513     else
514     {
515         switch (qualifier)
516         {
517             case EvqAttribute:
518             case EvqVertexIn:
519                 var = FindVariable(symbolName, mAttribs);
520                 break;
521             case EvqFragmentOut:
522             case EvqFragmentInOut:
523                 var                  = FindVariable(symbolName, mOutputVariables);
524                 var->isFragmentInOut = qualifier == EvqFragmentInOut;
525                 break;
526             case EvqUniform:
527             {
528                 if (interfaceBlock)
529                 {
530                     var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks);
531                 }
532                 else
533                 {
534                     var = FindVariable(symbolName, mUniforms);
535                 }
536 
537                 // It's an internal error to reference an undefined user uniform
538                 ASSERT(!gl::IsBuiltInName(symbolName.data()) || var);
539             }
540             break;
541             case EvqBuffer:
542             {
543                 var =
544                     FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks);
545             }
546             break;
547             case EvqFragCoord:
548                 recordBuiltInVaryingUsed(symbol->variable(), &mFragCoordAdded, mInputVaryings);
549                 return;
550             case EvqFrontFacing:
551                 recordBuiltInVaryingUsed(symbol->variable(), &mFrontFacingAdded, mInputVaryings);
552                 return;
553             case EvqHelperInvocation:
554                 recordBuiltInVaryingUsed(symbol->variable(), &mHelperInvocationAdded,
555                                          mInputVaryings);
556                 return;
557             case EvqPointCoord:
558                 recordBuiltInVaryingUsed(symbol->variable(), &mPointCoordAdded, mInputVaryings);
559                 return;
560             case EvqNumWorkGroups:
561                 recordBuiltInAttributeUsed(symbol->variable(), &mNumWorkGroupsAdded);
562                 return;
563             case EvqWorkGroupID:
564                 recordBuiltInAttributeUsed(symbol->variable(), &mWorkGroupIDAdded);
565                 return;
566             case EvqLocalInvocationID:
567                 recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIDAdded);
568                 return;
569             case EvqGlobalInvocationID:
570                 recordBuiltInAttributeUsed(symbol->variable(), &mGlobalInvocationIDAdded);
571                 return;
572             case EvqLocalInvocationIndex:
573                 recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIndexAdded);
574                 return;
575             case EvqInstanceID:
576                 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
577                 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
578                 // InstanceID. Note that gl_InstanceID is not added to the symbol table for ESSL1
579                 // shaders.
580                 recordBuiltInAttributeUsed(symbol->variable(), &mInstanceIDAdded);
581                 return;
582             case EvqVertexID:
583                 recordBuiltInAttributeUsed(symbol->variable(), &mVertexIDAdded);
584                 return;
585             case EvqPosition:
586                 recordBuiltInVaryingUsed(symbol->variable(), &mPositionAdded, mOutputVaryings);
587                 return;
588             case EvqPointSize:
589                 recordBuiltInVaryingUsed(symbol->variable(), &mPointSizeAdded, mOutputVaryings);
590                 return;
591             case EvqDrawID:
592                 recordBuiltInAttributeUsed(symbol->variable(), &mDrawIDAdded);
593                 return;
594             case EvqLastFragData:
595                 recordBuiltInVaryingUsed(symbol->variable(), &mLastFragDataAdded, mInputVaryings);
596                 return;
597             case EvqFragColor:
598                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragColorAdded);
599                 return;
600             case EvqFragData:
601                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDataAdded);
602                 return;
603             case EvqFragDepth:
604                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthAdded);
605                 return;
606             case EvqSecondaryFragColorEXT:
607                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragColorEXTAdded);
608                 return;
609             case EvqSecondaryFragDataEXT:
610                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragDataEXTAdded);
611                 return;
612             case EvqInvocationID:
613                 recordBuiltInVaryingUsed(symbol->variable(), &mInvocationIDAdded, mInputVaryings);
614                 break;
615             case EvqPrimitiveIDIn:
616                 recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDInAdded, mInputVaryings);
617                 break;
618             case EvqPrimitiveID:
619                 if (mShaderType == GL_GEOMETRY_SHADER_EXT)
620                 {
621                     recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
622                                              mOutputVaryings);
623                 }
624                 else
625                 {
626                     ASSERT(mShaderType == GL_FRAGMENT_SHADER ||
627                            mShaderType == GL_TESS_CONTROL_SHADER ||
628                            mShaderType == GL_TESS_EVALUATION_SHADER);
629                     recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
630                                              mInputVaryings);
631                 }
632                 break;
633             case EvqLayer:
634                 if (mShaderType == GL_GEOMETRY_SHADER_EXT)
635                 {
636                     recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mOutputVaryings);
637                 }
638                 else if (mShaderType == GL_FRAGMENT_SHADER)
639                 {
640                     recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mInputVaryings);
641                 }
642                 else
643                 {
644                     ASSERT(mShaderType == GL_VERTEX_SHADER &&
645                            (IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2) ||
646                             IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview)));
647                 }
648                 break;
649             case EvqShared:
650                 if (mShaderType == GL_COMPUTE_SHADER)
651                 {
652                     recordBuiltInVaryingUsed(symbol->variable(), &mSharedVariableAdded,
653                                              mSharedVariables);
654                 }
655                 break;
656             case EvqClipDistance:
657                 recordBuiltInVaryingUsed(
658                     symbol->variable(), &mClipDistanceAdded,
659                     mShaderType == GL_FRAGMENT_SHADER ? mInputVaryings : mOutputVaryings);
660                 return;
661             case EvqCullDistance:
662                 recordBuiltInVaryingUsed(
663                     symbol->variable(), &mCullDistanceAdded,
664                     mShaderType == GL_FRAGMENT_SHADER ? mInputVaryings : mOutputVaryings);
665                 return;
666             case EvqSampleID:
667                 recordBuiltInVaryingUsed(symbol->variable(), &mSampleIDAdded, mInputVaryings);
668                 return;
669             case EvqSamplePosition:
670                 recordBuiltInVaryingUsed(symbol->variable(), &mSamplePositionAdded, mInputVaryings);
671                 return;
672             case EvqSampleMaskIn:
673                 recordBuiltInVaryingUsed(symbol->variable(), &mSampleMaskInAdded, mInputVaryings);
674                 return;
675             case EvqSampleMask:
676                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSampleMaskAdded);
677                 return;
678             case EvqPatchVerticesIn:
679                 recordBuiltInVaryingUsed(symbol->variable(), &mPatchVerticesInAdded,
680                                          mInputVaryings);
681                 break;
682             case EvqTessCoord:
683                 recordBuiltInVaryingUsed(symbol->variable(), &mTessCoordAdded, mInputVaryings);
684                 break;
685             case EvqTessLevelOuter:
686                 if (mShaderType == GL_TESS_CONTROL_SHADER)
687                 {
688                     recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded,
689                                              mOutputVaryings);
690                 }
691                 else
692                 {
693                     ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER);
694                     recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelOuterAdded,
695                                              mInputVaryings);
696                 }
697                 break;
698             case EvqTessLevelInner:
699                 if (mShaderType == GL_TESS_CONTROL_SHADER)
700                 {
701                     recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded,
702                                              mOutputVaryings);
703                 }
704                 else
705                 {
706                     ASSERT(mShaderType == GL_TESS_EVALUATION_SHADER);
707                     recordBuiltInVaryingUsed(symbol->variable(), &mTessLevelInnerAdded,
708                                              mInputVaryings);
709                 }
710                 break;
711             case EvqBoundingBox:
712                 recordBuiltInVaryingUsed(symbol->variable(), &mBoundingBoxAdded, mOutputVaryings);
713                 break;
714             default:
715                 break;
716         }
717     }
718     if (var)
719     {
720         MarkActive(var);
721     }
722 }
723 
setFieldOrVariableProperties(const TType & type,bool staticUse,bool isShaderIOBlock,bool isPatch,ShaderVariable * variableOut) const724 void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
725                                                              bool staticUse,
726                                                              bool isShaderIOBlock,
727                                                              bool isPatch,
728                                                              ShaderVariable *variableOut) const
729 {
730     ASSERT(variableOut);
731 
732     variableOut->staticUse       = staticUse;
733     variableOut->isShaderIOBlock = isShaderIOBlock;
734     variableOut->isPatch         = isPatch;
735 
736     const TStructure *structure           = type.getStruct();
737     const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
738     if (structure)
739     {
740         // Structures use a NONE type that isn't exposed outside ANGLE.
741         variableOut->type = GL_NONE;
742         if (structure->symbolType() != SymbolType::Empty)
743         {
744             variableOut->structOrBlockName = structure->name().data();
745         }
746 
747         const TFieldList &fields = structure->fields();
748 
749         for (const TField *field : fields)
750         {
751             // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
752             // ShaderVariable objects.
753             ShaderVariable fieldVariable;
754             setFieldProperties(*field->type(), field->name(), staticUse, isShaderIOBlock, isPatch,
755                                field->symbolType(), &fieldVariable);
756             variableOut->fields.push_back(fieldVariable);
757         }
758     }
759     else if (interfaceBlock && isShaderIOBlock)
760     {
761         const bool isPerVertex = (interfaceBlock->name() == "gl_PerVertex");
762         variableOut->type      = GL_NONE;
763         if (interfaceBlock->symbolType() != SymbolType::Empty)
764         {
765             variableOut->structOrBlockName = interfaceBlock->name().data();
766             variableOut->mappedStructOrBlockName =
767                 isPerVertex ? interfaceBlock->name().data()
768                             : HashName(interfaceBlock->name(), mHashFunction, nullptr).data();
769         }
770         const TFieldList &fields = interfaceBlock->fields();
771         for (const TField *field : fields)
772         {
773             ShaderVariable fieldVariable;
774 
775             setFieldProperties(*field->type(), field->name(), staticUse, true, isPatch,
776                                field->symbolType(), &fieldVariable);
777             fieldVariable.isShaderIOBlock = true;
778             variableOut->fields.push_back(fieldVariable);
779         }
780     }
781     else
782     {
783         variableOut->type      = GLVariableType(type);
784         variableOut->precision = GLVariablePrecision(type);
785     }
786 
787     const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
788     if (!arraySizes.empty())
789     {
790         variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end());
791 
792         if (arraySizes[0] == 0)
793         {
794             // Tessellation Control & Evaluation shader inputs:
795             // Declaring an array size is optional. If no size is specified, it will be taken from
796             // the implementation-dependent maximum patch size (gl_MaxPatchVertices).
797             if (type.getQualifier() == EvqTessControlIn ||
798                 type.getQualifier() == EvqTessEvaluationIn)
799             {
800                 variableOut->arraySizes[0] = mResources.MaxPatchVertices;
801             }
802 
803             // Tessellation Control shader outputs:
804             // Declaring an array size is optional. If no size is specified, it will be taken from
805             // output patch size declared in the shader.
806             if (type.getQualifier() == EvqTessControlOut)
807             {
808                 ASSERT(mTessControlShaderOutputVertices > 0);
809                 variableOut->arraySizes[0] = mTessControlShaderOutputVertices;
810             }
811         }
812     }
813 }
814 
setFieldProperties(const TType & type,const ImmutableString & name,bool staticUse,bool isShaderIOBlock,bool isPatch,SymbolType symbolType,ShaderVariable * variableOut) const815 void CollectVariablesTraverser::setFieldProperties(const TType &type,
816                                                    const ImmutableString &name,
817                                                    bool staticUse,
818                                                    bool isShaderIOBlock,
819                                                    bool isPatch,
820                                                    SymbolType symbolType,
821                                                    ShaderVariable *variableOut) const
822 {
823     ASSERT(variableOut);
824     setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);
825     variableOut->name.assign(name.data(), name.length());
826     variableOut->mappedName = (symbolType == SymbolType::BuiltIn)
827                                   ? name.data()
828                                   : HashName(name, mHashFunction, nullptr).data();
829 }
830 
setCommonVariableProperties(const TType & type,const TVariable & variable,ShaderVariable * variableOut) const831 void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
832                                                             const TVariable &variable,
833                                                             ShaderVariable *variableOut) const
834 {
835     ASSERT(variableOut);
836     ASSERT(type.getInterfaceBlock() == nullptr || IsShaderIoBlock(type.getQualifier()) ||
837            type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut);
838 
839     const bool staticUse       = mSymbolTable->isStaticallyUsed(variable);
840     const bool isShaderIOBlock = type.getInterfaceBlock() != nullptr;
841     const bool isPatch = type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut;
842 
843     setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);
844 
845     const bool isNamed = variable.symbolType() != SymbolType::Empty;
846 
847     ASSERT(isNamed || isShaderIOBlock);
848     if (isNamed)
849     {
850         variableOut->name.assign(variable.name().data(), variable.name().length());
851         variableOut->mappedName = getMappedName(&variable);
852     }
853 
854     // For I/O blocks, additionally store the name of the block as blockName.  If the variable is
855     // unnamed, this name will be used instead for the purpose of interface matching.
856     if (isShaderIOBlock)
857     {
858         const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
859         ASSERT(interfaceBlock);
860 
861         variableOut->structOrBlockName.assign(interfaceBlock->name().data(),
862                                               interfaceBlock->name().length());
863         variableOut->mappedStructOrBlockName =
864             HashName(interfaceBlock->name(), mHashFunction, nullptr).data();
865         variableOut->isShaderIOBlock = true;
866     }
867 }
868 
recordAttribute(const TIntermSymbol & variable) const869 ShaderVariable CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
870 {
871     const TType &type = variable.getType();
872     ASSERT(!type.getStruct());
873 
874     ShaderVariable attribute;
875     setCommonVariableProperties(type, variable.variable(), &attribute);
876 
877     attribute.location = type.getLayoutQualifier().location;
878     return attribute;
879 }
880 
recordOutputVariable(const TIntermSymbol & variable) const881 ShaderVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
882 {
883     const TType &type = variable.getType();
884     ASSERT(!type.getStruct());
885 
886     ShaderVariable outputVariable;
887     setCommonVariableProperties(type, variable.variable(), &outputVariable);
888 
889     outputVariable.location = type.getLayoutQualifier().location;
890     outputVariable.index    = type.getLayoutQualifier().index;
891     outputVariable.yuv      = type.getLayoutQualifier().yuv;
892     return outputVariable;
893 }
894 
recordVarying(const TIntermSymbol & variable) const895 ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
896 {
897     const TType &type = variable.getType();
898 
899     ShaderVariable varying;
900     setCommonVariableProperties(type, variable.variable(), &varying);
901     varying.location = type.getLayoutQualifier().location;
902 
903     switch (type.getQualifier())
904     {
905         case EvqVaryingIn:
906         case EvqVaryingOut:
907         case EvqVertexOut:
908         case EvqSmoothOut:
909         case EvqFlatOut:
910         case EvqNoPerspectiveOut:
911         case EvqCentroidOut:
912         case EvqGeometryOut:
913         case EvqSampleOut:
914             if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant())
915             {
916                 varying.isInvariant = true;
917             }
918             break;
919         case EvqPatchIn:
920         case EvqPatchOut:
921             varying.isPatch = true;
922             break;
923         default:
924             break;
925     }
926 
927     varying.interpolation = GetInterpolationType(type.getQualifier());
928 
929     // Shader I/O block properties
930     if (type.getBasicType() == EbtInterfaceBlock)
931     {
932         bool isBlockImplicitLocation = false;
933         int location                 = type.getLayoutQualifier().location;
934 
935         // when a interface has not location in layout, assign to the zero.
936         if (location < 0)
937         {
938             location                = 0;
939             isBlockImplicitLocation = true;
940         }
941 
942         const TInterfaceBlock *blockType = type.getInterfaceBlock();
943         ASSERT(blockType->fields().size() == varying.fields.size());
944 
945         for (size_t fieldIndex = 0; fieldIndex < varying.fields.size(); ++fieldIndex)
946         {
947             const TField *blockField      = blockType->fields()[fieldIndex];
948             ShaderVariable &fieldVariable = varying.fields[fieldIndex];
949             const TType &fieldType        = *blockField->type();
950 
951             fieldVariable.hasImplicitLocation = isBlockImplicitLocation;
952             fieldVariable.isPatch             = varying.isPatch;
953 
954             int fieldLocation = fieldType.getLayoutQualifier().location;
955             if (fieldLocation >= 0)
956             {
957                 fieldVariable.hasImplicitLocation = false;
958                 fieldVariable.location            = fieldLocation;
959                 location                          = fieldLocation;
960             }
961             else
962             {
963                 fieldVariable.location = location;
964                 location += fieldType.getLocationCount();
965             }
966 
967             if (fieldType.getQualifier() != EvqGlobal)
968             {
969                 fieldVariable.interpolation = GetFieldInterpolationType(fieldType.getQualifier());
970             }
971         }
972     }
973 
974     return varying;
975 }
976 
recordInterfaceBlock(const char * instanceName,const TType & interfaceBlockType,InterfaceBlock * interfaceBlock) const977 void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName,
978                                                      const TType &interfaceBlockType,
979                                                      InterfaceBlock *interfaceBlock) const
980 {
981     ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);
982     ASSERT(interfaceBlock);
983 
984     const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
985     ASSERT(blockType);
986 
987     interfaceBlock->name       = blockType->name().data();
988     interfaceBlock->mappedName = getMappedName(blockType);
989 
990     const bool isGLInBuiltin = (instanceName != nullptr) && strncmp(instanceName, "gl_in", 5u) == 0;
991     if (instanceName != nullptr)
992     {
993         interfaceBlock->instanceName = instanceName;
994         const TSymbol *blockSymbol   = nullptr;
995         if (isGLInBuiltin)
996         {
997             blockSymbol = mSymbolTable->getGlInVariableWithArraySize();
998         }
999         else
1000         {
1001             blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName));
1002         }
1003         ASSERT(blockSymbol && blockSymbol->isVariable());
1004         interfaceBlock->staticUse =
1005             mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol));
1006     }
1007 
1008     ASSERT(!interfaceBlockType.isArrayOfArrays());  // Disallowed by GLSL ES 3.10 section 4.3.9
1009     interfaceBlock->arraySize =
1010         interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
1011 
1012     interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
1013     if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
1014         interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
1015     {
1016         // TODO(oetuaho): Remove setting isRowMajorLayout.
1017         interfaceBlock->isRowMajorLayout = false;
1018         interfaceBlock->binding          = blockType->blockBinding();
1019         interfaceBlock->layout           = GetBlockLayoutType(blockType->blockStorage());
1020     }
1021 
1022     // Gather field information
1023     bool anyFieldStaticallyUsed = false;
1024 
1025     for (const TField *field : blockType->fields())
1026     {
1027         const TType &fieldType = *field->type();
1028 
1029         bool staticUse = false;
1030         if (instanceName == nullptr)
1031         {
1032             // Static use of individual fields has been recorded, since they are present in the
1033             // symbol table as variables.
1034             const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name());
1035             ASSERT(fieldSymbol && fieldSymbol->isVariable());
1036             staticUse =
1037                 mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol));
1038             if (staticUse)
1039             {
1040                 anyFieldStaticallyUsed = true;
1041             }
1042         }
1043 
1044         ShaderVariable fieldVariable;
1045         setFieldProperties(fieldType, field->name(), staticUse, false, false, field->symbolType(),
1046                            &fieldVariable);
1047         fieldVariable.isRowMajorLayout =
1048             (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
1049         interfaceBlock->fields.push_back(fieldVariable);
1050     }
1051     if (anyFieldStaticallyUsed)
1052     {
1053         interfaceBlock->staticUse = true;
1054     }
1055 }
1056 
recordUniform(const TIntermSymbol & variable) const1057 ShaderVariable CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
1058 {
1059     ShaderVariable uniform;
1060     setCommonVariableProperties(variable.getType(), variable.variable(), &uniform);
1061     uniform.binding = variable.getType().getLayoutQualifier().binding;
1062     uniform.imageUnitFormat =
1063         GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat);
1064     uniform.location  = variable.getType().getLayoutQualifier().location;
1065     uniform.offset    = variable.getType().getLayoutQualifier().offset;
1066     uniform.readonly  = variable.getType().getMemoryQualifier().readonly;
1067     uniform.writeonly = variable.getType().getMemoryQualifier().writeonly;
1068     return uniform;
1069 }
1070 
visitDeclaration(Visit,TIntermDeclaration * node)1071 bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
1072 {
1073     const TIntermSequence &sequence = *(node->getSequence());
1074     ASSERT(!sequence.empty());
1075 
1076     const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
1077     TQualifier qualifier          = typedNode.getQualifier();
1078 
1079     bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
1080                             qualifier == EvqFragmentOut || qualifier == EvqFragmentInOut ||
1081                             qualifier == EvqUniform || IsVarying(qualifier);
1082 
1083     if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
1084     {
1085         return true;
1086     }
1087 
1088     for (TIntermNode *variableNode : sequence)
1089     {
1090         // The only case in which the sequence will not contain a TIntermSymbol node is
1091         // initialization. It will contain a TInterBinary node in that case. Since attributes,
1092         // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
1093         // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
1094         const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
1095         if (variable.variable().symbolType() == SymbolType::AngleInternal)
1096         {
1097             // Internal variables are not collected.
1098             continue;
1099         }
1100 
1101         // SpirvTransformer::transform uses a map of ShaderVariables, it needs member variables and
1102         // (named or unnamed) structure as ShaderVariable. at link between two shaders, validation
1103         // between of named and unnamed, needs the same structure, its members, and members order
1104         // except instance name.
1105         if (typedNode.getBasicType() == EbtInterfaceBlock && !IsShaderIoBlock(qualifier) &&
1106             qualifier != EvqPatchIn && qualifier != EvqPatchOut)
1107         {
1108             InterfaceBlock interfaceBlock;
1109             bool isUnnamed    = variable.variable().symbolType() == SymbolType::Empty;
1110             const TType &type = variable.getType();
1111             recordInterfaceBlock(isUnnamed ? nullptr : variable.getName().data(), type,
1112                                  &interfaceBlock);
1113 
1114             // all fields in interface block will be added for updating interface variables because
1115             // the temporal structure variable will be ignored.
1116             switch (qualifier)
1117             {
1118                 case EvqUniform:
1119                     mUniformBlocks->push_back(interfaceBlock);
1120                     break;
1121                 case EvqBuffer:
1122                     mShaderStorageBlocks->push_back(interfaceBlock);
1123                     break;
1124                 default:
1125                     UNREACHABLE();
1126             }
1127         }
1128         else
1129         {
1130             ASSERT(variable.variable().symbolType() != SymbolType::Empty ||
1131                    IsShaderIoBlock(qualifier) || qualifier == EvqPatchIn ||
1132                    qualifier == EvqPatchOut);
1133             switch (qualifier)
1134             {
1135                 case EvqAttribute:
1136                 case EvqVertexIn:
1137                     mAttribs->push_back(recordAttribute(variable));
1138                     break;
1139                 case EvqFragmentOut:
1140                 case EvqFragmentInOut:
1141                     mOutputVariables->push_back(recordOutputVariable(variable));
1142                     break;
1143                 case EvqUniform:
1144                     mUniforms->push_back(recordUniform(variable));
1145                     break;
1146                 default:
1147                     if (IsVaryingIn(qualifier))
1148                     {
1149                         mInputVaryings->push_back(recordVarying(variable));
1150                     }
1151                     else
1152                     {
1153                         ASSERT(IsVaryingOut(qualifier));
1154                         mOutputVaryings->push_back(recordVarying(variable));
1155                     }
1156                     break;
1157             }
1158         }
1159     }
1160 
1161     // None of the recorded variables can have initializers, so we don't need to traverse the
1162     // declarators.
1163     return false;
1164 }
1165 
findNamedInterfaceBlock(const ImmutableString & blockName) const1166 InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(
1167     const ImmutableString &blockName) const
1168 {
1169     InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);
1170     if (!namedBlock)
1171     {
1172         namedBlock = FindVariable(blockName, mShaderStorageBlocks);
1173     }
1174     return namedBlock;
1175 }
1176 
visitBinary(Visit,TIntermBinary * binaryNode)1177 bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
1178 {
1179     if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
1180     {
1181         // NOTE: we do not determine static use / activeness for individual blocks of an array.
1182         TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
1183         ASSERT(blockNode);
1184 
1185         TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
1186         ASSERT(constantUnion);
1187 
1188         InterfaceBlock *namedBlock = nullptr;
1189 
1190         bool traverseIndexExpression         = false;
1191         TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();
1192         if (interfaceIndexingNode)
1193         {
1194             ASSERT(interfaceIndexingNode->getOp() == EOpIndexDirect ||
1195                    interfaceIndexingNode->getOp() == EOpIndexIndirect);
1196             traverseIndexExpression = true;
1197             blockNode               = interfaceIndexingNode->getLeft();
1198         }
1199 
1200         const TType &interfaceNodeType        = blockNode->getType();
1201         const TInterfaceBlock *interfaceBlock = interfaceNodeType.getInterfaceBlock();
1202         const TQualifier qualifier            = interfaceNodeType.getQualifier();
1203 
1204         // If it's a shader I/O block, look in varyings
1205         ShaderVariable *ioBlockVar = nullptr;
1206         if (qualifier == EvqPerVertexIn)
1207         {
1208             TIntermSymbol *symbolNode = blockNode->getAsSymbolNode();
1209             ASSERT(symbolNode);
1210             recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexInAdded, mInputVaryings);
1211             ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);
1212         }
1213         else if (IsVaryingIn(qualifier))
1214         {
1215             ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);
1216         }
1217         else if (qualifier == EvqPerVertexOut)
1218         {
1219             TIntermSymbol *symbolNode = blockNode->getAsSymbolNode();
1220             ASSERT(symbolNode);
1221             recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexOutAdded, mOutputVaryings);
1222             ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
1223         }
1224         else if (IsVaryingOut(qualifier))
1225         {
1226             ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
1227         }
1228 
1229         if (ioBlockVar)
1230         {
1231             MarkActive(ioBlockVar);
1232         }
1233         else
1234         {
1235             if (!namedBlock)
1236             {
1237                 namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
1238             }
1239             ASSERT(namedBlock);
1240             ASSERT(namedBlock->staticUse);
1241             namedBlock->active      = true;
1242             unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
1243             ASSERT(fieldIndex < namedBlock->fields.size());
1244             // TODO(oetuaho): Would be nicer to record static use of fields of named interface
1245             // blocks more accurately at parse time - now we only mark the fields statically used if
1246             // they are active. http://anglebug.com/2440 We need to mark this field and all of its
1247             // sub-fields, as static/active
1248             MarkActive(&namedBlock->fields[fieldIndex]);
1249         }
1250 
1251         if (traverseIndexExpression)
1252         {
1253             ASSERT(interfaceIndexingNode);
1254             interfaceIndexingNode->getRight()->traverse(this);
1255         }
1256         return false;
1257     }
1258 
1259     return true;
1260 }
1261 
1262 }  // anonymous namespace
1263 
CollectVariables(TIntermBlock * root,std::vector<ShaderVariable> * attributes,std::vector<ShaderVariable> * outputVariables,std::vector<ShaderVariable> * uniforms,std::vector<ShaderVariable> * inputVaryings,std::vector<ShaderVariable> * outputVaryings,std::vector<ShaderVariable> * sharedVariables,std::vector<InterfaceBlock> * uniformBlocks,std::vector<InterfaceBlock> * shaderStorageBlocks,ShHashFunction64 hashFunction,TSymbolTable * symbolTable,GLenum shaderType,const TExtensionBehavior & extensionBehavior,const ShBuiltInResources & resources,int tessControlShaderOutputVertices)1264 void CollectVariables(TIntermBlock *root,
1265                       std::vector<ShaderVariable> *attributes,
1266                       std::vector<ShaderVariable> *outputVariables,
1267                       std::vector<ShaderVariable> *uniforms,
1268                       std::vector<ShaderVariable> *inputVaryings,
1269                       std::vector<ShaderVariable> *outputVaryings,
1270                       std::vector<ShaderVariable> *sharedVariables,
1271                       std::vector<InterfaceBlock> *uniformBlocks,
1272                       std::vector<InterfaceBlock> *shaderStorageBlocks,
1273                       ShHashFunction64 hashFunction,
1274                       TSymbolTable *symbolTable,
1275                       GLenum shaderType,
1276                       const TExtensionBehavior &extensionBehavior,
1277                       const ShBuiltInResources &resources,
1278                       int tessControlShaderOutputVertices)
1279 {
1280     CollectVariablesTraverser collect(
1281         attributes, outputVariables, uniforms, inputVaryings, outputVaryings, sharedVariables,
1282         uniformBlocks, shaderStorageBlocks, hashFunction, symbolTable, shaderType,
1283         extensionBehavior, resources, tessControlShaderOutputVertices);
1284     root->traverse(&collect);
1285 }
1286 
1287 }  // namespace sh
1288