• 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         case EvqPixelLocalEXT:
50             return BlockType::PIXEL_LOCAL_EXT;
51         default:
52             UNREACHABLE();
53             return BlockType::BLOCK_UNIFORM;
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         if (structure->symbolType() != SymbolType::Empty)
750         {
751             variableOut->structOrBlockName = structure->name().data();
752         }
753 
754         const TFieldList &fields = structure->fields();
755 
756         for (const TField *field : fields)
757         {
758             // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
759             // ShaderVariable objects.
760             ShaderVariable fieldVariable;
761             setFieldProperties(*field->type(), field->name(), staticUse, isShaderIOBlock, isPatch,
762                                field->symbolType(), &fieldVariable);
763             variableOut->fields.push_back(fieldVariable);
764         }
765     }
766     else if (interfaceBlock && isShaderIOBlock)
767     {
768         const bool isPerVertex = (interfaceBlock->name() == "gl_PerVertex");
769         variableOut->type      = GL_NONE;
770         if (interfaceBlock->symbolType() != SymbolType::Empty)
771         {
772             variableOut->structOrBlockName = interfaceBlock->name().data();
773             variableOut->mappedStructOrBlockName =
774                 isPerVertex ? interfaceBlock->name().data()
775                             : HashName(interfaceBlock->name(), mHashFunction, nullptr).data();
776         }
777         const TFieldList &fields = interfaceBlock->fields();
778         for (const TField *field : fields)
779         {
780             ShaderVariable fieldVariable;
781 
782             setFieldProperties(*field->type(), field->name(), staticUse, true, isPatch,
783                                field->symbolType(), &fieldVariable);
784             fieldVariable.isShaderIOBlock = true;
785             variableOut->fields.push_back(fieldVariable);
786         }
787     }
788     else
789     {
790         variableOut->type      = GLVariableType(type);
791         variableOut->precision = GLVariablePrecision(type);
792     }
793 
794     const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
795     if (!arraySizes.empty())
796     {
797         variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end());
798 
799         if (arraySizes[0] == 0)
800         {
801             // Tessellation Control & Evaluation shader inputs:
802             // Declaring an array size is optional. If no size is specified, it will be taken from
803             // the implementation-dependent maximum patch size (gl_MaxPatchVertices).
804             if (type.getQualifier() == EvqTessControlIn ||
805                 type.getQualifier() == EvqTessEvaluationIn)
806             {
807                 variableOut->arraySizes[0] = mResources.MaxPatchVertices;
808             }
809 
810             // Tessellation Control shader outputs:
811             // Declaring an array size is optional. If no size is specified, it will be taken from
812             // output patch size declared in the shader.
813             if (type.getQualifier() == EvqTessControlOut)
814             {
815                 ASSERT(mTessControlShaderOutputVertices > 0);
816                 variableOut->arraySizes[0] = mTessControlShaderOutputVertices;
817             }
818         }
819     }
820 }
821 
setFieldProperties(const TType & type,const ImmutableString & name,bool staticUse,bool isShaderIOBlock,bool isPatch,SymbolType symbolType,ShaderVariable * variableOut) const822 void CollectVariablesTraverser::setFieldProperties(const TType &type,
823                                                    const ImmutableString &name,
824                                                    bool staticUse,
825                                                    bool isShaderIOBlock,
826                                                    bool isPatch,
827                                                    SymbolType symbolType,
828                                                    ShaderVariable *variableOut) const
829 {
830     ASSERT(variableOut);
831     setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);
832     variableOut->name.assign(name.data(), name.length());
833     variableOut->mappedName = (symbolType == SymbolType::BuiltIn)
834                                   ? name.data()
835                                   : HashName(name, mHashFunction, nullptr).data();
836 }
837 
setCommonVariableProperties(const TType & type,const TVariable & variable,ShaderVariable * variableOut) const838 void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
839                                                             const TVariable &variable,
840                                                             ShaderVariable *variableOut) const
841 {
842     ASSERT(variableOut);
843     ASSERT(type.getInterfaceBlock() == nullptr || IsShaderIoBlock(type.getQualifier()) ||
844            type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut);
845 
846     const bool staticUse       = mSymbolTable->isStaticallyUsed(variable);
847     const bool isShaderIOBlock = type.getInterfaceBlock() != nullptr;
848     const bool isPatch = type.getQualifier() == EvqPatchIn || type.getQualifier() == EvqPatchOut;
849 
850     setFieldOrVariableProperties(type, staticUse, isShaderIOBlock, isPatch, variableOut);
851 
852     const bool isNamed = variable.symbolType() != SymbolType::Empty;
853 
854     ASSERT(isNamed || isShaderIOBlock);
855     if (isNamed)
856     {
857         variableOut->name.assign(variable.name().data(), variable.name().length());
858         variableOut->mappedName = getMappedName(&variable);
859     }
860 
861     // For I/O blocks, additionally store the name of the block as blockName.  If the variable is
862     // unnamed, this name will be used instead for the purpose of interface matching.
863     if (isShaderIOBlock)
864     {
865         const TInterfaceBlock *interfaceBlock = type.getInterfaceBlock();
866         ASSERT(interfaceBlock);
867 
868         variableOut->structOrBlockName.assign(interfaceBlock->name().data(),
869                                               interfaceBlock->name().length());
870         variableOut->mappedStructOrBlockName =
871             HashName(interfaceBlock->name(), mHashFunction, nullptr).data();
872         variableOut->isShaderIOBlock = true;
873     }
874 }
875 
recordAttribute(const TIntermSymbol & variable) const876 ShaderVariable CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
877 {
878     const TType &type = variable.getType();
879     ASSERT(!type.getStruct());
880 
881     ShaderVariable attribute;
882     setCommonVariableProperties(type, variable.variable(), &attribute);
883 
884     attribute.location = type.getLayoutQualifier().location;
885     return attribute;
886 }
887 
recordOutputVariable(const TIntermSymbol & variable) const888 ShaderVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
889 {
890     const TType &type = variable.getType();
891     ASSERT(!type.getStruct());
892 
893     ShaderVariable outputVariable;
894     setCommonVariableProperties(type, variable.variable(), &outputVariable);
895 
896     outputVariable.location = type.getLayoutQualifier().location;
897     outputVariable.index    = type.getLayoutQualifier().index;
898     outputVariable.yuv      = type.getLayoutQualifier().yuv;
899     return outputVariable;
900 }
901 
recordVarying(const TIntermSymbol & variable) const902 ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
903 {
904     const TType &type = variable.getType();
905 
906     ShaderVariable varying;
907     setCommonVariableProperties(type, variable.variable(), &varying);
908     varying.location = type.getLayoutQualifier().location;
909 
910     switch (type.getQualifier())
911     {
912         case EvqVaryingIn:
913         case EvqVaryingOut:
914         case EvqVertexOut:
915         case EvqSmoothOut:
916         case EvqFlatOut:
917         case EvqNoPerspectiveOut:
918         case EvqCentroidOut:
919         case EvqSampleOut:
920         case EvqNoPerspectiveCentroidOut:
921         case EvqNoPerspectiveSampleOut:
922         case EvqGeometryOut:
923             if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant())
924             {
925                 varying.isInvariant = true;
926             }
927             break;
928         case EvqPatchIn:
929         case EvqPatchOut:
930             varying.isPatch = true;
931             break;
932         default:
933             break;
934     }
935 
936     varying.interpolation = GetInterpolationType(type.getQualifier());
937 
938     // Shader I/O block properties
939     if (type.getBasicType() == EbtInterfaceBlock)
940     {
941         bool isBlockImplicitLocation = false;
942         int location                 = type.getLayoutQualifier().location;
943 
944         // when a interface has not location in layout, assign to the zero.
945         if (location < 0)
946         {
947             location                = 0;
948             isBlockImplicitLocation = true;
949         }
950 
951         const TInterfaceBlock *blockType = type.getInterfaceBlock();
952         ASSERT(blockType->fields().size() == varying.fields.size());
953 
954         for (size_t fieldIndex = 0; fieldIndex < varying.fields.size(); ++fieldIndex)
955         {
956             const TField *blockField      = blockType->fields()[fieldIndex];
957             ShaderVariable &fieldVariable = varying.fields[fieldIndex];
958             const TType &fieldType        = *blockField->type();
959 
960             fieldVariable.hasImplicitLocation = isBlockImplicitLocation;
961             fieldVariable.isPatch             = varying.isPatch;
962 
963             int fieldLocation = fieldType.getLayoutQualifier().location;
964             if (fieldLocation >= 0)
965             {
966                 fieldVariable.hasImplicitLocation = false;
967                 fieldVariable.location            = fieldLocation;
968                 location                          = fieldLocation;
969             }
970             else
971             {
972                 fieldVariable.location = location;
973                 location += fieldType.getLocationCount();
974             }
975 
976             if (fieldType.getQualifier() != EvqGlobal)
977             {
978                 fieldVariable.interpolation = GetFieldInterpolationType(fieldType.getQualifier());
979             }
980         }
981     }
982 
983     return varying;
984 }
985 
recordInterfaceBlock(const char * instanceName,const TType & interfaceBlockType,InterfaceBlock * interfaceBlock) const986 void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName,
987                                                      const TType &interfaceBlockType,
988                                                      InterfaceBlock *interfaceBlock) const
989 {
990     ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);
991     ASSERT(interfaceBlock);
992 
993     const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
994     ASSERT(blockType);
995 
996     interfaceBlock->name       = blockType->name().data();
997     interfaceBlock->mappedName = getMappedName(blockType);
998 
999     const bool isGLInBuiltin = (instanceName != nullptr) && strncmp(instanceName, "gl_in", 5u) == 0;
1000     if (instanceName != nullptr)
1001     {
1002         interfaceBlock->instanceName = instanceName;
1003         const TSymbol *blockSymbol   = nullptr;
1004         if (isGLInBuiltin)
1005         {
1006             blockSymbol = mSymbolTable->getGlInVariableWithArraySize();
1007         }
1008         else
1009         {
1010             blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName));
1011         }
1012         ASSERT(blockSymbol && blockSymbol->isVariable());
1013         interfaceBlock->staticUse =
1014             mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol));
1015     }
1016 
1017     ASSERT(!interfaceBlockType.isArrayOfArrays());  // Disallowed by GLSL ES 3.10 section 4.3.9
1018     interfaceBlock->arraySize =
1019         interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
1020 
1021     interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
1022     if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
1023         interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
1024     {
1025         // TODO(oetuaho): Remove setting isRowMajorLayout.
1026         interfaceBlock->isRowMajorLayout = false;
1027         interfaceBlock->binding          = blockType->blockBinding();
1028         interfaceBlock->layout           = GetBlockLayoutType(blockType->blockStorage());
1029     }
1030 
1031     // Consider an SSBO readonly if all its fields are readonly.  Note that ANGLE doesn't keep the
1032     // readonly qualifier applied to the interface block itself, but rather applies it to the
1033     // fields.
1034     ASSERT(!interfaceBlockType.getMemoryQualifier().readonly);
1035     bool isReadOnly = true;
1036 
1037     // Gather field information
1038     bool anyFieldStaticallyUsed = false;
1039 
1040     for (const TField *field : blockType->fields())
1041     {
1042         const TType &fieldType = *field->type();
1043 
1044         bool staticUse = false;
1045         if (instanceName == nullptr)
1046         {
1047             // Static use of individual fields has been recorded, since they are present in the
1048             // symbol table as variables.
1049             const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name());
1050             ASSERT(fieldSymbol && fieldSymbol->isVariable());
1051             staticUse =
1052                 mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol));
1053             if (staticUse)
1054             {
1055                 anyFieldStaticallyUsed = true;
1056             }
1057         }
1058 
1059         ShaderVariable fieldVariable;
1060         setFieldProperties(fieldType, field->name(), staticUse, false, false, field->symbolType(),
1061                            &fieldVariable);
1062         fieldVariable.isRowMajorLayout =
1063             (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
1064         interfaceBlock->fields.push_back(fieldVariable);
1065 
1066         // The SSBO is not readonly if any field is not readonly.
1067         if (!fieldType.getMemoryQualifier().readonly)
1068         {
1069             isReadOnly = false;
1070         }
1071     }
1072     if (anyFieldStaticallyUsed)
1073     {
1074         interfaceBlock->staticUse = true;
1075     }
1076     if (interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
1077     {
1078         interfaceBlock->isReadOnly = isReadOnly;
1079     }
1080 }
1081 
recordUniform(const TIntermSymbol & variable) const1082 ShaderVariable CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
1083 {
1084     ShaderVariable uniform;
1085     setCommonVariableProperties(variable.getType(), variable.variable(), &uniform);
1086     uniform.binding = variable.getType().getLayoutQualifier().binding;
1087     uniform.imageUnitFormat =
1088         GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat);
1089     uniform.location      = variable.getType().getLayoutQualifier().location;
1090     uniform.offset        = variable.getType().getLayoutQualifier().offset;
1091     uniform.rasterOrdered = variable.getType().getLayoutQualifier().rasterOrdered;
1092     uniform.readonly      = variable.getType().getMemoryQualifier().readonly;
1093     uniform.writeonly     = variable.getType().getMemoryQualifier().writeonly;
1094     return uniform;
1095 }
1096 
visitDeclaration(Visit,TIntermDeclaration * node)1097 bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
1098 {
1099     const TIntermSequence &sequence = *(node->getSequence());
1100     ASSERT(!sequence.empty());
1101 
1102     const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
1103     TQualifier qualifier          = typedNode.getQualifier();
1104 
1105     bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
1106                             qualifier == EvqFragmentOut || qualifier == EvqFragmentInOut ||
1107                             qualifier == EvqUniform || IsVarying(qualifier);
1108 
1109     if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
1110     {
1111         return true;
1112     }
1113 
1114     for (TIntermNode *variableNode : sequence)
1115     {
1116         // The only case in which the sequence will not contain a TIntermSymbol node is
1117         // initialization. It will contain a TInterBinary node in that case. Since attributes,
1118         // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
1119         // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
1120         const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
1121         if (variable.variable().symbolType() == SymbolType::AngleInternal)
1122         {
1123             // Internal variables are not collected.
1124             continue;
1125         }
1126 
1127         // SpirvTransformer::transform uses a map of ShaderVariables, it needs member variables and
1128         // (named or unnamed) structure as ShaderVariable. at link between two shaders, validation
1129         // between of named and unnamed, needs the same structure, its members, and members order
1130         // except instance name.
1131         if (typedNode.getBasicType() == EbtInterfaceBlock && !IsShaderIoBlock(qualifier) &&
1132             qualifier != EvqPatchIn && qualifier != EvqPatchOut)
1133         {
1134             InterfaceBlock interfaceBlock;
1135             bool isUnnamed    = variable.variable().symbolType() == SymbolType::Empty;
1136             const TType &type = variable.getType();
1137             recordInterfaceBlock(isUnnamed ? nullptr : variable.getName().data(), type,
1138                                  &interfaceBlock);
1139 
1140             // all fields in interface block will be added for updating interface variables because
1141             // the temporal structure variable will be ignored.
1142             switch (qualifier)
1143             {
1144                 case EvqUniform:
1145                     mUniformBlocks->push_back(interfaceBlock);
1146                     break;
1147                 case EvqBuffer:
1148                     mShaderStorageBlocks->push_back(interfaceBlock);
1149                     break;
1150                 case EvqPixelLocalEXT:
1151                     // EXT_shader_pixel_local_storage is completely self-contained within the
1152                     // shader, so we don't need to gather any info on it.
1153                     break;
1154                 default:
1155                     UNREACHABLE();
1156             }
1157         }
1158         else
1159         {
1160             ASSERT(variable.variable().symbolType() != SymbolType::Empty ||
1161                    IsShaderIoBlock(qualifier) || qualifier == EvqPatchIn ||
1162                    qualifier == EvqPatchOut);
1163             switch (qualifier)
1164             {
1165                 case EvqAttribute:
1166                 case EvqVertexIn:
1167                     mAttribs->push_back(recordAttribute(variable));
1168                     break;
1169                 case EvqFragmentOut:
1170                 case EvqFragmentInOut:
1171                     mOutputVariables->push_back(recordOutputVariable(variable));
1172                     break;
1173                 case EvqUniform:
1174                     mUniforms->push_back(recordUniform(variable));
1175                     break;
1176                 default:
1177                     if (IsVaryingIn(qualifier))
1178                     {
1179                         mInputVaryings->push_back(recordVarying(variable));
1180                     }
1181                     else
1182                     {
1183                         ASSERT(IsVaryingOut(qualifier));
1184                         mOutputVaryings->push_back(recordVarying(variable));
1185                     }
1186                     break;
1187             }
1188         }
1189     }
1190 
1191     // None of the recorded variables can have initializers, so we don't need to traverse the
1192     // declarators.
1193     return false;
1194 }
1195 
findNamedInterfaceBlock(const ImmutableString & blockName) const1196 InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(
1197     const ImmutableString &blockName) const
1198 {
1199     InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);
1200     if (!namedBlock)
1201     {
1202         namedBlock = FindVariable(blockName, mShaderStorageBlocks);
1203     }
1204     return namedBlock;
1205 }
1206 
visitBinary(Visit,TIntermBinary * binaryNode)1207 bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
1208 {
1209     if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
1210     {
1211         // NOTE: we do not determine static use / activeness for individual blocks of an array.
1212         TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
1213         ASSERT(blockNode);
1214 
1215         TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
1216         ASSERT(constantUnion);
1217 
1218         InterfaceBlock *namedBlock = nullptr;
1219 
1220         bool traverseIndexExpression         = false;
1221         TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();
1222         if (interfaceIndexingNode)
1223         {
1224             ASSERT(interfaceIndexingNode->getOp() == EOpIndexDirect ||
1225                    interfaceIndexingNode->getOp() == EOpIndexIndirect);
1226             traverseIndexExpression = true;
1227             blockNode               = interfaceIndexingNode->getLeft();
1228         }
1229 
1230         const TType &interfaceNodeType        = blockNode->getType();
1231         const TInterfaceBlock *interfaceBlock = interfaceNodeType.getInterfaceBlock();
1232         const TQualifier qualifier            = interfaceNodeType.getQualifier();
1233 
1234         // If it's a shader I/O block, look in varyings
1235         ShaderVariable *ioBlockVar = nullptr;
1236         if (qualifier == EvqPerVertexIn)
1237         {
1238             TIntermSymbol *symbolNode = blockNode->getAsSymbolNode();
1239             ASSERT(symbolNode);
1240             recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexInAdded, mInputVaryings);
1241             ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);
1242         }
1243         else if (IsVaryingIn(qualifier))
1244         {
1245             ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mInputVaryings);
1246         }
1247         else if (qualifier == EvqPerVertexOut)
1248         {
1249             TIntermSymbol *symbolNode = blockNode->getAsSymbolNode();
1250             ASSERT(symbolNode);
1251             recordBuiltInVaryingUsed(symbolNode->variable(), &mPerVertexOutAdded, mOutputVaryings);
1252             ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
1253         }
1254         else if (IsVaryingOut(qualifier))
1255         {
1256             ioBlockVar = FindShaderIOBlockVariable(interfaceBlock->name(), mOutputVaryings);
1257         }
1258 
1259         if (ioBlockVar)
1260         {
1261             MarkActive(ioBlockVar);
1262         }
1263         else if (qualifier != EvqPixelLocalEXT)
1264         {
1265 
1266             if (!namedBlock)
1267             {
1268                 namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
1269             }
1270             ASSERT(namedBlock);
1271             ASSERT(namedBlock->staticUse);
1272             namedBlock->active      = true;
1273             unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
1274             ASSERT(fieldIndex < namedBlock->fields.size());
1275             // TODO(oetuaho): Would be nicer to record static use of fields of named interface
1276             // blocks more accurately at parse time - now we only mark the fields statically used if
1277             // they are active. http://anglebug.com/2440 We need to mark this field and all of its
1278             // sub-fields, as static/active
1279             MarkActive(&namedBlock->fields[fieldIndex]);
1280         }
1281 
1282         if (traverseIndexExpression)
1283         {
1284             ASSERT(interfaceIndexingNode);
1285             interfaceIndexingNode->getRight()->traverse(this);
1286         }
1287         return false;
1288     }
1289 
1290     return true;
1291 }
1292 
1293 }  // anonymous namespace
1294 
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)1295 void CollectVariables(TIntermBlock *root,
1296                       std::vector<ShaderVariable> *attributes,
1297                       std::vector<ShaderVariable> *outputVariables,
1298                       std::vector<ShaderVariable> *uniforms,
1299                       std::vector<ShaderVariable> *inputVaryings,
1300                       std::vector<ShaderVariable> *outputVaryings,
1301                       std::vector<ShaderVariable> *sharedVariables,
1302                       std::vector<InterfaceBlock> *uniformBlocks,
1303                       std::vector<InterfaceBlock> *shaderStorageBlocks,
1304                       ShHashFunction64 hashFunction,
1305                       TSymbolTable *symbolTable,
1306                       GLenum shaderType,
1307                       const TExtensionBehavior &extensionBehavior,
1308                       const ShBuiltInResources &resources,
1309                       int tessControlShaderOutputVertices)
1310 {
1311     CollectVariablesTraverser collect(
1312         attributes, outputVariables, uniforms, inputVaryings, outputVaryings, sharedVariables,
1313         uniformBlocks, shaderStorageBlocks, hashFunction, symbolTable, shaderType,
1314         extensionBehavior, resources, tessControlShaderOutputVertices);
1315     root->traverse(&collect);
1316 }
1317 
1318 }  // namespace sh
1319