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