• 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 
41 // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
GetBlockType(TQualifier qualifier)42 BlockType GetBlockType(TQualifier qualifier)
43 {
44     switch (qualifier)
45     {
46         case EvqUniform:
47             return BlockType::BLOCK_UNIFORM;
48         case EvqBuffer:
49             return BlockType::BLOCK_BUFFER;
50         case EvqPerVertexIn:
51             return BlockType::BLOCK_IN;
52         default:
53             UNREACHABLE();
54             return BlockType::BLOCK_UNIFORM;
55     }
56 }
57 
58 template <class VarT>
FindVariable(const ImmutableString & name,std::vector<VarT> * infoList)59 VarT *FindVariable(const ImmutableString &name, std::vector<VarT> *infoList)
60 {
61     // TODO(zmo): optimize this function.
62     for (size_t ii = 0; ii < infoList->size(); ++ii)
63     {
64         if (name == (*infoList)[ii].name)
65             return &((*infoList)[ii]);
66     }
67 
68     return nullptr;
69 }
70 
71 // Note that this shouldn't be called for interface blocks - active information is collected for
72 // individual fields in case of interface blocks.
MarkActive(ShaderVariable * variable)73 void MarkActive(ShaderVariable *variable)
74 {
75     if (!variable->active)
76     {
77         if (variable->isStruct())
78         {
79             // Conservatively assume all fields are statically used as well.
80             for (auto &field : variable->fields)
81             {
82                 MarkActive(&field);
83             }
84         }
85         ASSERT(variable->staticUse);
86         variable->active = true;
87     }
88 }
89 
FindVariableInInterfaceBlock(const ImmutableString & name,const TInterfaceBlock * interfaceBlock,std::vector<InterfaceBlock> * infoList)90 ShaderVariable *FindVariableInInterfaceBlock(const ImmutableString &name,
91                                              const TInterfaceBlock *interfaceBlock,
92                                              std::vector<InterfaceBlock> *infoList)
93 {
94     ASSERT(interfaceBlock);
95     InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList);
96     ASSERT(namedBlock);
97 
98     // Set static use on the parent interface block here
99     namedBlock->staticUse = true;
100     namedBlock->active    = true;
101     return FindVariable(name, &namedBlock->fields);
102 }
103 
104 // Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
105 // and interface blocks.
106 class CollectVariablesTraverser : public TIntermTraverser
107 {
108   public:
109     CollectVariablesTraverser(std::vector<Attribute> *attribs,
110                               std::vector<OutputVariable> *outputVariables,
111                               std::vector<Uniform> *uniforms,
112                               std::vector<Varying> *inputVaryings,
113                               std::vector<Varying> *outputVaryings,
114                               std::vector<InterfaceBlock> *uniformBlocks,
115                               std::vector<InterfaceBlock> *shaderStorageBlocks,
116                               std::vector<InterfaceBlock> *inBlocks,
117                               ShHashFunction64 hashFunction,
118                               TSymbolTable *symbolTable,
119                               GLenum shaderType,
120                               const TExtensionBehavior &extensionBehavior);
121 
122     bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
123     void visitSymbol(TIntermSymbol *symbol) override;
124     bool visitDeclaration(Visit, TIntermDeclaration *node) override;
125     bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
126 
127   private:
128     std::string getMappedName(const TSymbol *symbol) const;
129 
130     void setFieldOrVariableProperties(const TType &type,
131                                       bool staticUse,
132                                       ShaderVariable *variableOut) const;
133     void setFieldProperties(const TType &type,
134                             const ImmutableString &name,
135                             bool staticUse,
136                             ShaderVariable *variableOut) const;
137     void setCommonVariableProperties(const TType &type,
138                                      const TVariable &variable,
139                                      ShaderVariable *variableOut) const;
140 
141     Attribute recordAttribute(const TIntermSymbol &variable) const;
142     OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
143     Varying recordVarying(const TIntermSymbol &variable) const;
144     void recordInterfaceBlock(const char *instanceName,
145                               const TType &interfaceBlockType,
146                               InterfaceBlock *interfaceBlock) const;
147     Uniform recordUniform(const TIntermSymbol &variable) const;
148 
149     void setBuiltInInfoFromSymbol(const TVariable &variable, ShaderVariable *info);
150 
151     void recordBuiltInVaryingUsed(const TVariable &variable,
152                                   bool *addedFlag,
153                                   std::vector<Varying> *varyings);
154     void recordBuiltInFragmentOutputUsed(const TVariable &variable, bool *addedFlag);
155     void recordBuiltInAttributeUsed(const TVariable &variable, bool *addedFlag);
156     InterfaceBlock *recordGLInUsed(const TType &glInType);
157     InterfaceBlock *findNamedInterfaceBlock(const ImmutableString &name) const;
158 
159     std::vector<Attribute> *mAttribs;
160     std::vector<OutputVariable> *mOutputVariables;
161     std::vector<Uniform> *mUniforms;
162     std::vector<Varying> *mInputVaryings;
163     std::vector<Varying> *mOutputVaryings;
164     std::vector<InterfaceBlock> *mUniformBlocks;
165     std::vector<InterfaceBlock> *mShaderStorageBlocks;
166     std::vector<InterfaceBlock> *mInBlocks;
167 
168     std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
169 
170     // Shader uniforms
171     bool mDepthRangeAdded;
172 
173     // Vertex Shader builtins
174     bool mInstanceIDAdded;
175     bool mVertexIDAdded;
176     bool mPointSizeAdded;
177     bool mDrawIDAdded;
178     bool mBaseVertexAdded;
179     bool mBaseInstanceAdded;
180 
181     // Vertex Shader and Geometry Shader builtins
182     bool mPositionAdded;
183 
184     // Fragment Shader builtins
185     bool mPointCoordAdded;
186     bool mFrontFacingAdded;
187     bool mFragCoordAdded;
188     bool mLastFragDataAdded;
189     bool mFragColorAdded;
190     bool mFragDataAdded;
191     bool mFragDepthEXTAdded;
192     bool mFragDepthAdded;
193     bool mSecondaryFragColorEXTAdded;
194     bool mSecondaryFragDataEXTAdded;
195 
196     // Geometry Shader builtins
197     bool mPerVertexInAdded;
198     bool mPrimitiveIDInAdded;
199     bool mInvocationIDAdded;
200 
201     // Geometry Shader and Fragment Shader builtins
202     bool mPrimitiveIDAdded;
203     bool mLayerAdded;
204 
205     ShHashFunction64 mHashFunction;
206 
207     GLenum mShaderType;
208     const TExtensionBehavior &mExtensionBehavior;
209 };
210 
CollectVariablesTraverser(std::vector<sh::Attribute> * attribs,std::vector<sh::OutputVariable> * outputVariables,std::vector<sh::Uniform> * uniforms,std::vector<sh::Varying> * inputVaryings,std::vector<sh::Varying> * outputVaryings,std::vector<sh::InterfaceBlock> * uniformBlocks,std::vector<sh::InterfaceBlock> * shaderStorageBlocks,std::vector<sh::InterfaceBlock> * inBlocks,ShHashFunction64 hashFunction,TSymbolTable * symbolTable,GLenum shaderType,const TExtensionBehavior & extensionBehavior)211 CollectVariablesTraverser::CollectVariablesTraverser(
212     std::vector<sh::Attribute> *attribs,
213     std::vector<sh::OutputVariable> *outputVariables,
214     std::vector<sh::Uniform> *uniforms,
215     std::vector<sh::Varying> *inputVaryings,
216     std::vector<sh::Varying> *outputVaryings,
217     std::vector<sh::InterfaceBlock> *uniformBlocks,
218     std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
219     std::vector<sh::InterfaceBlock> *inBlocks,
220     ShHashFunction64 hashFunction,
221     TSymbolTable *symbolTable,
222     GLenum shaderType,
223     const TExtensionBehavior &extensionBehavior)
224     : TIntermTraverser(true, false, false, symbolTable),
225       mAttribs(attribs),
226       mOutputVariables(outputVariables),
227       mUniforms(uniforms),
228       mInputVaryings(inputVaryings),
229       mOutputVaryings(outputVaryings),
230       mUniformBlocks(uniformBlocks),
231       mShaderStorageBlocks(shaderStorageBlocks),
232       mInBlocks(inBlocks),
233       mDepthRangeAdded(false),
234       mInstanceIDAdded(false),
235       mVertexIDAdded(false),
236       mPointSizeAdded(false),
237       mDrawIDAdded(false),
238       mBaseVertexAdded(false),
239       mBaseInstanceAdded(false),
240       mPositionAdded(false),
241       mPointCoordAdded(false),
242       mFrontFacingAdded(false),
243       mFragCoordAdded(false),
244       mLastFragDataAdded(false),
245       mFragColorAdded(false),
246       mFragDataAdded(false),
247       mFragDepthEXTAdded(false),
248       mFragDepthAdded(false),
249       mSecondaryFragColorEXTAdded(false),
250       mSecondaryFragDataEXTAdded(false),
251       mPerVertexInAdded(false),
252       mPrimitiveIDInAdded(false),
253       mInvocationIDAdded(false),
254       mPrimitiveIDAdded(false),
255       mLayerAdded(false),
256       mHashFunction(hashFunction),
257       mShaderType(shaderType),
258       mExtensionBehavior(extensionBehavior)
259 {}
260 
getMappedName(const TSymbol * symbol) const261 std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const
262 {
263     return HashName(symbol, mHashFunction, nullptr).data();
264 }
265 
setBuiltInInfoFromSymbol(const TVariable & variable,ShaderVariable * info)266 void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variable,
267                                                          ShaderVariable *info)
268 {
269     const TType &type = variable.getType();
270 
271     info->name       = variable.name().data();
272     info->mappedName = variable.name().data();
273     info->type       = GLVariableType(type);
274     info->precision  = GLVariablePrecision(type);
275     if (auto *arraySizes = type.getArraySizes())
276     {
277         info->arraySizes.assign(arraySizes->begin(), arraySizes->end());
278     }
279 }
280 
recordBuiltInVaryingUsed(const TVariable & variable,bool * addedFlag,std::vector<Varying> * varyings)281 void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable,
282                                                          bool *addedFlag,
283                                                          std::vector<Varying> *varyings)
284 {
285     ASSERT(varyings);
286     if (!(*addedFlag))
287     {
288         Varying info;
289         setBuiltInInfoFromSymbol(variable, &info);
290         info.staticUse   = true;
291         info.active      = true;
292         info.isInvariant = mSymbolTable->isVaryingInvariant(variable);
293         varyings->push_back(info);
294         (*addedFlag) = true;
295     }
296 }
297 
recordBuiltInFragmentOutputUsed(const TVariable & variable,bool * addedFlag)298 void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const TVariable &variable,
299                                                                 bool *addedFlag)
300 {
301     if (!(*addedFlag))
302     {
303         OutputVariable info;
304         setBuiltInInfoFromSymbol(variable, &info);
305         info.staticUse = true;
306         info.active    = true;
307         mOutputVariables->push_back(info);
308         (*addedFlag) = true;
309     }
310 }
311 
recordBuiltInAttributeUsed(const TVariable & variable,bool * addedFlag)312 void CollectVariablesTraverser::recordBuiltInAttributeUsed(const TVariable &variable,
313                                                            bool *addedFlag)
314 {
315     if (!(*addedFlag))
316     {
317         Attribute info;
318         setBuiltInInfoFromSymbol(variable, &info);
319         info.staticUse = true;
320         info.active    = true;
321         info.location  = -1;
322         mAttribs->push_back(info);
323         (*addedFlag) = true;
324     }
325 }
326 
recordGLInUsed(const TType & glInType)327 InterfaceBlock *CollectVariablesTraverser::recordGLInUsed(const TType &glInType)
328 {
329     if (!mPerVertexInAdded)
330     {
331         ASSERT(glInType.getQualifier() == EvqPerVertexIn);
332         InterfaceBlock info;
333         recordInterfaceBlock("gl_in", glInType, &info);
334 
335         mPerVertexInAdded = true;
336         mInBlocks->push_back(info);
337         return &mInBlocks->back();
338     }
339     else
340     {
341         return FindVariable(ImmutableString("gl_PerVertex"), mInBlocks);
342     }
343 }
344 
visitInvariantDeclaration(Visit visit,TIntermInvariantDeclaration * node)345 bool CollectVariablesTraverser::visitInvariantDeclaration(Visit visit,
346                                                           TIntermInvariantDeclaration *node)
347 {
348     // We should not mark variables as active just based on an invariant declaration, so we don't
349     // traverse the symbols declared invariant.
350     return false;
351 }
352 
353 // We want to check whether a uniform/varying is active because we need to skip updating inactive
354 // ones. We also only count the active ones in packing computing. Also, gl_FragCoord, gl_PointCoord,
355 // and gl_FrontFacing count toward varying counting if they are active in a fragment shader.
visitSymbol(TIntermSymbol * symbol)356 void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
357 {
358     ASSERT(symbol != nullptr);
359 
360     if (symbol->variable().symbolType() == SymbolType::AngleInternal ||
361         symbol->variable().symbolType() == SymbolType::Empty)
362     {
363         // Internal variables or nameless variables are not collected.
364         return;
365     }
366 
367     ShaderVariable *var = nullptr;
368 
369     const ImmutableString &symbolName = symbol->getName();
370 
371     // Check the qualifier from the variable, not from the symbol node. The node may have a
372     // different qualifier if it's the result of a folded ternary node.
373     TQualifier qualifier = symbol->variable().getType().getQualifier();
374 
375     if (IsVaryingIn(qualifier))
376     {
377         var = FindVariable(symbolName, mInputVaryings);
378     }
379     else if (IsVaryingOut(qualifier))
380     {
381         var = FindVariable(symbolName, mOutputVaryings);
382     }
383     else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
384     {
385         UNREACHABLE();
386     }
387     else if (symbolName == "gl_DepthRange")
388     {
389         ASSERT(qualifier == EvqUniform);
390 
391         if (!mDepthRangeAdded)
392         {
393             Uniform info;
394             const char kName[] = "gl_DepthRange";
395             info.name          = kName;
396             info.mappedName    = kName;
397             info.type          = GL_NONE;
398             info.precision     = GL_NONE;
399             info.staticUse     = true;
400             info.active        = true;
401 
402             ShaderVariable nearInfo(GL_FLOAT);
403             const char kNearName[] = "near";
404             nearInfo.name          = kNearName;
405             nearInfo.mappedName    = kNearName;
406             nearInfo.precision     = GL_HIGH_FLOAT;
407             nearInfo.staticUse     = true;
408             nearInfo.active        = true;
409 
410             ShaderVariable farInfo(GL_FLOAT);
411             const char kFarName[] = "far";
412             farInfo.name          = kFarName;
413             farInfo.mappedName    = kFarName;
414             farInfo.precision     = GL_HIGH_FLOAT;
415             farInfo.staticUse     = true;
416             farInfo.active        = true;
417 
418             ShaderVariable diffInfo(GL_FLOAT);
419             const char kDiffName[] = "diff";
420             diffInfo.name          = kDiffName;
421             diffInfo.mappedName    = kDiffName;
422             diffInfo.precision     = GL_HIGH_FLOAT;
423             diffInfo.staticUse     = true;
424             diffInfo.active        = true;
425 
426             info.fields.push_back(nearInfo);
427             info.fields.push_back(farInfo);
428             info.fields.push_back(diffInfo);
429 
430             mUniforms->push_back(info);
431             mDepthRangeAdded = true;
432         }
433     }
434     else
435     {
436         switch (qualifier)
437         {
438             case EvqAttribute:
439             case EvqVertexIn:
440                 var = FindVariable(symbolName, mAttribs);
441                 break;
442             case EvqFragmentOut:
443                 var = FindVariable(symbolName, mOutputVariables);
444                 break;
445             case EvqUniform:
446             {
447                 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
448                 if (interfaceBlock)
449                 {
450                     var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks);
451                 }
452                 else
453                 {
454                     var = FindVariable(symbolName, mUniforms);
455                 }
456 
457                 // It's an internal error to reference an undefined user uniform
458                 ASSERT(!symbolName.beginsWith("gl_") || var);
459             }
460             break;
461             case EvqBuffer:
462             {
463                 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
464                 var =
465                     FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks);
466             }
467             break;
468             case EvqFragCoord:
469                 recordBuiltInVaryingUsed(symbol->variable(), &mFragCoordAdded, mInputVaryings);
470                 return;
471             case EvqFrontFacing:
472                 recordBuiltInVaryingUsed(symbol->variable(), &mFrontFacingAdded, mInputVaryings);
473                 return;
474             case EvqPointCoord:
475                 recordBuiltInVaryingUsed(symbol->variable(), &mPointCoordAdded, mInputVaryings);
476                 return;
477             case EvqInstanceID:
478                 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
479                 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
480                 // InstanceID. Note that gl_InstanceID is not added to the symbol table for ESSL1
481                 // shaders.
482                 recordBuiltInAttributeUsed(symbol->variable(), &mInstanceIDAdded);
483                 return;
484             case EvqVertexID:
485                 recordBuiltInAttributeUsed(symbol->variable(), &mVertexIDAdded);
486                 return;
487             case EvqPosition:
488                 recordBuiltInVaryingUsed(symbol->variable(), &mPositionAdded, mOutputVaryings);
489                 return;
490             case EvqPointSize:
491                 recordBuiltInVaryingUsed(symbol->variable(), &mPointSizeAdded, mOutputVaryings);
492                 return;
493             case EvqDrawID:
494                 recordBuiltInAttributeUsed(symbol->variable(), &mDrawIDAdded);
495                 return;
496             case EvqBaseVertex:
497                 recordBuiltInAttributeUsed(symbol->variable(), &mBaseVertexAdded);
498                 return;
499             case EvqBaseInstance:
500                 recordBuiltInAttributeUsed(symbol->variable(), &mBaseInstanceAdded);
501                 return;
502             case EvqLastFragData:
503                 recordBuiltInVaryingUsed(symbol->variable(), &mLastFragDataAdded, mInputVaryings);
504                 return;
505             case EvqFragColor:
506                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragColorAdded);
507                 return;
508             case EvqFragData:
509                 if (!mFragDataAdded)
510                 {
511                     OutputVariable info;
512                     setBuiltInInfoFromSymbol(symbol->variable(), &info);
513                     if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))
514                     {
515                         ASSERT(info.arraySizes.size() == 1u);
516                         info.arraySizes.back() = 1u;
517                     }
518                     info.staticUse = true;
519                     info.active    = true;
520                     mOutputVariables->push_back(info);
521                     mFragDataAdded = true;
522                 }
523                 return;
524             case EvqFragDepthEXT:
525                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthEXTAdded);
526                 return;
527             case EvqFragDepth:
528                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthAdded);
529                 return;
530             case EvqSecondaryFragColorEXT:
531                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragColorEXTAdded);
532                 return;
533             case EvqSecondaryFragDataEXT:
534                 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragDataEXTAdded);
535                 return;
536             case EvqInvocationID:
537                 recordBuiltInVaryingUsed(symbol->variable(), &mInvocationIDAdded, mInputVaryings);
538                 break;
539             case EvqPrimitiveIDIn:
540                 recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDInAdded, mInputVaryings);
541                 break;
542             case EvqPrimitiveID:
543                 if (mShaderType == GL_GEOMETRY_SHADER_EXT)
544                 {
545                     recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
546                                              mOutputVaryings);
547                 }
548                 else
549                 {
550                     ASSERT(mShaderType == GL_FRAGMENT_SHADER);
551                     recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
552                                              mInputVaryings);
553                 }
554                 break;
555             case EvqLayer:
556                 if (mShaderType == GL_GEOMETRY_SHADER_EXT)
557                 {
558                     recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mOutputVaryings);
559                 }
560                 else if (mShaderType == GL_FRAGMENT_SHADER)
561                 {
562                     recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mInputVaryings);
563                 }
564                 else
565                 {
566                     ASSERT(mShaderType == GL_VERTEX_SHADER &&
567                            (IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2) ||
568                             IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview)));
569                 }
570                 break;
571             default:
572                 break;
573         }
574     }
575     if (var)
576     {
577         MarkActive(var);
578     }
579 }
580 
setFieldOrVariableProperties(const TType & type,bool staticUse,ShaderVariable * variableOut) const581 void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
582                                                              bool staticUse,
583                                                              ShaderVariable *variableOut) const
584 {
585     ASSERT(variableOut);
586 
587     variableOut->staticUse = staticUse;
588 
589     const TStructure *structure = type.getStruct();
590     if (!structure)
591     {
592         variableOut->type      = GLVariableType(type);
593         variableOut->precision = GLVariablePrecision(type);
594     }
595     else
596     {
597         // Structures use a NONE type that isn't exposed outside ANGLE.
598         variableOut->type = GL_NONE;
599         if (structure->symbolType() != SymbolType::Empty)
600         {
601             variableOut->structName = structure->name().data();
602         }
603 
604         const TFieldList &fields = structure->fields();
605 
606         for (const TField *field : fields)
607         {
608             // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
609             // ShaderVariable objects.
610             ShaderVariable fieldVariable;
611             setFieldProperties(*field->type(), field->name(), staticUse, &fieldVariable);
612             variableOut->fields.push_back(fieldVariable);
613         }
614     }
615     if (auto *arraySizes = type.getArraySizes())
616     {
617         variableOut->arraySizes.assign(arraySizes->begin(), arraySizes->end());
618     }
619 }
620 
setFieldProperties(const TType & type,const ImmutableString & name,bool staticUse,ShaderVariable * variableOut) const621 void CollectVariablesTraverser::setFieldProperties(const TType &type,
622                                                    const ImmutableString &name,
623                                                    bool staticUse,
624                                                    ShaderVariable *variableOut) const
625 {
626     ASSERT(variableOut);
627     setFieldOrVariableProperties(type, staticUse, variableOut);
628     variableOut->name.assign(name.data(), name.length());
629     variableOut->mappedName = HashName(name, mHashFunction, nullptr).data();
630 }
631 
setCommonVariableProperties(const TType & type,const TVariable & variable,ShaderVariable * variableOut) const632 void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
633                                                             const TVariable &variable,
634                                                             ShaderVariable *variableOut) const
635 {
636     ASSERT(variableOut);
637 
638     variableOut->staticUse = mSymbolTable->isStaticallyUsed(variable);
639     setFieldOrVariableProperties(type, variableOut->staticUse, variableOut);
640     ASSERT(variable.symbolType() != SymbolType::Empty);
641     variableOut->name.assign(variable.name().data(), variable.name().length());
642     variableOut->mappedName = getMappedName(&variable);
643 }
644 
recordAttribute(const TIntermSymbol & variable) const645 Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
646 {
647     const TType &type = variable.getType();
648     ASSERT(!type.getStruct());
649 
650     Attribute attribute;
651     setCommonVariableProperties(type, variable.variable(), &attribute);
652 
653     attribute.location = type.getLayoutQualifier().location;
654     return attribute;
655 }
656 
recordOutputVariable(const TIntermSymbol & variable) const657 OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
658 {
659     const TType &type = variable.getType();
660     ASSERT(!type.getStruct());
661 
662     OutputVariable outputVariable;
663     setCommonVariableProperties(type, variable.variable(), &outputVariable);
664 
665     outputVariable.location = type.getLayoutQualifier().location;
666     outputVariable.index    = type.getLayoutQualifier().index;
667     return outputVariable;
668 }
669 
recordVarying(const TIntermSymbol & variable) const670 Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
671 {
672     const TType &type = variable.getType();
673 
674     Varying varying;
675     setCommonVariableProperties(type, variable.variable(), &varying);
676     varying.location = type.getLayoutQualifier().location;
677 
678     switch (type.getQualifier())
679     {
680         case EvqVaryingIn:
681         case EvqVaryingOut:
682         case EvqVertexOut:
683         case EvqSmoothOut:
684         case EvqFlatOut:
685         case EvqCentroidOut:
686         case EvqGeometryOut:
687             if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant())
688             {
689                 varying.isInvariant = true;
690             }
691             break;
692         default:
693             break;
694     }
695 
696     varying.interpolation = GetInterpolationType(type.getQualifier());
697     return varying;
698 }
699 
700 // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
recordInterfaceBlock(const char * instanceName,const TType & interfaceBlockType,InterfaceBlock * interfaceBlock) const701 void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName,
702                                                      const TType &interfaceBlockType,
703                                                      InterfaceBlock *interfaceBlock) const
704 {
705     ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);
706     ASSERT(interfaceBlock);
707 
708     const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
709     ASSERT(blockType);
710 
711     interfaceBlock->name       = blockType->name().data();
712     interfaceBlock->mappedName = getMappedName(blockType);
713     if (instanceName != nullptr)
714     {
715         interfaceBlock->instanceName = instanceName;
716         const TSymbol *blockSymbol   = nullptr;
717         if (strncmp(instanceName, "gl_in", 5u) == 0)
718         {
719             blockSymbol = mSymbolTable->getGlInVariableWithArraySize();
720         }
721         else
722         {
723             blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName));
724         }
725         ASSERT(blockSymbol && blockSymbol->isVariable());
726         interfaceBlock->staticUse =
727             mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol));
728     }
729     ASSERT(!interfaceBlockType.isArrayOfArrays());  // Disallowed by GLSL ES 3.10 section 4.3.9
730     interfaceBlock->arraySize =
731         interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
732 
733     interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
734     if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
735         interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
736     {
737         // TODO(oetuaho): Remove setting isRowMajorLayout.
738         interfaceBlock->isRowMajorLayout = false;
739         interfaceBlock->binding          = blockType->blockBinding();
740         interfaceBlock->layout           = GetBlockLayoutType(blockType->blockStorage());
741     }
742 
743     // Gather field information
744     bool anyFieldStaticallyUsed = false;
745     for (const TField *field : blockType->fields())
746     {
747         const TType &fieldType = *field->type();
748 
749         bool staticUse = false;
750         if (instanceName == nullptr)
751         {
752             // Static use of individual fields has been recorded, since they are present in the
753             // symbol table as variables.
754             const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name());
755             ASSERT(fieldSymbol && fieldSymbol->isVariable());
756             staticUse =
757                 mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol));
758             if (staticUse)
759             {
760                 anyFieldStaticallyUsed = true;
761             }
762         }
763 
764         InterfaceBlockField fieldVariable;
765         setFieldProperties(fieldType, field->name(), staticUse, &fieldVariable);
766         fieldVariable.isRowMajorLayout =
767             (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
768         interfaceBlock->fields.push_back(fieldVariable);
769     }
770     if (anyFieldStaticallyUsed)
771     {
772         interfaceBlock->staticUse = true;
773     }
774 }
775 
recordUniform(const TIntermSymbol & variable) const776 Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
777 {
778     Uniform uniform;
779     setCommonVariableProperties(variable.getType(), variable.variable(), &uniform);
780     uniform.binding = variable.getType().getLayoutQualifier().binding;
781     uniform.imageUnitFormat =
782         GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat);
783     uniform.location  = variable.getType().getLayoutQualifier().location;
784     uniform.offset    = variable.getType().getLayoutQualifier().offset;
785     uniform.readonly  = variable.getType().getMemoryQualifier().readonly;
786     uniform.writeonly = variable.getType().getMemoryQualifier().writeonly;
787     return uniform;
788 }
789 
visitDeclaration(Visit,TIntermDeclaration * node)790 bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
791 {
792     const TIntermSequence &sequence = *(node->getSequence());
793     ASSERT(!sequence.empty());
794 
795     const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
796     TQualifier qualifier          = typedNode.getQualifier();
797 
798     bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
799                             qualifier == EvqFragmentOut || qualifier == EvqUniform ||
800                             IsVarying(qualifier);
801 
802     if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
803     {
804         return true;
805     }
806 
807     for (TIntermNode *variableNode : sequence)
808     {
809         // The only case in which the sequence will not contain a TIntermSymbol node is
810         // initialization. It will contain a TInterBinary node in that case. Since attributes,
811         // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
812         // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
813         const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
814         if (variable.variable().symbolType() == SymbolType::AngleInternal)
815         {
816             // Internal variables are not collected.
817             continue;
818         }
819 
820         // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
821         if (typedNode.getBasicType() == EbtInterfaceBlock)
822         {
823             InterfaceBlock interfaceBlock;
824             recordInterfaceBlock(variable.variable().symbolType() != SymbolType::Empty
825                                      ? variable.getName().data()
826                                      : nullptr,
827                                  variable.getType(), &interfaceBlock);
828 
829             switch (qualifier)
830             {
831                 case EvqUniform:
832                     mUniformBlocks->push_back(interfaceBlock);
833                     break;
834                 case EvqBuffer:
835                     mShaderStorageBlocks->push_back(interfaceBlock);
836                     break;
837                 default:
838                     UNREACHABLE();
839             }
840         }
841         else
842         {
843             ASSERT(variable.variable().symbolType() != SymbolType::Empty);
844             switch (qualifier)
845             {
846                 case EvqAttribute:
847                 case EvqVertexIn:
848                     mAttribs->push_back(recordAttribute(variable));
849                     break;
850                 case EvqFragmentOut:
851                     mOutputVariables->push_back(recordOutputVariable(variable));
852                     break;
853                 case EvqUniform:
854                     mUniforms->push_back(recordUniform(variable));
855                     break;
856                 default:
857                     if (IsVaryingIn(qualifier))
858                     {
859                         mInputVaryings->push_back(recordVarying(variable));
860                     }
861                     else
862                     {
863                         ASSERT(IsVaryingOut(qualifier));
864                         mOutputVaryings->push_back(recordVarying(variable));
865                     }
866                     break;
867             }
868         }
869     }
870 
871     // None of the recorded variables can have initializers, so we don't need to traverse the
872     // declarators.
873     return false;
874 }
875 
876 // TODO(jiawei.shao@intel.com): add search on mInBlocks and mOutBlocks when implementing
877 // GL_EXT_shader_io_blocks.
findNamedInterfaceBlock(const ImmutableString & blockName) const878 InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(
879     const ImmutableString &blockName) const
880 {
881     InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);
882     if (!namedBlock)
883     {
884         namedBlock = FindVariable(blockName, mShaderStorageBlocks);
885     }
886     return namedBlock;
887 }
888 
visitBinary(Visit,TIntermBinary * binaryNode)889 bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
890 {
891     if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
892     {
893         // NOTE: we do not determine static use / activeness for individual blocks of an array.
894         TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
895         ASSERT(blockNode);
896 
897         TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
898         ASSERT(constantUnion);
899 
900         InterfaceBlock *namedBlock = nullptr;
901 
902         bool traverseIndexExpression         = false;
903         TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();
904         if (interfaceIndexingNode)
905         {
906             TIntermTyped *interfaceNode = interfaceIndexingNode->getLeft()->getAsTyped();
907             ASSERT(interfaceNode);
908 
909             const TType &interfaceType = interfaceNode->getType();
910             if (interfaceType.getQualifier() == EvqPerVertexIn)
911             {
912                 namedBlock = recordGLInUsed(interfaceType);
913                 ASSERT(namedBlock);
914 
915                 // We need to continue traversing to collect useful variables in the index
916                 // expression of gl_in.
917                 traverseIndexExpression = true;
918             }
919         }
920 
921         const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
922         if (!namedBlock)
923         {
924             namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
925         }
926         ASSERT(namedBlock);
927         ASSERT(namedBlock->staticUse);
928         namedBlock->active      = true;
929         unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
930         ASSERT(fieldIndex < namedBlock->fields.size());
931         // TODO(oetuaho): Would be nicer to record static use of fields of named interface blocks
932         // more accurately at parse time - now we only mark the fields statically used if they are
933         // active. http://anglebug.com/2440
934         namedBlock->fields[fieldIndex].staticUse = true;
935         namedBlock->fields[fieldIndex].active    = true;
936 
937         if (traverseIndexExpression)
938         {
939             ASSERT(interfaceIndexingNode);
940             interfaceIndexingNode->getRight()->traverse(this);
941         }
942         return false;
943     }
944 
945     return true;
946 }
947 
948 }  // anonymous namespace
949 
CollectVariables(TIntermBlock * root,std::vector<Attribute> * attributes,std::vector<OutputVariable> * outputVariables,std::vector<Uniform> * uniforms,std::vector<Varying> * inputVaryings,std::vector<Varying> * outputVaryings,std::vector<InterfaceBlock> * uniformBlocks,std::vector<InterfaceBlock> * shaderStorageBlocks,std::vector<InterfaceBlock> * inBlocks,ShHashFunction64 hashFunction,TSymbolTable * symbolTable,GLenum shaderType,const TExtensionBehavior & extensionBehavior)950 void CollectVariables(TIntermBlock *root,
951                       std::vector<Attribute> *attributes,
952                       std::vector<OutputVariable> *outputVariables,
953                       std::vector<Uniform> *uniforms,
954                       std::vector<Varying> *inputVaryings,
955                       std::vector<Varying> *outputVaryings,
956                       std::vector<InterfaceBlock> *uniformBlocks,
957                       std::vector<InterfaceBlock> *shaderStorageBlocks,
958                       std::vector<InterfaceBlock> *inBlocks,
959                       ShHashFunction64 hashFunction,
960                       TSymbolTable *symbolTable,
961                       GLenum shaderType,
962                       const TExtensionBehavior &extensionBehavior)
963 {
964     CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
965                                       outputVaryings, uniformBlocks, shaderStorageBlocks, inBlocks,
966                                       hashFunction, symbolTable, shaderType, extensionBehavior);
967     root->traverse(&collect);
968 }
969 
970 }  // namespace sh
971