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