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/VariableInfo.h"
9 #include "compiler/translator/util.h"
10 #include "common/utilities.h"
12 template <typename VarT>
13 static void ExpandUserDefinedVariable(const VarT &variable,
14 const std::string &name,
15 const std::string &mappedName,
17 std::vector<VarT> *expanded);
19 // Returns info for an attribute, uniform, or varying.
20 template <typename VarT>
21 static void ExpandVariable(const VarT &variable,
22 const std::string &name,
23 const std::string &mappedName,
25 std::vector<VarT> *expanded)
27 if (variable.isStruct())
29 if (variable.isArray())
31 for (size_t elementIndex = 0; elementIndex < variable.elementCount(); elementIndex++)
33 std::string lname = name + ArrayString(elementIndex);
34 std::string lmappedName = mappedName + ArrayString(elementIndex);
35 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
40 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
45 VarT expandedVar = variable;
47 expandedVar.name = name;
48 expandedVar.mappedName = mappedName;
50 // Mark all expanded fields as used if the parent is used
53 expandedVar.staticUse = true;
56 if (expandedVar.isArray())
58 expandedVar.name += "[0]";
59 expandedVar.mappedName += "[0]";
62 expanded->push_back(expandedVar);
67 static void ExpandUserDefinedVariable(const VarT &variable,
68 const std::string &name,
69 const std::string &mappedName,
71 std::vector<VarT> *expanded)
73 ASSERT(variable.isStruct());
75 const std::vector<VarT> &fields = variable.fields;
77 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
79 const VarT &field = fields[fieldIndex];
81 name + "." + field.name,
82 mappedName + "." + field.mappedName,
89 static VarT *FindVariable(const TString &name,
90 std::vector<VarT> *infoList)
92 // TODO(zmo): optimize this function.
93 for (size_t ii = 0; ii < infoList->size(); ++ii)
95 if ((*infoList)[ii].name.c_str() == name)
96 return &((*infoList)[ii]);
102 CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
103 std::vector<sh::Attribute> *outputVariables,
104 std::vector<sh::Uniform> *uniforms,
105 std::vector<sh::Varying> *varyings,
106 std::vector<sh::InterfaceBlock> *interfaceBlocks,
107 ShHashFunction64 hashFunction)
109 mOutputVariables(outputVariables),
112 mInterfaceBlocks(interfaceBlocks),
113 mPointCoordAdded(false),
114 mFrontFacingAdded(false),
115 mFragCoordAdded(false),
116 mHashFunction(hashFunction)
120 // We want to check whether a uniform/varying is statically used
121 // because we only count the used ones in packing computing.
122 // Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
123 // toward varying counting if they are statically used in a fragment
125 void CollectVariables::visitSymbol(TIntermSymbol *symbol)
127 ASSERT(symbol != NULL);
128 sh::ShaderVariable *var = NULL;
129 const TString &symbolName = symbol->getSymbol();
131 if (sh::IsVarying(symbol->getQualifier()))
133 var = FindVariable(symbolName, mVaryings);
135 else if (symbol->getType() != EbtInterfaceBlock)
137 switch (symbol->getQualifier())
141 var = FindVariable(symbolName, mAttribs);
144 var = FindVariable(symbolName, mOutputVariables);
148 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
151 sh::InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
153 var = FindVariable(symbolName, &namedBlock->fields);
155 // Set static use on the parent interface block here
156 namedBlock->staticUse = true;
160 var = FindVariable(symbolName, mUniforms);
163 // It's an internal error to reference an undefined user uniform
164 ASSERT(symbolName.compare(0, 3, "gl_") == 0 || var);
168 if (!mFragCoordAdded)
171 info.name = "gl_FragCoord";
172 info.mappedName = "gl_FragCoord";
173 info.type = GL_FLOAT_VEC4;
175 info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter.
176 info.staticUse = true;
177 mVaryings->push_back(info);
178 mFragCoordAdded = true;
182 if (!mFrontFacingAdded)
185 info.name = "gl_FrontFacing";
186 info.mappedName = "gl_FrontFacing";
189 info.precision = GL_NONE;
190 info.staticUse = true;
191 mVaryings->push_back(info);
192 mFrontFacingAdded = true;
196 if (!mPointCoordAdded)
199 info.name = "gl_PointCoord";
200 info.mappedName = "gl_PointCoord";
201 info.type = GL_FLOAT_VEC2;
203 info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter.
204 info.staticUse = true;
205 mVaryings->push_back(info);
206 mPointCoordAdded = true;
215 var->staticUse = true;
219 template <typename VarT>
220 class NameHashingTraverser : public sh::GetVariableTraverser<VarT>
223 NameHashingTraverser(std::vector<VarT> *output, ShHashFunction64 hashFunction)
224 : sh::GetVariableTraverser<VarT>(output),
225 mHashFunction(hashFunction)
229 void visitVariable(VarT *variable)
231 TString stringName = TString(variable->name.c_str());
232 variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str();
235 ShHashFunction64 mHashFunction;
238 // Attributes, which cannot have struct fields, are a special case
240 void CollectVariables::visitVariable(const TIntermSymbol *variable,
241 std::vector<sh::Attribute> *infoList) const
244 const TType &type = variable->getType();
245 ASSERT(!type.getStruct());
247 sh::Attribute attribute;
249 attribute.type = sh::GLVariableType(type);
250 attribute.precision = sh::GLVariablePrecision(type);
251 attribute.name = variable->getSymbol().c_str();
252 attribute.arraySize = static_cast<unsigned int>(type.getArraySize());
253 attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
254 attribute.location = variable->getType().getLayoutQualifier().location;
256 infoList->push_back(attribute);
260 void CollectVariables::visitVariable(const TIntermSymbol *variable,
261 std::vector<sh::InterfaceBlock> *infoList) const
263 sh::InterfaceBlock interfaceBlock;
264 const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock();
266 bool isRowMajor = (blockType->matrixPacking() == EmpRowMajor);
268 interfaceBlock.name = blockType->name().c_str();
269 interfaceBlock.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
270 interfaceBlock.arraySize = variable->getArraySize();
271 interfaceBlock.isRowMajorLayout = isRowMajor;
272 interfaceBlock.layout = sh::GetBlockLayoutType(blockType->blockStorage());
275 const TFieldList &blockFields = blockType->fields();
277 for (size_t fieldIndex = 0; fieldIndex < blockFields.size(); fieldIndex++)
279 const TField *field = blockFields[fieldIndex];
282 sh::GetInterfaceBlockFieldTraverser traverser(&interfaceBlock.fields, isRowMajor);
283 traverser.traverse(*field->type(), field->name());
286 infoList->push_back(interfaceBlock);
289 template <typename VarT>
290 void CollectVariables::visitVariable(const TIntermSymbol *variable,
291 std::vector<VarT> *infoList) const
293 NameHashingTraverser<VarT> traverser(infoList, mHashFunction);
294 traverser.traverse(variable->getType(), variable->getSymbol());
297 template <typename VarT>
298 void CollectVariables::visitInfoList(const TIntermSequence &sequence,
299 std::vector<VarT> *infoList) const
301 for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++)
303 const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode();
304 // The only case in which the sequence will not contain a
305 // TIntermSymbol node is initialization. It will contain a
306 // TInterBinary node in that case. Since attributes, uniforms,
307 // and varyings cannot be initialized in a shader, we must have
308 // only TIntermSymbol nodes in the sequence.
309 ASSERT(variable != NULL);
310 visitVariable(variable, infoList);
314 bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node)
316 bool visitChildren = true;
318 switch (node->getOp())
322 const TIntermSequence &sequence = *(node->getSequence());
323 ASSERT(!sequence.empty());
325 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
326 TQualifier qualifier = typedNode.getQualifier();
328 if (typedNode.getBasicType() == EbtInterfaceBlock)
330 visitInfoList(sequence, mInterfaceBlocks);
332 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn ||
333 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
334 sh::IsVarying(qualifier))
340 visitInfoList(sequence, mAttribs);
343 visitInfoList(sequence, mOutputVariables);
346 visitInfoList(sequence, mUniforms);
349 // do not traverse invariant declarations such as
350 // "invariant gl_Position;"
351 if (typedNode.getBasicType() != EbtInvariant)
353 visitInfoList(sequence, mVaryings);
358 visitChildren = false;
365 return visitChildren;
368 template <typename VarT>
369 void ExpandVariables(const std::vector<VarT> &compact, std::vector<VarT> *expanded)
371 for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++)
373 const VarT &variable = compact[variableIndex];
374 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
378 template void ExpandVariables(const std::vector<sh::Uniform> &, std::vector<sh::Uniform> *);
379 template void ExpandVariables(const std::vector<sh::Varying> &, std::vector<sh::Varying> *);