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
41 // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
GetBlockType(TQualifier qualifier)42 BlockType GetBlockType(TQualifier qualifier)
43 {
44 switch (qualifier)
45 {
46 case EvqUniform:
47 return BlockType::BLOCK_UNIFORM;
48 case EvqBuffer:
49 return BlockType::BLOCK_BUFFER;
50 case EvqPerVertexIn:
51 return BlockType::BLOCK_IN;
52 default:
53 UNREACHABLE();
54 return BlockType::BLOCK_UNIFORM;
55 }
56 }
57
58 template <class VarT>
FindVariable(const ImmutableString & name,std::vector<VarT> * infoList)59 VarT *FindVariable(const ImmutableString &name, std::vector<VarT> *infoList)
60 {
61 // TODO(zmo): optimize this function.
62 for (size_t ii = 0; ii < infoList->size(); ++ii)
63 {
64 if (name == (*infoList)[ii].name)
65 return &((*infoList)[ii]);
66 }
67
68 return nullptr;
69 }
70
MarkActive(ShaderVariable * variable)71 void MarkActive(ShaderVariable *variable)
72 {
73 if (!variable->active)
74 {
75 if (variable->isStruct())
76 {
77 // Conservatively assume all fields are statically used as well.
78 for (auto &field : variable->fields)
79 {
80 MarkActive(&field);
81 }
82 }
83 variable->staticUse = true;
84 variable->active = true;
85 }
86 }
87
FindVariableInInterfaceBlock(const ImmutableString & name,const TInterfaceBlock * interfaceBlock,std::vector<InterfaceBlock> * infoList)88 ShaderVariable *FindVariableInInterfaceBlock(const ImmutableString &name,
89 const TInterfaceBlock *interfaceBlock,
90 std::vector<InterfaceBlock> *infoList)
91 {
92 ASSERT(interfaceBlock);
93 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), infoList);
94 ASSERT(namedBlock);
95
96 // Set static use on the parent interface block here
97 namedBlock->staticUse = true;
98 namedBlock->active = true;
99 return FindVariable(name, &namedBlock->fields);
100 }
101
102 // Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
103 // shared data and interface blocks.
104 class CollectVariablesTraverser : public TIntermTraverser
105 {
106 public:
107 CollectVariablesTraverser(std::vector<ShaderVariable> *attribs,
108 std::vector<ShaderVariable> *outputVariables,
109 std::vector<ShaderVariable> *uniforms,
110 std::vector<ShaderVariable> *inputVaryings,
111 std::vector<ShaderVariable> *outputVaryings,
112 std::vector<ShaderVariable> *sharedVariables,
113 std::vector<InterfaceBlock> *uniformBlocks,
114 std::vector<InterfaceBlock> *shaderStorageBlocks,
115 std::vector<InterfaceBlock> *inBlocks,
116 ShHashFunction64 hashFunction,
117 TSymbolTable *symbolTable,
118 GLenum shaderType,
119 const TExtensionBehavior &extensionBehavior);
120
121 bool visitGlobalQualifierDeclaration(Visit visit,
122 TIntermGlobalQualifierDeclaration *node) override;
123 void visitSymbol(TIntermSymbol *symbol) override;
124 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
125 bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
126
127 private:
128 std::string getMappedName(const TSymbol *symbol) const;
129
130 void setFieldOrVariableProperties(const TType &type,
131 bool staticUse,
132 ShaderVariable *variableOut) const;
133 void setFieldProperties(const TType &type,
134 const ImmutableString &name,
135 bool staticUse,
136 ShaderVariable *variableOut) const;
137 void setCommonVariableProperties(const TType &type,
138 const TVariable &variable,
139 ShaderVariable *variableOut) const;
140
141 ShaderVariable recordAttribute(const TIntermSymbol &variable) const;
142 ShaderVariable recordOutputVariable(const TIntermSymbol &variable) const;
143 ShaderVariable recordVarying(const TIntermSymbol &variable) const;
144 void recordInterfaceBlock(const char *instanceName,
145 const TType &interfaceBlockType,
146 InterfaceBlock *interfaceBlock) const;
147 ShaderVariable recordUniform(const TIntermSymbol &variable) const;
148
149 void setBuiltInInfoFromSymbol(const TVariable &variable, ShaderVariable *info);
150
151 void recordBuiltInVaryingUsed(const TVariable &variable,
152 bool *addedFlag,
153 std::vector<ShaderVariable> *varyings);
154 void recordBuiltInFragmentOutputUsed(const TVariable &variable, bool *addedFlag);
155 void recordBuiltInAttributeUsed(const TVariable &variable, bool *addedFlag);
156 InterfaceBlock *recordGLInUsed(const TType &glInType);
157 InterfaceBlock *findNamedInterfaceBlock(const ImmutableString &name) const;
158
159 std::vector<ShaderVariable> *mAttribs;
160 std::vector<ShaderVariable> *mOutputVariables;
161 std::vector<ShaderVariable> *mUniforms;
162 std::vector<ShaderVariable> *mInputVaryings;
163 std::vector<ShaderVariable> *mOutputVaryings;
164 std::vector<ShaderVariable> *mSharedVariables;
165 std::vector<InterfaceBlock> *mUniformBlocks;
166 std::vector<InterfaceBlock> *mShaderStorageBlocks;
167 std::vector<InterfaceBlock> *mInBlocks;
168
169 std::map<std::string, ShaderVariable *> mInterfaceBlockFields;
170
171 // Shader uniforms
172 bool mDepthRangeAdded;
173
174 // Compute Shader builtins
175 bool mNumWorkGroupsAdded;
176 bool mWorkGroupIDAdded;
177 bool mLocalInvocationIDAdded;
178 bool mGlobalInvocationIDAdded;
179 bool mLocalInvocationIndexAdded;
180
181 // Vertex Shader builtins
182 bool mInstanceIDAdded;
183 bool mVertexIDAdded;
184 bool mPointSizeAdded;
185 bool mDrawIDAdded;
186 bool mBaseVertexAdded;
187 bool mBaseInstanceAdded;
188
189 // Vertex Shader and Geometry Shader builtins
190 bool mPositionAdded;
191 bool mClipDistanceAdded;
192
193 // Fragment Shader builtins
194 bool mPointCoordAdded;
195 bool mFrontFacingAdded;
196 bool mHelperInvocationAdded;
197 bool mFragCoordAdded;
198 bool mLastFragDataAdded;
199 bool mFragColorAdded;
200 bool mFragDataAdded;
201 bool mFragDepthEXTAdded;
202 bool mFragDepthAdded;
203 bool mSecondaryFragColorEXTAdded;
204 bool mSecondaryFragDataEXTAdded;
205
206 // Geometry Shader builtins
207 bool mPerVertexInAdded;
208 bool mPrimitiveIDInAdded;
209 bool mInvocationIDAdded;
210
211 // Geometry Shader and Fragment Shader builtins
212 bool mPrimitiveIDAdded;
213 bool mLayerAdded;
214
215 // Shared memory variables
216 bool mSharedVariableAdded;
217
218 ShHashFunction64 mHashFunction;
219
220 GLenum mShaderType;
221 const TExtensionBehavior &mExtensionBehavior;
222 };
223
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,std::vector<sh::InterfaceBlock> * inBlocks,ShHashFunction64 hashFunction,TSymbolTable * symbolTable,GLenum shaderType,const TExtensionBehavior & extensionBehavior)224 CollectVariablesTraverser::CollectVariablesTraverser(
225 std::vector<sh::ShaderVariable> *attribs,
226 std::vector<sh::ShaderVariable> *outputVariables,
227 std::vector<sh::ShaderVariable> *uniforms,
228 std::vector<sh::ShaderVariable> *inputVaryings,
229 std::vector<sh::ShaderVariable> *outputVaryings,
230 std::vector<sh::ShaderVariable> *sharedVariables,
231 std::vector<sh::InterfaceBlock> *uniformBlocks,
232 std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
233 std::vector<sh::InterfaceBlock> *inBlocks,
234 ShHashFunction64 hashFunction,
235 TSymbolTable *symbolTable,
236 GLenum shaderType,
237 const TExtensionBehavior &extensionBehavior)
238 : TIntermTraverser(true, false, false, symbolTable),
239 mAttribs(attribs),
240 mOutputVariables(outputVariables),
241 mUniforms(uniforms),
242 mInputVaryings(inputVaryings),
243 mOutputVaryings(outputVaryings),
244 mSharedVariables(sharedVariables),
245 mUniformBlocks(uniformBlocks),
246 mShaderStorageBlocks(shaderStorageBlocks),
247 mInBlocks(inBlocks),
248 mDepthRangeAdded(false),
249 mNumWorkGroupsAdded(false),
250 mWorkGroupIDAdded(false),
251 mLocalInvocationIDAdded(false),
252 mGlobalInvocationIDAdded(false),
253 mLocalInvocationIndexAdded(false),
254 mInstanceIDAdded(false),
255 mVertexIDAdded(false),
256 mPointSizeAdded(false),
257 mDrawIDAdded(false),
258 mBaseVertexAdded(false),
259 mBaseInstanceAdded(false),
260 mPositionAdded(false),
261 mClipDistanceAdded(false),
262 mPointCoordAdded(false),
263 mFrontFacingAdded(false),
264 mHelperInvocationAdded(false),
265 mFragCoordAdded(false),
266 mLastFragDataAdded(false),
267 mFragColorAdded(false),
268 mFragDataAdded(false),
269 mFragDepthEXTAdded(false),
270 mFragDepthAdded(false),
271 mSecondaryFragColorEXTAdded(false),
272 mSecondaryFragDataEXTAdded(false),
273 mPerVertexInAdded(false),
274 mPrimitiveIDInAdded(false),
275 mInvocationIDAdded(false),
276 mPrimitiveIDAdded(false),
277 mLayerAdded(false),
278 mSharedVariableAdded(false),
279 mHashFunction(hashFunction),
280 mShaderType(shaderType),
281 mExtensionBehavior(extensionBehavior)
282 {}
283
getMappedName(const TSymbol * symbol) const284 std::string CollectVariablesTraverser::getMappedName(const TSymbol *symbol) const
285 {
286 return HashName(symbol, mHashFunction, nullptr).data();
287 }
288
setBuiltInInfoFromSymbol(const TVariable & variable,ShaderVariable * info)289 void CollectVariablesTraverser::setBuiltInInfoFromSymbol(const TVariable &variable,
290 ShaderVariable *info)
291 {
292 const TType &type = variable.getType();
293
294 info->name = variable.name().data();
295 info->mappedName = variable.name().data();
296
297 setFieldOrVariableProperties(type, true, info);
298 }
299
recordBuiltInVaryingUsed(const TVariable & variable,bool * addedFlag,std::vector<ShaderVariable> * varyings)300 void CollectVariablesTraverser::recordBuiltInVaryingUsed(const TVariable &variable,
301 bool *addedFlag,
302 std::vector<ShaderVariable> *varyings)
303 {
304 ASSERT(varyings);
305 if (!(*addedFlag))
306 {
307 ShaderVariable info;
308 setBuiltInInfoFromSymbol(variable, &info);
309 info.active = true;
310 info.isInvariant = mSymbolTable->isVaryingInvariant(variable);
311
312 varyings->push_back(info);
313 (*addedFlag) = true;
314 }
315 }
316
recordBuiltInFragmentOutputUsed(const TVariable & variable,bool * addedFlag)317 void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const TVariable &variable,
318 bool *addedFlag)
319 {
320 if (!(*addedFlag))
321 {
322 ShaderVariable info;
323 setBuiltInInfoFromSymbol(variable, &info);
324 info.active = true;
325 mOutputVariables->push_back(info);
326 (*addedFlag) = true;
327 }
328 }
329
recordBuiltInAttributeUsed(const TVariable & variable,bool * addedFlag)330 void CollectVariablesTraverser::recordBuiltInAttributeUsed(const TVariable &variable,
331 bool *addedFlag)
332 {
333 if (!(*addedFlag))
334 {
335 ShaderVariable info;
336 setBuiltInInfoFromSymbol(variable, &info);
337 info.active = true;
338 info.location = -1;
339 mAttribs->push_back(info);
340 (*addedFlag) = true;
341 }
342 }
343
recordGLInUsed(const TType & glInType)344 InterfaceBlock *CollectVariablesTraverser::recordGLInUsed(const TType &glInType)
345 {
346 if (!mPerVertexInAdded)
347 {
348 ASSERT(glInType.getQualifier() == EvqPerVertexIn);
349 InterfaceBlock info;
350 recordInterfaceBlock("gl_in", glInType, &info);
351
352 mPerVertexInAdded = true;
353 mInBlocks->push_back(info);
354 return &mInBlocks->back();
355 }
356 else
357 {
358 return FindVariable(ImmutableString("gl_PerVertex"), mInBlocks);
359 }
360 }
361
visitGlobalQualifierDeclaration(Visit visit,TIntermGlobalQualifierDeclaration * node)362 bool CollectVariablesTraverser::visitGlobalQualifierDeclaration(
363 Visit visit,
364 TIntermGlobalQualifierDeclaration *node)
365 {
366 // We should not mark variables as active just based on an invariant/precise declaration, so we
367 // don't traverse the symbols declared invariant.
368 return false;
369 }
370
371 // We want to check whether a uniform/varying is active because we need to skip updating inactive
372 // ones. We also only count the active ones in packing computing. Also, gl_FragCoord, gl_PointCoord,
373 // and gl_FrontFacing count toward varying counting if they are active in a fragment shader.
visitSymbol(TIntermSymbol * symbol)374 void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
375 {
376 ASSERT(symbol != nullptr);
377
378 if (symbol->variable().symbolType() == SymbolType::AngleInternal ||
379 symbol->variable().symbolType() == SymbolType::Empty)
380 {
381 // Internal variables or nameless variables are not collected.
382 return;
383 }
384
385 ShaderVariable *var = nullptr;
386
387 const ImmutableString &symbolName = symbol->getName();
388
389 // Check the qualifier from the variable, not from the symbol node. The node may have a
390 // different qualifier if it's the result of a folded ternary node.
391 TQualifier qualifier = symbol->variable().getType().getQualifier();
392
393 if (IsVaryingIn(qualifier))
394 {
395 var = FindVariable(symbolName, mInputVaryings);
396 }
397 else if (IsVaryingOut(qualifier))
398 {
399 var = FindVariable(symbolName, mOutputVaryings);
400 }
401 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
402 {
403 UNREACHABLE();
404 }
405 else if (symbolName == "gl_DepthRange")
406 {
407 ASSERT(qualifier == EvqUniform);
408
409 if (!mDepthRangeAdded)
410 {
411 ShaderVariable info;
412 const char kName[] = "gl_DepthRange";
413 info.name = kName;
414 info.mappedName = kName;
415 info.type = GL_NONE;
416 info.precision = GL_NONE;
417 info.staticUse = true;
418 info.active = true;
419
420 ShaderVariable nearInfo(GL_FLOAT);
421 const char kNearName[] = "near";
422 nearInfo.name = kNearName;
423 nearInfo.mappedName = kNearName;
424 nearInfo.precision = GL_HIGH_FLOAT;
425 nearInfo.staticUse = true;
426 nearInfo.active = true;
427
428 ShaderVariable farInfo(GL_FLOAT);
429 const char kFarName[] = "far";
430 farInfo.name = kFarName;
431 farInfo.mappedName = kFarName;
432 farInfo.precision = GL_HIGH_FLOAT;
433 farInfo.staticUse = true;
434 farInfo.active = true;
435
436 ShaderVariable diffInfo(GL_FLOAT);
437 const char kDiffName[] = "diff";
438 diffInfo.name = kDiffName;
439 diffInfo.mappedName = kDiffName;
440 diffInfo.precision = GL_HIGH_FLOAT;
441 diffInfo.staticUse = true;
442 diffInfo.active = true;
443
444 info.fields.push_back(nearInfo);
445 info.fields.push_back(farInfo);
446 info.fields.push_back(diffInfo);
447
448 mUniforms->push_back(info);
449 mDepthRangeAdded = true;
450 }
451 }
452 else
453 {
454 switch (qualifier)
455 {
456 case EvqAttribute:
457 case EvqVertexIn:
458 var = FindVariable(symbolName, mAttribs);
459 break;
460 case EvqFragmentOut:
461 var = FindVariable(symbolName, mOutputVariables);
462 break;
463 case EvqUniform:
464 {
465 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
466 if (interfaceBlock)
467 {
468 var = FindVariableInInterfaceBlock(symbolName, interfaceBlock, mUniformBlocks);
469 }
470 else
471 {
472 var = FindVariable(symbolName, mUniforms);
473 }
474
475 // It's an internal error to reference an undefined user uniform
476 ASSERT(!symbolName.beginsWith("gl_") || var);
477 }
478 break;
479 case EvqBuffer:
480 {
481 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
482 var =
483 FindVariableInInterfaceBlock(symbolName, interfaceBlock, mShaderStorageBlocks);
484 }
485 break;
486 case EvqFragCoord:
487 recordBuiltInVaryingUsed(symbol->variable(), &mFragCoordAdded, mInputVaryings);
488 return;
489 case EvqFrontFacing:
490 recordBuiltInVaryingUsed(symbol->variable(), &mFrontFacingAdded, mInputVaryings);
491 return;
492 case EvqHelperInvocation:
493 recordBuiltInVaryingUsed(symbol->variable(), &mHelperInvocationAdded,
494 mInputVaryings);
495 return;
496 case EvqPointCoord:
497 recordBuiltInVaryingUsed(symbol->variable(), &mPointCoordAdded, mInputVaryings);
498 return;
499 case EvqNumWorkGroups:
500 recordBuiltInAttributeUsed(symbol->variable(), &mNumWorkGroupsAdded);
501 return;
502 case EvqWorkGroupID:
503 recordBuiltInAttributeUsed(symbol->variable(), &mWorkGroupIDAdded);
504 return;
505 case EvqLocalInvocationID:
506 recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIDAdded);
507 return;
508 case EvqGlobalInvocationID:
509 recordBuiltInAttributeUsed(symbol->variable(), &mGlobalInvocationIDAdded);
510 return;
511 case EvqLocalInvocationIndex:
512 recordBuiltInAttributeUsed(symbol->variable(), &mLocalInvocationIndexAdded);
513 return;
514 case EvqInstanceID:
515 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
516 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
517 // InstanceID. Note that gl_InstanceID is not added to the symbol table for ESSL1
518 // shaders.
519 recordBuiltInAttributeUsed(symbol->variable(), &mInstanceIDAdded);
520 return;
521 case EvqVertexID:
522 recordBuiltInAttributeUsed(symbol->variable(), &mVertexIDAdded);
523 return;
524 case EvqPosition:
525 recordBuiltInVaryingUsed(symbol->variable(), &mPositionAdded, mOutputVaryings);
526 return;
527 case EvqPointSize:
528 recordBuiltInVaryingUsed(symbol->variable(), &mPointSizeAdded, mOutputVaryings);
529 return;
530 case EvqDrawID:
531 recordBuiltInAttributeUsed(symbol->variable(), &mDrawIDAdded);
532 return;
533 case EvqBaseVertex:
534 recordBuiltInAttributeUsed(symbol->variable(), &mBaseVertexAdded);
535 return;
536 case EvqBaseInstance:
537 recordBuiltInAttributeUsed(symbol->variable(), &mBaseInstanceAdded);
538 return;
539 case EvqLastFragData:
540 recordBuiltInVaryingUsed(symbol->variable(), &mLastFragDataAdded, mInputVaryings);
541 return;
542 case EvqFragColor:
543 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragColorAdded);
544 return;
545 case EvqFragData:
546 if (!mFragDataAdded)
547 {
548 ShaderVariable info;
549 setBuiltInInfoFromSymbol(symbol->variable(), &info);
550 if (!IsExtensionEnabled(mExtensionBehavior, TExtension::EXT_draw_buffers))
551 {
552 ASSERT(info.arraySizes.size() == 1u);
553 info.arraySizes.back() = 1u;
554 }
555 info.active = true;
556 mOutputVariables->push_back(info);
557 mFragDataAdded = true;
558 }
559 return;
560 case EvqFragDepthEXT:
561 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthEXTAdded);
562 return;
563 case EvqFragDepth:
564 recordBuiltInFragmentOutputUsed(symbol->variable(), &mFragDepthAdded);
565 return;
566 case EvqSecondaryFragColorEXT:
567 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragColorEXTAdded);
568 return;
569 case EvqSecondaryFragDataEXT:
570 recordBuiltInFragmentOutputUsed(symbol->variable(), &mSecondaryFragDataEXTAdded);
571 return;
572 case EvqInvocationID:
573 recordBuiltInVaryingUsed(symbol->variable(), &mInvocationIDAdded, mInputVaryings);
574 break;
575 case EvqPrimitiveIDIn:
576 recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDInAdded, mInputVaryings);
577 break;
578 case EvqPrimitiveID:
579 if (mShaderType == GL_GEOMETRY_SHADER_EXT)
580 {
581 recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
582 mOutputVaryings);
583 }
584 else
585 {
586 ASSERT(mShaderType == GL_FRAGMENT_SHADER);
587 recordBuiltInVaryingUsed(symbol->variable(), &mPrimitiveIDAdded,
588 mInputVaryings);
589 }
590 break;
591 case EvqLayer:
592 if (mShaderType == GL_GEOMETRY_SHADER_EXT)
593 {
594 recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mOutputVaryings);
595 }
596 else if (mShaderType == GL_FRAGMENT_SHADER)
597 {
598 recordBuiltInVaryingUsed(symbol->variable(), &mLayerAdded, mInputVaryings);
599 }
600 else
601 {
602 ASSERT(mShaderType == GL_VERTEX_SHADER &&
603 (IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview2) ||
604 IsExtensionEnabled(mExtensionBehavior, TExtension::OVR_multiview)));
605 }
606 break;
607 case EvqShared:
608 if (mShaderType == GL_COMPUTE_SHADER)
609 {
610 recordBuiltInVaryingUsed(symbol->variable(), &mSharedVariableAdded,
611 mSharedVariables);
612 }
613 break;
614 case EvqClipDistance:
615 recordBuiltInVaryingUsed(symbol->variable(), &mClipDistanceAdded, mOutputVaryings);
616 return;
617 default:
618 break;
619 }
620 }
621 if (var)
622 {
623 MarkActive(var);
624 }
625 }
626
setFieldOrVariableProperties(const TType & type,bool staticUse,ShaderVariable * variableOut) const627 void CollectVariablesTraverser::setFieldOrVariableProperties(const TType &type,
628 bool staticUse,
629 ShaderVariable *variableOut) const
630 {
631 ASSERT(variableOut);
632
633 variableOut->staticUse = staticUse;
634
635 const TStructure *structure = type.getStruct();
636 if (!structure)
637 {
638 variableOut->type = GLVariableType(type);
639 variableOut->precision = GLVariablePrecision(type);
640 }
641 else
642 {
643 // Structures use a NONE type that isn't exposed outside ANGLE.
644 variableOut->type = GL_NONE;
645 if (structure->symbolType() != SymbolType::Empty)
646 {
647 variableOut->structName = structure->name().data();
648 }
649
650 const TFieldList &fields = structure->fields();
651
652 for (const TField *field : fields)
653 {
654 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
655 // ShaderVariable objects.
656 ShaderVariable fieldVariable;
657 setFieldProperties(*field->type(), field->name(), staticUse, &fieldVariable);
658 variableOut->fields.push_back(fieldVariable);
659 }
660 }
661 const TSpan<const unsigned int> &arraySizes = type.getArraySizes();
662 if (!arraySizes.empty())
663 {
664 variableOut->arraySizes.assign(arraySizes.begin(), arraySizes.end());
665 }
666 }
667
setFieldProperties(const TType & type,const ImmutableString & name,bool staticUse,ShaderVariable * variableOut) const668 void CollectVariablesTraverser::setFieldProperties(const TType &type,
669 const ImmutableString &name,
670 bool staticUse,
671 ShaderVariable *variableOut) const
672 {
673 ASSERT(variableOut);
674 setFieldOrVariableProperties(type, staticUse, variableOut);
675 variableOut->name.assign(name.data(), name.length());
676 variableOut->mappedName = HashName(name, mHashFunction, nullptr).data();
677 }
678
setCommonVariableProperties(const TType & type,const TVariable & variable,ShaderVariable * variableOut) const679 void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
680 const TVariable &variable,
681 ShaderVariable *variableOut) const
682 {
683 ASSERT(variableOut);
684
685 variableOut->staticUse = mSymbolTable->isStaticallyUsed(variable);
686 setFieldOrVariableProperties(type, variableOut->staticUse, variableOut);
687 ASSERT(variable.symbolType() != SymbolType::Empty);
688 variableOut->name.assign(variable.name().data(), variable.name().length());
689 variableOut->mappedName = getMappedName(&variable);
690 }
691
recordAttribute(const TIntermSymbol & variable) const692 ShaderVariable CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
693 {
694 const TType &type = variable.getType();
695 ASSERT(!type.getStruct());
696
697 ShaderVariable attribute;
698 setCommonVariableProperties(type, variable.variable(), &attribute);
699
700 attribute.location = type.getLayoutQualifier().location;
701 return attribute;
702 }
703
recordOutputVariable(const TIntermSymbol & variable) const704 ShaderVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
705 {
706 const TType &type = variable.getType();
707 ASSERT(!type.getStruct());
708
709 ShaderVariable outputVariable;
710 setCommonVariableProperties(type, variable.variable(), &outputVariable);
711
712 outputVariable.location = type.getLayoutQualifier().location;
713 outputVariable.index = type.getLayoutQualifier().index;
714 return outputVariable;
715 }
716
recordVarying(const TIntermSymbol & variable) const717 ShaderVariable CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
718 {
719 const TType &type = variable.getType();
720
721 ShaderVariable varying;
722 setCommonVariableProperties(type, variable.variable(), &varying);
723 varying.location = type.getLayoutQualifier().location;
724
725 switch (type.getQualifier())
726 {
727 case EvqVaryingIn:
728 case EvqVaryingOut:
729 case EvqVertexOut:
730 case EvqSmoothOut:
731 case EvqFlatOut:
732 case EvqNoPerspectiveOut:
733 case EvqCentroidOut:
734 case EvqGeometryOut:
735 if (mSymbolTable->isVaryingInvariant(variable.variable()) || type.isInvariant())
736 {
737 varying.isInvariant = true;
738 }
739 break;
740 default:
741 break;
742 }
743
744 varying.interpolation = GetInterpolationType(type.getQualifier());
745 return varying;
746 }
747
748 // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
recordInterfaceBlock(const char * instanceName,const TType & interfaceBlockType,InterfaceBlock * interfaceBlock) const749 void CollectVariablesTraverser::recordInterfaceBlock(const char *instanceName,
750 const TType &interfaceBlockType,
751 InterfaceBlock *interfaceBlock) const
752 {
753 ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);
754 ASSERT(interfaceBlock);
755
756 const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
757 ASSERT(blockType);
758
759 interfaceBlock->name = blockType->name().data();
760 interfaceBlock->mappedName = getMappedName(blockType);
761 if (instanceName != nullptr)
762 {
763 interfaceBlock->instanceName = instanceName;
764 const TSymbol *blockSymbol = nullptr;
765 if (strncmp(instanceName, "gl_in", 5u) == 0)
766 {
767 blockSymbol = mSymbolTable->getGlInVariableWithArraySize();
768 }
769 else
770 {
771 blockSymbol = mSymbolTable->findGlobal(ImmutableString(instanceName));
772 }
773 ASSERT(blockSymbol && blockSymbol->isVariable());
774 interfaceBlock->staticUse =
775 mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(blockSymbol));
776 }
777 ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9
778 interfaceBlock->arraySize =
779 interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
780
781 interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
782 if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
783 interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
784 {
785 // TODO(oetuaho): Remove setting isRowMajorLayout.
786 interfaceBlock->isRowMajorLayout = false;
787 interfaceBlock->binding = blockType->blockBinding();
788 interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage());
789 }
790
791 // Gather field information
792 bool anyFieldStaticallyUsed = false;
793 for (const TField *field : blockType->fields())
794 {
795 const TType &fieldType = *field->type();
796
797 bool staticUse = false;
798 if (instanceName == nullptr)
799 {
800 // Static use of individual fields has been recorded, since they are present in the
801 // symbol table as variables.
802 const TSymbol *fieldSymbol = mSymbolTable->findGlobal(field->name());
803 ASSERT(fieldSymbol && fieldSymbol->isVariable());
804 staticUse =
805 mSymbolTable->isStaticallyUsed(*static_cast<const TVariable *>(fieldSymbol));
806 if (staticUse)
807 {
808 anyFieldStaticallyUsed = true;
809 }
810 }
811
812 ShaderVariable fieldVariable;
813 setFieldProperties(fieldType, field->name(), staticUse, &fieldVariable);
814 fieldVariable.isRowMajorLayout =
815 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
816 interfaceBlock->fields.push_back(fieldVariable);
817 }
818 if (anyFieldStaticallyUsed)
819 {
820 interfaceBlock->staticUse = true;
821 }
822 }
823
recordUniform(const TIntermSymbol & variable) const824 ShaderVariable CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
825 {
826 ShaderVariable uniform;
827 setCommonVariableProperties(variable.getType(), variable.variable(), &uniform);
828 uniform.binding = variable.getType().getLayoutQualifier().binding;
829 uniform.imageUnitFormat =
830 GetImageInternalFormatType(variable.getType().getLayoutQualifier().imageInternalFormat);
831 uniform.location = variable.getType().getLayoutQualifier().location;
832 uniform.offset = variable.getType().getLayoutQualifier().offset;
833 uniform.readonly = variable.getType().getMemoryQualifier().readonly;
834 uniform.writeonly = variable.getType().getMemoryQualifier().writeonly;
835 return uniform;
836 }
837
visitDeclaration(Visit,TIntermDeclaration * node)838 bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
839 {
840 const TIntermSequence &sequence = *(node->getSequence());
841 ASSERT(!sequence.empty());
842
843 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
844 TQualifier qualifier = typedNode.getQualifier();
845
846 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
847 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
848 IsVarying(qualifier);
849
850 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
851 {
852 return true;
853 }
854
855 for (TIntermNode *variableNode : sequence)
856 {
857 // The only case in which the sequence will not contain a TIntermSymbol node is
858 // initialization. It will contain a TInterBinary node in that case. Since attributes,
859 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
860 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
861 const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
862 if (variable.variable().symbolType() == SymbolType::AngleInternal)
863 {
864 // Internal variables are not collected.
865 continue;
866 }
867
868 // TODO(jiawei.shao@intel.com): implement GL_EXT_shader_io_blocks.
869 if (typedNode.getBasicType() == EbtInterfaceBlock)
870 {
871 InterfaceBlock interfaceBlock;
872 recordInterfaceBlock(variable.variable().symbolType() != SymbolType::Empty
873 ? variable.getName().data()
874 : nullptr,
875 variable.getType(), &interfaceBlock);
876
877 switch (qualifier)
878 {
879 case EvqUniform:
880 mUniformBlocks->push_back(interfaceBlock);
881 break;
882 case EvqBuffer:
883 mShaderStorageBlocks->push_back(interfaceBlock);
884 break;
885 default:
886 UNREACHABLE();
887 }
888 }
889 else
890 {
891 ASSERT(variable.variable().symbolType() != SymbolType::Empty);
892 switch (qualifier)
893 {
894 case EvqAttribute:
895 case EvqVertexIn:
896 mAttribs->push_back(recordAttribute(variable));
897 break;
898 case EvqFragmentOut:
899 mOutputVariables->push_back(recordOutputVariable(variable));
900 break;
901 case EvqUniform:
902 mUniforms->push_back(recordUniform(variable));
903 break;
904 default:
905 if (IsVaryingIn(qualifier))
906 {
907 mInputVaryings->push_back(recordVarying(variable));
908 }
909 else
910 {
911 ASSERT(IsVaryingOut(qualifier));
912 mOutputVaryings->push_back(recordVarying(variable));
913 }
914 break;
915 }
916 }
917 }
918
919 // None of the recorded variables can have initializers, so we don't need to traverse the
920 // declarators.
921 return false;
922 }
923
924 // TODO(jiawei.shao@intel.com): add search on mInBlocks and mOutBlocks when implementing
925 // GL_EXT_shader_io_blocks.
findNamedInterfaceBlock(const ImmutableString & blockName) const926 InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(
927 const ImmutableString &blockName) const
928 {
929 InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);
930 if (!namedBlock)
931 {
932 namedBlock = FindVariable(blockName, mShaderStorageBlocks);
933 }
934 return namedBlock;
935 }
936
visitBinary(Visit,TIntermBinary * binaryNode)937 bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
938 {
939 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
940 {
941 // NOTE: we do not determine static use / activeness for individual blocks of an array.
942 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
943 ASSERT(blockNode);
944
945 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
946 ASSERT(constantUnion);
947
948 InterfaceBlock *namedBlock = nullptr;
949
950 bool traverseIndexExpression = false;
951 TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();
952 if (interfaceIndexingNode)
953 {
954 TIntermTyped *interfaceNode = interfaceIndexingNode->getLeft()->getAsTyped();
955 ASSERT(interfaceNode);
956
957 const TType &interfaceType = interfaceNode->getType();
958 if (interfaceType.getQualifier() == EvqPerVertexIn)
959 {
960 namedBlock = recordGLInUsed(interfaceType);
961 ASSERT(namedBlock);
962 }
963
964 // We need to continue traversing to collect useful variables in the index expression
965 // of the interface block array or gl_in in the case of the if above.
966 traverseIndexExpression = true;
967 }
968
969 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
970 if (!namedBlock)
971 {
972 namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
973 }
974 ASSERT(namedBlock);
975 ASSERT(namedBlock->staticUse);
976 namedBlock->active = true;
977 unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
978 ASSERT(fieldIndex < namedBlock->fields.size());
979 // TODO(oetuaho): Would be nicer to record static use of fields of named interface blocks
980 // more accurately at parse time - now we only mark the fields statically used if they are
981 // active. http://anglebug.com/2440
982 // We need to mark this field and all of its sub-fields, as static/active
983 MarkActive(&namedBlock->fields[fieldIndex]);
984
985 if (traverseIndexExpression)
986 {
987 ASSERT(interfaceIndexingNode);
988 interfaceIndexingNode->getRight()->traverse(this);
989 }
990 return false;
991 }
992
993 return true;
994 }
995
996 } // anonymous namespace
997
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,std::vector<InterfaceBlock> * inBlocks,ShHashFunction64 hashFunction,TSymbolTable * symbolTable,GLenum shaderType,const TExtensionBehavior & extensionBehavior)998 void CollectVariables(TIntermBlock *root,
999 std::vector<ShaderVariable> *attributes,
1000 std::vector<ShaderVariable> *outputVariables,
1001 std::vector<ShaderVariable> *uniforms,
1002 std::vector<ShaderVariable> *inputVaryings,
1003 std::vector<ShaderVariable> *outputVaryings,
1004 std::vector<ShaderVariable> *sharedVariables,
1005 std::vector<InterfaceBlock> *uniformBlocks,
1006 std::vector<InterfaceBlock> *shaderStorageBlocks,
1007 std::vector<InterfaceBlock> *inBlocks,
1008 ShHashFunction64 hashFunction,
1009 TSymbolTable *symbolTable,
1010 GLenum shaderType,
1011 const TExtensionBehavior &extensionBehavior)
1012 {
1013 CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
1014 outputVaryings, sharedVariables, uniformBlocks,
1015 shaderStorageBlocks, inBlocks, hashFunction, symbolTable,
1016 shaderType, extensionBehavior);
1017 root->traverse(&collect);
1018 }
1019
1020 } // namespace sh
1021