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