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