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