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