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