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