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