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