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