blob: 0bd95cb31e3e8399695cf9e91511d0f6d9787f8e [file] [log] [blame]
alokp@chromium.org07620a52010-09-23 17:53:56 +00001//
shannonwoods@chromium.orge429ab72013-05-30 00:12:52 +00002// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
alokp@chromium.org07620a52010-09-23 17:53:56 +00003// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
Jamie Madill4667c452014-07-08 15:02:36 -04007#include "angle_gl.h"
Geoff Lang17732822013-08-29 13:46:49 -04008#include "compiler/translator/VariableInfo.h"
Jamie Madillaa72d782014-07-02 15:31:19 -04009#include "compiler/translator/util.h"
Jamie Madilld5512cd2014-07-10 17:50:08 -040010#include "common/utilities.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000011
Jamie Madilla718c1e2014-07-02 15:31:22 -040012template <typename VarT>
Jamie Madill23a8a432014-07-09 13:27:42 -040013static void ExpandUserDefinedVariable(const VarT &variable,
14 const std::string &name,
15 const std::string &mappedName,
16 bool markStaticUse,
17 std::vector<VarT> *expanded);
Zhenyao Mod2d340b2013-09-23 14:57:05 -040018
19// Returns info for an attribute, uniform, or varying.
Jamie Madilla718c1e2014-07-02 15:31:22 -040020template <typename VarT>
Jamie Madill23a8a432014-07-09 13:27:42 -040021static void ExpandVariable(const VarT &variable,
22 const std::string &name,
23 const std::string &mappedName,
24 bool markStaticUse,
25 std::vector<VarT> *expanded)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000026{
Jamie Madill23a8a432014-07-09 13:27:42 -040027 if (variable.isStruct())
Jamie Madill4667c452014-07-08 15:02:36 -040028 {
Jamie Madill23a8a432014-07-09 13:27:42 -040029 if (variable.isArray())
30 {
31 for (size_t elementIndex = 0; elementIndex < variable.elementCount(); elementIndex++)
32 {
33 std::string lname = name + ArrayString(elementIndex);
34 std::string lmappedName = mappedName + ArrayString(elementIndex);
35 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
36 }
37 }
38 else
39 {
40 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
41 }
Jamie Madill4667c452014-07-08 15:02:36 -040042 }
43 else
44 {
Jamie Madill23a8a432014-07-09 13:27:42 -040045 VarT expandedVar = variable;
46
47 expandedVar.name = name;
48 expandedVar.mappedName = mappedName;
49
50 // Mark all expanded fields as used if the parent is used
51 if (markStaticUse)
52 {
53 expandedVar.staticUse = true;
54 }
55
56 if (expandedVar.isArray())
57 {
58 expandedVar.name += "[0]";
59 expandedVar.mappedName += "[0]";
60 }
61
62 expanded->push_back(expandedVar);
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000063 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000064}
65
Jamie Madilla718c1e2014-07-02 15:31:22 -040066template <class VarT>
Jamie Madill23a8a432014-07-09 13:27:42 -040067static void ExpandUserDefinedVariable(const VarT &variable,
68 const std::string &name,
69 const std::string &mappedName,
70 bool markStaticUse,
71 std::vector<VarT> *expanded)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000072{
Jamie Madill23a8a432014-07-09 13:27:42 -040073 ASSERT(variable.isStruct());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000074
Jamie Madill23a8a432014-07-09 13:27:42 -040075 const std::vector<VarT> &fields = variable.fields;
76
77 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill4667c452014-07-08 15:02:36 -040078 {
Jamie Madill23a8a432014-07-09 13:27:42 -040079 const VarT &field = fields[fieldIndex];
80 ExpandVariable(field,
81 name + "." + field.name,
82 mappedName + "." + field.mappedName,
83 markStaticUse,
84 expanded);
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000085 }
86}
87
Jamie Madilla718c1e2014-07-02 15:31:22 -040088template <class VarT>
Jamie Madilld5512cd2014-07-10 17:50:08 -040089static VarT *FindVariable(const TString &name,
Jamie Madill23a8a432014-07-09 13:27:42 -040090 std::vector<VarT> *infoList)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040091{
92 // TODO(zmo): optimize this function.
Jamie Madilla718c1e2014-07-02 15:31:22 -040093 for (size_t ii = 0; ii < infoList->size(); ++ii)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040094 {
Jamie Madill23a8a432014-07-09 13:27:42 -040095 if ((*infoList)[ii].name.c_str() == name)
Jamie Madilla718c1e2014-07-02 15:31:22 -040096 return &((*infoList)[ii]);
Zhenyao Mod2d340b2013-09-23 14:57:05 -040097 }
Jamie Madilld5512cd2014-07-10 17:50:08 -040098
Zhenyao Mod2d340b2013-09-23 14:57:05 -040099 return NULL;
100}
101
Jamie Madilla718c1e2014-07-02 15:31:22 -0400102CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
Jamie Madilld5512cd2014-07-10 17:50:08 -0400103 std::vector<sh::Attribute> *outputVariables,
Jamie Madilla718c1e2014-07-02 15:31:22 -0400104 std::vector<sh::Uniform> *uniforms,
105 std::vector<sh::Varying> *varyings,
Jamie Madilld5512cd2014-07-10 17:50:08 -0400106 std::vector<sh::InterfaceBlock> *interfaceBlocks,
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400107 ShHashFunction64 hashFunction)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000108 : mAttribs(attribs),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400109 mOutputVariables(outputVariables),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000110 mUniforms(uniforms),
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400111 mVaryings(varyings),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400112 mInterfaceBlocks(interfaceBlocks),
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400113 mPointCoordAdded(false),
114 mFrontFacingAdded(false),
115 mFragCoordAdded(false),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000116 mHashFunction(hashFunction)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000117{
118}
119
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400120// 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
124// shader.
Jamie Madill4667c452014-07-08 15:02:36 -0400125void CollectVariables::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000126{
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400127 ASSERT(symbol != NULL);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400128 sh::ShaderVariable *var = NULL;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400129 const TString &symbolName = symbol->getSymbol();
Jamie Madill4667c452014-07-08 15:02:36 -0400130
131 if (sh::IsVarying(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400132 {
Jamie Madilld5512cd2014-07-10 17:50:08 -0400133 var = FindVariable(symbolName, mVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400134 }
Jamie Madilld5512cd2014-07-10 17:50:08 -0400135 else if (symbol->getType() != EbtInterfaceBlock)
Jamie Madill4667c452014-07-08 15:02:36 -0400136 {
137 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400138 {
Jamie Madilld5512cd2014-07-10 17:50:08 -0400139 case EvqAttribute:
140 case EvqVertexIn:
141 var = FindVariable(symbolName, mAttribs);
142 break;
143 case EvqFragmentOut:
144 var = FindVariable(symbolName, mOutputVariables);
145 break;
Jamie Madill4667c452014-07-08 15:02:36 -0400146 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400147 {
148 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
149 if (interfaceBlock)
150 {
151 sh::InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
152 ASSERT(namedBlock);
153 var = FindVariable(symbolName, &namedBlock->fields);
154
155 // Set static use on the parent interface block here
156 namedBlock->staticUse = true;
157 }
158 else
159 {
160 var = FindVariable(symbolName, mUniforms);
161 }
162
163 // It's an internal error to reference an undefined user uniform
164 ASSERT(symbolName.compare(0, 3, "gl_") == 0 || var);
165 }
Jamie Madill4667c452014-07-08 15:02:36 -0400166 break;
167 case EvqFragCoord:
168 if (!mFragCoordAdded)
169 {
170 sh::Varying info;
171 info.name = "gl_FragCoord";
172 info.mappedName = "gl_FragCoord";
173 info.type = GL_FLOAT_VEC4;
174 info.arraySize = 0;
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;
179 }
180 return;
181 case EvqFrontFacing:
182 if (!mFrontFacingAdded)
183 {
184 sh::Varying info;
185 info.name = "gl_FrontFacing";
186 info.mappedName = "gl_FrontFacing";
187 info.type = GL_BOOL;
188 info.arraySize = 0;
189 info.precision = GL_NONE;
190 info.staticUse = true;
191 mVaryings->push_back(info);
192 mFrontFacingAdded = true;
193 }
194 return;
195 case EvqPointCoord:
196 if (!mPointCoordAdded)
197 {
198 sh::Varying info;
199 info.name = "gl_PointCoord";
200 info.mappedName = "gl_PointCoord";
201 info.type = GL_FLOAT_VEC2;
202 info.arraySize = 0;
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;
207 }
208 return;
209 default:
210 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400211 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400212 }
213 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400214 {
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400215 var->staticUse = true;
Jamie Madilla718c1e2014-07-02 15:31:22 -0400216 }
217}
218
219template <typename VarT>
Jamie Madill23a8a432014-07-09 13:27:42 -0400220class NameHashingTraverser : public sh::GetVariableTraverser<VarT>
221{
222 public:
223 NameHashingTraverser(std::vector<VarT> *output, ShHashFunction64 hashFunction)
224 : sh::GetVariableTraverser<VarT>(output),
225 mHashFunction(hashFunction)
226 {}
227
228 private:
229 void visitVariable(VarT *variable)
230 {
231 TString stringName = TString(variable->name.c_str());
232 variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str();
233 }
234
235 ShHashFunction64 mHashFunction;
236};
237
238// Attributes, which cannot have struct fields, are a special case
239template <>
240void CollectVariables::visitVariable(const TIntermSymbol *variable,
241 std::vector<sh::Attribute> *infoList) const
242{
243 ASSERT(variable);
244 const TType &type = variable->getType();
245 ASSERT(!type.getStruct());
246
247 sh::Attribute attribute;
248
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;
255
256 infoList->push_back(attribute);
257}
258
Jamie Madilld5512cd2014-07-10 17:50:08 -0400259template <>
260void CollectVariables::visitVariable(const TIntermSymbol *variable,
261 std::vector<sh::InterfaceBlock> *infoList) const
262{
263 sh::InterfaceBlock interfaceBlock;
264 const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock();
265
266 bool isRowMajor = (blockType->matrixPacking() == EmpRowMajor);
267
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());
273
274 ASSERT(blockType);
275 const TFieldList &blockFields = blockType->fields();
276
277 for (size_t fieldIndex = 0; fieldIndex < blockFields.size(); fieldIndex++)
278 {
279 const TField *field = blockFields[fieldIndex];
280 ASSERT(field);
281
282 sh::GetInterfaceBlockFieldTraverser traverser(&interfaceBlock.fields, isRowMajor);
283 traverser.traverse(*field->type(), field->name());
284 }
285
286 infoList->push_back(interfaceBlock);
287}
288
Jamie Madill23a8a432014-07-09 13:27:42 -0400289template <typename VarT>
Jamie Madill4667c452014-07-08 15:02:36 -0400290void CollectVariables::visitVariable(const TIntermSymbol *variable,
291 std::vector<VarT> *infoList) const
292{
Jamie Madill23a8a432014-07-09 13:27:42 -0400293 NameHashingTraverser<VarT> traverser(infoList, mHashFunction);
294 traverser.traverse(variable->getType(), variable->getSymbol());
Jamie Madill4667c452014-07-08 15:02:36 -0400295}
296
297template <typename VarT>
298void CollectVariables::visitInfoList(const TIntermSequence &sequence,
299 std::vector<VarT> *infoList) const
Jamie Madilla718c1e2014-07-02 15:31:22 -0400300{
301 for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++)
302 {
Jamie Madill4667c452014-07-08 15:02:36 -0400303 const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode();
Jamie Madilla718c1e2014-07-02 15:31:22 -0400304 // 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);
Jamie Madill4667c452014-07-08 15:02:36 -0400310 visitVariable(variable, infoList);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400311 }
alokp@chromium.org07620a52010-09-23 17:53:56 +0000312}
313
Jamie Madill4667c452014-07-08 15:02:36 -0400314bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000315{
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400316 bool visitChildren = true;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000317
318 switch (node->getOp())
319 {
Jamie Madill4667c452014-07-08 15:02:36 -0400320 case EOpDeclaration:
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000321 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700322 const TIntermSequence &sequence = *(node->getSequence());
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400323 ASSERT(!sequence.empty());
324
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700325 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
Jamie Madilld5512cd2014-07-10 17:50:08 -0400326 TQualifier qualifier = typedNode.getQualifier();
327
328 if (typedNode.getBasicType() == EbtInterfaceBlock)
329 {
330 visitInfoList(sequence, mInterfaceBlocks);
331 }
332 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn ||
333 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
334 sh::IsVarying(qualifier))
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400335 {
Jamie Madill4667c452014-07-08 15:02:36 -0400336 switch (qualifier)
337 {
338 case EvqAttribute:
339 case EvqVertexIn:
340 visitInfoList(sequence, mAttribs);
341 break;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400342 case EvqFragmentOut:
343 visitInfoList(sequence, mOutputVariables);
344 break;
Jamie Madill4667c452014-07-08 15:02:36 -0400345 case EvqUniform:
346 visitInfoList(sequence, mUniforms);
347 break;
348 default:
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400349 // do not traverse invariant declarations such as
350 // "invariant gl_Position;"
351 if (typedNode.getBasicType() != EbtInvariant)
352 {
353 visitInfoList(sequence, mVaryings);
354 }
Jamie Madill4667c452014-07-08 15:02:36 -0400355 break;
356 }
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400357
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400358 visitChildren = false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000359 }
Jamie Madill4667c452014-07-08 15:02:36 -0400360 break;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000361 }
Jamie Madill4667c452014-07-08 15:02:36 -0400362 default: break;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000363 }
364
365 return visitChildren;
366}
Jamie Madill23a8a432014-07-09 13:27:42 -0400367
368template <typename VarT>
369void ExpandVariables(const std::vector<VarT> &compact, std::vector<VarT> *expanded)
370{
371 for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++)
372 {
373 const VarT &variable = compact[variableIndex];
374 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
375 }
376}
377
378template void ExpandVariables(const std::vector<sh::Uniform> &, std::vector<sh::Uniform> *);
379template void ExpandVariables(const std::vector<sh::Varying> &, std::vector<sh::Varying> *);