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.
8 #include "compiler/translator/SymbolTable.h"
9 #include "compiler/translator/VariableInfo.h"
10 #include "compiler/translator/util.h"
11 #include "common/utilities.h"
19 TString InterfaceBlockFieldName(const TInterfaceBlock &interfaceBlock, const TField &field)
21 if (interfaceBlock.hasInstanceName())
23 return interfaceBlock.name() + "." + field.name();
31 BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
35 case EbsPacked: return BLOCKLAYOUT_PACKED;
36 case EbsShared: return BLOCKLAYOUT_SHARED;
37 case EbsStd140: return BLOCKLAYOUT_STANDARD;
38 default: UNREACHABLE(); return BLOCKLAYOUT_SHARED;
42 void ExpandUserDefinedVariable(const ShaderVariable &variable,
43 const std::string &name,
44 const std::string &mappedName,
46 std::vector<ShaderVariable> *expanded);
48 void ExpandVariable(const ShaderVariable &variable,
49 const std::string &name,
50 const std::string &mappedName,
52 std::vector<ShaderVariable> *expanded)
54 if (variable.isStruct())
56 if (variable.isArray())
58 for (size_t elementIndex = 0; elementIndex < variable.elementCount(); elementIndex++)
60 std::string lname = name + ::ArrayString(elementIndex);
61 std::string lmappedName = mappedName + ::ArrayString(elementIndex);
62 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
67 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
72 ShaderVariable expandedVar = variable;
74 expandedVar.name = name;
75 expandedVar.mappedName = mappedName;
77 // Mark all expanded fields as used if the parent is used
80 expandedVar.staticUse = true;
83 if (expandedVar.isArray())
85 expandedVar.name += "[0]";
86 expandedVar.mappedName += "[0]";
89 expanded->push_back(expandedVar);
93 void ExpandUserDefinedVariable(const ShaderVariable &variable,
94 const std::string &name,
95 const std::string &mappedName,
97 std::vector<ShaderVariable> *expanded)
99 ASSERT(variable.isStruct());
101 const std::vector<ShaderVariable> &fields = variable.fields;
103 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
105 const ShaderVariable &field = fields[fieldIndex];
106 ExpandVariable(field,
107 name + "." + field.name,
108 mappedName + "." + field.mappedName,
114 template <class VarT>
115 VarT *FindVariable(const TString &name,
116 std::vector<VarT> *infoList)
118 // TODO(zmo): optimize this function.
119 for (size_t ii = 0; ii < infoList->size(); ++ii)
121 if ((*infoList)[ii].name.c_str() == name)
122 return &((*infoList)[ii]);
130 CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
131 std::vector<sh::Attribute> *outputVariables,
132 std::vector<sh::Uniform> *uniforms,
133 std::vector<sh::Varying> *varyings,
134 std::vector<sh::InterfaceBlock> *interfaceBlocks,
135 ShHashFunction64 hashFunction,
136 const TSymbolTable &symbolTable)
138 mOutputVariables(outputVariables),
141 mInterfaceBlocks(interfaceBlocks),
142 mPointCoordAdded(false),
143 mFrontFacingAdded(false),
144 mFragCoordAdded(false),
145 mPositionAdded(false),
146 mPointSizeAdded(false),
147 mHashFunction(hashFunction),
148 mSymbolTable(symbolTable)
152 // We want to check whether a uniform/varying is statically used
153 // because we only count the used ones in packing computing.
154 // Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
155 // toward varying counting if they are statically used in a fragment
157 void CollectVariables::visitSymbol(TIntermSymbol *symbol)
159 ASSERT(symbol != NULL);
160 ShaderVariable *var = NULL;
161 const TString &symbolName = symbol->getSymbol();
163 if (IsVarying(symbol->getQualifier()))
165 var = FindVariable(symbolName, mVaryings);
167 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
173 switch (symbol->getQualifier())
177 var = FindVariable(symbolName, mAttribs);
180 var = FindVariable(symbolName, mOutputVariables);
184 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
187 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
189 var = FindVariable(symbolName, &namedBlock->fields);
191 // Set static use on the parent interface block here
192 namedBlock->staticUse = true;
197 var = FindVariable(symbolName, mUniforms);
200 // It's an internal error to reference an undefined user uniform
201 ASSERT(symbolName.compare(0, 3, "gl_") == 0 || var);
205 if (!mFragCoordAdded)
208 const char kName[] = "gl_FragCoord";
210 info.mappedName = kName;
211 info.type = GL_FLOAT_VEC4;
213 info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
214 info.staticUse = true;
215 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
216 mVaryings->push_back(info);
217 mFragCoordAdded = true;
221 if (!mFrontFacingAdded)
224 const char kName[] = "gl_FrontFacing";
226 info.mappedName = kName;
229 info.precision = GL_NONE;
230 info.staticUse = true;
231 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
232 mVaryings->push_back(info);
233 mFrontFacingAdded = true;
237 if (!mPointCoordAdded)
240 const char kName[] = "gl_PointCoord";
242 info.mappedName = kName;
243 info.type = GL_FLOAT_VEC2;
245 info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
246 info.staticUse = true;
247 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
248 mVaryings->push_back(info);
249 mPointCoordAdded = true;
256 const char kName[] = "gl_Position";
258 info.mappedName = kName;
259 info.type = GL_FLOAT_VEC4;
261 info.precision = GL_HIGH_FLOAT; // Defined by spec.
262 info.staticUse = true;
263 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
264 mVaryings->push_back(info);
265 mPositionAdded = true;
269 if (!mPointSizeAdded)
272 const char kName[] = "gl_PointSize";
274 info.mappedName = kName;
275 info.type = GL_FLOAT;
277 info.precision = GL_MEDIUM_FLOAT; // Defined by spec.
278 info.staticUse = true;
279 info.isInvariant = mSymbolTable.isVaryingInvariant(kName);
280 mVaryings->push_back(info);
281 mPointSizeAdded = true;
290 var->staticUse = true;
294 class NameHashingTraverser : public GetVariableTraverser
297 NameHashingTraverser(ShHashFunction64 hashFunction,
298 const TSymbolTable &symbolTable)
299 : GetVariableTraverser(symbolTable),
300 mHashFunction(hashFunction)
304 DISALLOW_COPY_AND_ASSIGN(NameHashingTraverser);
306 virtual void visitVariable(ShaderVariable *variable)
308 TString stringName = TString(variable->name.c_str());
309 variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str();
312 ShHashFunction64 mHashFunction;
315 // Attributes, which cannot have struct fields, are a special case
317 void CollectVariables::visitVariable(const TIntermSymbol *variable,
318 std::vector<Attribute> *infoList) const
321 const TType &type = variable->getType();
322 ASSERT(!type.getStruct());
326 attribute.type = GLVariableType(type);
327 attribute.precision = GLVariablePrecision(type);
328 attribute.name = variable->getSymbol().c_str();
329 attribute.arraySize = static_cast<unsigned int>(type.getArraySize());
330 attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
331 attribute.location = variable->getType().getLayoutQualifier().location;
333 infoList->push_back(attribute);
337 void CollectVariables::visitVariable(const TIntermSymbol *variable,
338 std::vector<InterfaceBlock> *infoList) const
340 InterfaceBlock interfaceBlock;
341 const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock();
344 interfaceBlock.name = blockType->name().c_str();
345 interfaceBlock.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
346 interfaceBlock.instanceName = (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
347 interfaceBlock.arraySize = variable->getArraySize();
348 interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
349 interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
351 // Gather field information
352 const TFieldList &fieldList = blockType->fields();
354 for (size_t fieldIndex = 0; fieldIndex < fieldList.size(); ++fieldIndex)
356 const TField &field = *fieldList[fieldIndex];
357 const TString &fullFieldName = InterfaceBlockFieldName(*blockType, field);
358 const TType &fieldType = *field.type();
360 GetVariableTraverser traverser(mSymbolTable);
361 traverser.traverse(fieldType, fullFieldName, &interfaceBlock.fields);
363 interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
366 infoList->push_back(interfaceBlock);
369 template <typename VarT>
370 void CollectVariables::visitVariable(const TIntermSymbol *variable,
371 std::vector<VarT> *infoList) const
373 NameHashingTraverser traverser(mHashFunction, mSymbolTable);
374 traverser.traverse(variable->getType(), variable->getSymbol(), infoList);
377 template <typename VarT>
378 void CollectVariables::visitInfoList(const TIntermSequence &sequence,
379 std::vector<VarT> *infoList) const
381 for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++)
383 const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode();
384 // The only case in which the sequence will not contain a
385 // TIntermSymbol node is initialization. It will contain a
386 // TInterBinary node in that case. Since attributes, uniforms,
387 // and varyings cannot be initialized in a shader, we must have
388 // only TIntermSymbol nodes in the sequence.
389 ASSERT(variable != NULL);
390 visitVariable(variable, infoList);
394 bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node)
396 bool visitChildren = true;
398 switch (node->getOp())
402 const TIntermSequence &sequence = *(node->getSequence());
403 ASSERT(!sequence.empty());
405 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
406 TQualifier qualifier = typedNode.getQualifier();
408 if (typedNode.getBasicType() == EbtInterfaceBlock)
410 visitInfoList(sequence, mInterfaceBlocks);
411 visitChildren = false;
413 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn ||
414 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
415 IsVarying(qualifier))
421 visitInfoList(sequence, mAttribs);
424 visitInfoList(sequence, mOutputVariables);
427 visitInfoList(sequence, mUniforms);
430 visitInfoList(sequence, mVaryings);
434 visitChildren = false;
441 return visitChildren;
444 bool CollectVariables::visitBinary(Visit, TIntermBinary *binaryNode)
446 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
448 // NOTE: we do not determine static use for individual blocks of an array
449 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
452 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
453 ASSERT(constantUnion);
455 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
456 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
458 namedBlock->staticUse = true;
460 unsigned int fieldIndex = constantUnion->getUConst(0);
461 ASSERT(fieldIndex < namedBlock->fields.size());
462 namedBlock->fields[fieldIndex].staticUse = true;
469 void ExpandUniforms(const std::vector<Uniform> &compact,
470 std::vector<ShaderVariable> *expanded)
472 for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++)
474 const ShaderVariable &variable = compact[variableIndex];
475 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);