blob: d58770f295a34b3bae1c3f59a19f152d6647f73f [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 Madill54ad4f82014-09-03 09:40:46 -040012namespace
13{
Zhenyao Mod2d340b2013-09-23 14:57:05 -040014
Jamie Madill54ad4f82014-09-03 09:40:46 -040015TString InterfaceBlockFieldName(const TInterfaceBlock &interfaceBlock, const TField &field)
16{
17 if (interfaceBlock.hasInstanceName())
18 {
19 return interfaceBlock.name() + "." + field.name();
20 }
21 else
22 {
23 return field.name();
24 }
25}
26
27sh::BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
28{
29 switch (blockStorage)
30 {
31 case EbsPacked: return sh::BLOCKLAYOUT_PACKED;
32 case EbsShared: return sh::BLOCKLAYOUT_SHARED;
33 case EbsStd140: return sh::BLOCKLAYOUT_STANDARD;
34 default: UNREACHABLE(); return sh::BLOCKLAYOUT_SHARED;
35 }
36}
37
38void ExpandUserDefinedVariable(const sh::ShaderVariable &variable,
39 const std::string &name,
40 const std::string &mappedName,
41 bool markStaticUse,
42 std::vector<sh::ShaderVariable> *expanded);
43
44void ExpandVariable(const sh::ShaderVariable &variable,
45 const std::string &name,
46 const std::string &mappedName,
47 bool markStaticUse,
48 std::vector<sh::ShaderVariable> *expanded)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000049{
Jamie Madill23a8a432014-07-09 13:27:42 -040050 if (variable.isStruct())
Jamie Madill4667c452014-07-08 15:02:36 -040051 {
Jamie Madill23a8a432014-07-09 13:27:42 -040052 if (variable.isArray())
53 {
54 for (size_t elementIndex = 0; elementIndex < variable.elementCount(); elementIndex++)
55 {
56 std::string lname = name + ArrayString(elementIndex);
57 std::string lmappedName = mappedName + ArrayString(elementIndex);
58 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
59 }
60 }
61 else
62 {
63 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
64 }
Jamie Madill4667c452014-07-08 15:02:36 -040065 }
66 else
67 {
Jamie Madill42bcf322014-08-25 16:20:46 -040068 sh::ShaderVariable expandedVar = variable;
Jamie Madill23a8a432014-07-09 13:27:42 -040069
70 expandedVar.name = name;
71 expandedVar.mappedName = mappedName;
72
73 // Mark all expanded fields as used if the parent is used
74 if (markStaticUse)
75 {
76 expandedVar.staticUse = true;
77 }
78
79 if (expandedVar.isArray())
80 {
81 expandedVar.name += "[0]";
82 expandedVar.mappedName += "[0]";
83 }
84
85 expanded->push_back(expandedVar);
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000086 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000087}
88
Jamie Madill54ad4f82014-09-03 09:40:46 -040089void ExpandUserDefinedVariable(const sh::ShaderVariable &variable,
90 const std::string &name,
91 const std::string &mappedName,
92 bool markStaticUse,
93 std::vector<sh::ShaderVariable> *expanded)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000094{
Jamie Madill23a8a432014-07-09 13:27:42 -040095 ASSERT(variable.isStruct());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000096
Jamie Madill42bcf322014-08-25 16:20:46 -040097 const std::vector<sh::ShaderVariable> &fields = variable.fields;
Jamie Madill23a8a432014-07-09 13:27:42 -040098
99 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill4667c452014-07-08 15:02:36 -0400100 {
Jamie Madill42bcf322014-08-25 16:20:46 -0400101 const sh::ShaderVariable &field = fields[fieldIndex];
Jamie Madill23a8a432014-07-09 13:27:42 -0400102 ExpandVariable(field,
103 name + "." + field.name,
104 mappedName + "." + field.mappedName,
105 markStaticUse,
106 expanded);
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000107 }
108}
109
Jamie Madilla718c1e2014-07-02 15:31:22 -0400110template <class VarT>
Jamie Madill54ad4f82014-09-03 09:40:46 -0400111VarT *FindVariable(const TString &name,
112 std::vector<VarT> *infoList)
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400113{
114 // TODO(zmo): optimize this function.
Jamie Madilla718c1e2014-07-02 15:31:22 -0400115 for (size_t ii = 0; ii < infoList->size(); ++ii)
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400116 {
Jamie Madill23a8a432014-07-09 13:27:42 -0400117 if ((*infoList)[ii].name.c_str() == name)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400118 return &((*infoList)[ii]);
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400119 }
Jamie Madilld5512cd2014-07-10 17:50:08 -0400120
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400121 return NULL;
122}
123
Jamie Madill54ad4f82014-09-03 09:40:46 -0400124}
125
Jamie Madilla718c1e2014-07-02 15:31:22 -0400126CollectVariables::CollectVariables(std::vector<sh::Attribute> *attribs,
Jamie Madilld5512cd2014-07-10 17:50:08 -0400127 std::vector<sh::Attribute> *outputVariables,
Jamie Madilla718c1e2014-07-02 15:31:22 -0400128 std::vector<sh::Uniform> *uniforms,
129 std::vector<sh::Varying> *varyings,
Jamie Madilld5512cd2014-07-10 17:50:08 -0400130 std::vector<sh::InterfaceBlock> *interfaceBlocks,
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400131 ShHashFunction64 hashFunction)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000132 : mAttribs(attribs),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400133 mOutputVariables(outputVariables),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000134 mUniforms(uniforms),
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400135 mVaryings(varyings),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400136 mInterfaceBlocks(interfaceBlocks),
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400137 mPointCoordAdded(false),
138 mFrontFacingAdded(false),
139 mFragCoordAdded(false),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000140 mHashFunction(hashFunction)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000141{
142}
143
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400144// We want to check whether a uniform/varying is statically used
145// because we only count the used ones in packing computing.
146// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
147// toward varying counting if they are statically used in a fragment
148// shader.
Jamie Madill4667c452014-07-08 15:02:36 -0400149void CollectVariables::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000150{
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400151 ASSERT(symbol != NULL);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400152 sh::ShaderVariable *var = NULL;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400153 const TString &symbolName = symbol->getSymbol();
Jamie Madill4667c452014-07-08 15:02:36 -0400154
155 if (sh::IsVarying(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400156 {
Jamie Madilld5512cd2014-07-10 17:50:08 -0400157 var = FindVariable(symbolName, mVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400158 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400159 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
160 {
161 UNREACHABLE();
162 }
163 else
Jamie Madill4667c452014-07-08 15:02:36 -0400164 {
165 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400166 {
Jamie Madilld5512cd2014-07-10 17:50:08 -0400167 case EvqAttribute:
168 case EvqVertexIn:
169 var = FindVariable(symbolName, mAttribs);
170 break;
171 case EvqFragmentOut:
172 var = FindVariable(symbolName, mOutputVariables);
173 break;
Jamie Madill4667c452014-07-08 15:02:36 -0400174 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400175 {
176 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
177 if (interfaceBlock)
178 {
179 sh::InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
180 ASSERT(namedBlock);
181 var = FindVariable(symbolName, &namedBlock->fields);
182
183 // Set static use on the parent interface block here
184 namedBlock->staticUse = true;
Jamie Madillb547ddf2014-08-25 16:20:46 -0400185
Jamie Madilld5512cd2014-07-10 17:50:08 -0400186 }
187 else
188 {
189 var = FindVariable(symbolName, mUniforms);
190 }
191
192 // It's an internal error to reference an undefined user uniform
193 ASSERT(symbolName.compare(0, 3, "gl_") == 0 || var);
194 }
Jamie Madill4667c452014-07-08 15:02:36 -0400195 break;
196 case EvqFragCoord:
197 if (!mFragCoordAdded)
198 {
199 sh::Varying info;
200 info.name = "gl_FragCoord";
201 info.mappedName = "gl_FragCoord";
202 info.type = GL_FLOAT_VEC4;
203 info.arraySize = 0;
204 info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter.
205 info.staticUse = true;
206 mVaryings->push_back(info);
207 mFragCoordAdded = true;
208 }
209 return;
210 case EvqFrontFacing:
211 if (!mFrontFacingAdded)
212 {
213 sh::Varying info;
214 info.name = "gl_FrontFacing";
215 info.mappedName = "gl_FrontFacing";
216 info.type = GL_BOOL;
217 info.arraySize = 0;
218 info.precision = GL_NONE;
219 info.staticUse = true;
220 mVaryings->push_back(info);
221 mFrontFacingAdded = true;
222 }
223 return;
224 case EvqPointCoord:
225 if (!mPointCoordAdded)
226 {
227 sh::Varying info;
228 info.name = "gl_PointCoord";
229 info.mappedName = "gl_PointCoord";
230 info.type = GL_FLOAT_VEC2;
231 info.arraySize = 0;
232 info.precision = GL_MEDIUM_FLOAT; // Use mediump as it doesn't really matter.
233 info.staticUse = true;
234 mVaryings->push_back(info);
235 mPointCoordAdded = true;
236 }
237 return;
238 default:
239 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400240 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400241 }
242 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400243 {
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400244 var->staticUse = true;
Jamie Madilla718c1e2014-07-02 15:31:22 -0400245 }
246}
247
Jamie Madill42bcf322014-08-25 16:20:46 -0400248class NameHashingTraverser : public sh::GetVariableTraverser
Jamie Madill23a8a432014-07-09 13:27:42 -0400249{
250 public:
Jamie Madill42bcf322014-08-25 16:20:46 -0400251 NameHashingTraverser(ShHashFunction64 hashFunction)
252 : mHashFunction(hashFunction)
Jamie Madill23a8a432014-07-09 13:27:42 -0400253 {}
254
255 private:
Jamie Madill42bcf322014-08-25 16:20:46 -0400256 DISALLOW_COPY_AND_ASSIGN(NameHashingTraverser);
257
258 virtual void visitVariable(sh::ShaderVariable *variable)
Jamie Madill23a8a432014-07-09 13:27:42 -0400259 {
260 TString stringName = TString(variable->name.c_str());
261 variable->mappedName = TIntermTraverser::hash(stringName, mHashFunction).c_str();
262 }
263
264 ShHashFunction64 mHashFunction;
265};
266
267// Attributes, which cannot have struct fields, are a special case
268template <>
269void CollectVariables::visitVariable(const TIntermSymbol *variable,
270 std::vector<sh::Attribute> *infoList) const
271{
272 ASSERT(variable);
273 const TType &type = variable->getType();
274 ASSERT(!type.getStruct());
275
276 sh::Attribute attribute;
277
278 attribute.type = sh::GLVariableType(type);
279 attribute.precision = sh::GLVariablePrecision(type);
280 attribute.name = variable->getSymbol().c_str();
281 attribute.arraySize = static_cast<unsigned int>(type.getArraySize());
282 attribute.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
283 attribute.location = variable->getType().getLayoutQualifier().location;
284
285 infoList->push_back(attribute);
286}
287
Jamie Madilld5512cd2014-07-10 17:50:08 -0400288template <>
289void CollectVariables::visitVariable(const TIntermSymbol *variable,
290 std::vector<sh::InterfaceBlock> *infoList) const
291{
292 sh::InterfaceBlock interfaceBlock;
293 const TInterfaceBlock *blockType = variable->getType().getInterfaceBlock();
Jamie Madill42bcf322014-08-25 16:20:46 -0400294 ASSERT(blockType);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400295
296 interfaceBlock.name = blockType->name().c_str();
297 interfaceBlock.mappedName = TIntermTraverser::hash(variable->getSymbol(), mHashFunction).c_str();
Jamie Madill42bcf322014-08-25 16:20:46 -0400298 interfaceBlock.instanceName = (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
Jamie Madilld5512cd2014-07-10 17:50:08 -0400299 interfaceBlock.arraySize = variable->getArraySize();
Jamie Madill42bcf322014-08-25 16:20:46 -0400300 interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
Jamie Madill54ad4f82014-09-03 09:40:46 -0400301 interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
Jamie Madilld5512cd2014-07-10 17:50:08 -0400302
Jamie Madilla6f267f2014-08-27 11:44:15 -0400303 // Gather field information
Jamie Madill54ad4f82014-09-03 09:40:46 -0400304 const TFieldList &fieldList = blockType->fields();
305
306 for (size_t fieldIndex = 0; fieldIndex < fieldList.size(); ++fieldIndex)
307 {
308 const TField &field = *fieldList[fieldIndex];
309 const TString &fullFieldName = InterfaceBlockFieldName(*blockType, field);
310 const TType &fieldType = *field.type();
311
312 sh::GetVariableTraverser traverser;
313 traverser.traverse(fieldType, fullFieldName, &interfaceBlock.fields);
314
315 interfaceBlock.fields.back().isRowMajorLayout = (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
316 }
Jamie Madilld5512cd2014-07-10 17:50:08 -0400317
318 infoList->push_back(interfaceBlock);
319}
320
Jamie Madill23a8a432014-07-09 13:27:42 -0400321template <typename VarT>
Jamie Madill4667c452014-07-08 15:02:36 -0400322void CollectVariables::visitVariable(const TIntermSymbol *variable,
323 std::vector<VarT> *infoList) const
324{
Jamie Madill42bcf322014-08-25 16:20:46 -0400325 NameHashingTraverser traverser(mHashFunction);
326 traverser.traverse(variable->getType(), variable->getSymbol(), infoList);
Jamie Madill4667c452014-07-08 15:02:36 -0400327}
328
329template <typename VarT>
330void CollectVariables::visitInfoList(const TIntermSequence &sequence,
331 std::vector<VarT> *infoList) const
Jamie Madilla718c1e2014-07-02 15:31:22 -0400332{
333 for (size_t seqIndex = 0; seqIndex < sequence.size(); seqIndex++)
334 {
Jamie Madill4667c452014-07-08 15:02:36 -0400335 const TIntermSymbol *variable = sequence[seqIndex]->getAsSymbolNode();
Jamie Madilla718c1e2014-07-02 15:31:22 -0400336 // The only case in which the sequence will not contain a
337 // TIntermSymbol node is initialization. It will contain a
338 // TInterBinary node in that case. Since attributes, uniforms,
339 // and varyings cannot be initialized in a shader, we must have
340 // only TIntermSymbol nodes in the sequence.
341 ASSERT(variable != NULL);
Jamie Madill4667c452014-07-08 15:02:36 -0400342 visitVariable(variable, infoList);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400343 }
alokp@chromium.org07620a52010-09-23 17:53:56 +0000344}
345
Jamie Madill4667c452014-07-08 15:02:36 -0400346bool CollectVariables::visitAggregate(Visit, TIntermAggregate *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000347{
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400348 bool visitChildren = true;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000349
350 switch (node->getOp())
351 {
Jamie Madill4667c452014-07-08 15:02:36 -0400352 case EOpDeclaration:
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000353 {
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700354 const TIntermSequence &sequence = *(node->getSequence());
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400355 ASSERT(!sequence.empty());
356
Zhenyao Moe40d1e92014-07-16 17:40:36 -0700357 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
Jamie Madilld5512cd2014-07-10 17:50:08 -0400358 TQualifier qualifier = typedNode.getQualifier();
359
360 if (typedNode.getBasicType() == EbtInterfaceBlock)
361 {
362 visitInfoList(sequence, mInterfaceBlocks);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400363 visitChildren = false;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400364 }
365 else if (qualifier == EvqAttribute || qualifier == EvqVertexIn ||
366 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
367 sh::IsVarying(qualifier))
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400368 {
Jamie Madill4667c452014-07-08 15:02:36 -0400369 switch (qualifier)
370 {
371 case EvqAttribute:
372 case EvqVertexIn:
373 visitInfoList(sequence, mAttribs);
374 break;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400375 case EvqFragmentOut:
376 visitInfoList(sequence, mOutputVariables);
377 break;
Jamie Madill4667c452014-07-08 15:02:36 -0400378 case EvqUniform:
379 visitInfoList(sequence, mUniforms);
380 break;
381 default:
Jamie Madill3b5c2da2014-08-19 15:23:32 -0400382 visitInfoList(sequence, mVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400383 break;
384 }
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400385
Jamie Madill1c28e1f2014-08-04 11:37:54 -0400386 visitChildren = false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000387 }
Jamie Madill4667c452014-07-08 15:02:36 -0400388 break;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000389 }
Jamie Madill4667c452014-07-08 15:02:36 -0400390 default: break;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000391 }
392
393 return visitChildren;
394}
Jamie Madill23a8a432014-07-09 13:27:42 -0400395
Jamie Madillb547ddf2014-08-25 16:20:46 -0400396bool CollectVariables::visitBinary(Visit, TIntermBinary *binaryNode)
397{
398 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
399 {
Jamie Madilla6f267f2014-08-27 11:44:15 -0400400 // NOTE: we do not determine static use for individual blocks of an array
401 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
402 ASSERT(blockNode);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400403
404 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
405 ASSERT(constantUnion);
406
Jamie Madilla6f267f2014-08-27 11:44:15 -0400407 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
Jamie Madillb547ddf2014-08-25 16:20:46 -0400408 sh::InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
409 ASSERT(namedBlock);
410 namedBlock->staticUse = true;
411
412 unsigned int fieldIndex = constantUnion->getUConst(0);
413 ASSERT(fieldIndex < namedBlock->fields.size());
414 namedBlock->fields[fieldIndex].staticUse = true;
415 return false;
416 }
417
418 return true;
419}
420
Jamie Madill23a8a432014-07-09 13:27:42 -0400421template <typename VarT>
Jamie Madill42bcf322014-08-25 16:20:46 -0400422void ExpandVariables(const std::vector<VarT> &compact,
423 std::vector<sh::ShaderVariable> *expanded)
Jamie Madill23a8a432014-07-09 13:27:42 -0400424{
425 for (size_t variableIndex = 0; variableIndex < compact.size(); variableIndex++)
426 {
Jamie Madill42bcf322014-08-25 16:20:46 -0400427 const sh::ShaderVariable &variable = compact[variableIndex];
Jamie Madill23a8a432014-07-09 13:27:42 -0400428 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
429 }
430}
431
Jamie Madill42bcf322014-08-25 16:20:46 -0400432template void ExpandVariables(const std::vector<sh::Uniform> &, std::vector<sh::ShaderVariable> *);
433template void ExpandVariables(const std::vector<sh::Varying> &, std::vector<sh::ShaderVariable> *);