blob: cb22d402e6beb1191885e2e98f4d07b9e0c7ee01 [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
Geoff Lang17732822013-08-29 13:46:49 -04007#include "compiler/translator/VariableInfo.h"
Olli Etuaho19515012017-06-26 18:00:17 +03008
9#include "angle_gl.h"
Jamie Madilld5512cd2014-07-10 17:50:08 -040010#include "common/utilities.h"
Olli Etuaho19515012017-06-26 18:00:17 +030011#include "compiler/translator/IntermNode.h"
12#include "compiler/translator/SymbolTable.h"
13#include "compiler/translator/util.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000014
Jamie Madilla2fbb842014-09-03 09:40:47 -040015namespace sh
16{
17
Jamie Madill54ad4f82014-09-03 09:40:46 -040018namespace
19{
Zhenyao Mod2d340b2013-09-23 14:57:05 -040020
Jamie Madilla2fbb842014-09-03 09:40:47 -040021BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
Jamie Madill54ad4f82014-09-03 09:40:46 -040022{
23 switch (blockStorage)
24 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050025 case EbsPacked:
26 return BLOCKLAYOUT_PACKED;
27 case EbsShared:
28 return BLOCKLAYOUT_SHARED;
29 case EbsStd140:
30 return BLOCKLAYOUT_STANDARD;
31 default:
32 UNREACHABLE();
33 return BLOCKLAYOUT_SHARED;
Jamie Madill54ad4f82014-09-03 09:40:46 -040034 }
35}
36
Jamie Madilla2fbb842014-09-03 09:40:47 -040037void ExpandUserDefinedVariable(const ShaderVariable &variable,
Jamie Madill54ad4f82014-09-03 09:40:46 -040038 const std::string &name,
39 const std::string &mappedName,
40 bool markStaticUse,
Jamie Madilla2fbb842014-09-03 09:40:47 -040041 std::vector<ShaderVariable> *expanded)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000042{
Jamie Madill23a8a432014-07-09 13:27:42 -040043 ASSERT(variable.isStruct());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000044
Jamie Madilla2fbb842014-09-03 09:40:47 -040045 const std::vector<ShaderVariable> &fields = variable.fields;
Jamie Madill23a8a432014-07-09 13:27:42 -040046
47 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill4667c452014-07-08 15:02:36 -040048 {
Jamie Madilla2fbb842014-09-03 09:40:47 -040049 const ShaderVariable &field = fields[fieldIndex];
Jamie Madilld7b1ab52016-12-12 14:42:19 -050050 ExpandVariable(field, name + "." + field.name, mappedName + "." + field.mappedName,
51 markStaticUse, expanded);
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000052 }
53}
54
Jamie Madilla718c1e2014-07-02 15:31:22 -040055template <class VarT>
Jamie Madilld7b1ab52016-12-12 14:42:19 -050056VarT *FindVariable(const TString &name, std::vector<VarT> *infoList)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040057{
58 // TODO(zmo): optimize this function.
Jamie Madilla718c1e2014-07-02 15:31:22 -040059 for (size_t ii = 0; ii < infoList->size(); ++ii)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040060 {
Jamie Madill23a8a432014-07-09 13:27:42 -040061 if ((*infoList)[ii].name.c_str() == name)
Jamie Madilla718c1e2014-07-02 15:31:22 -040062 return &((*infoList)[ii]);
Zhenyao Mod2d340b2013-09-23 14:57:05 -040063 }
Jamie Madilld5512cd2014-07-10 17:50:08 -040064
Yunchao Hef81ce4a2017-04-24 10:49:17 +080065 return nullptr;
Zhenyao Mod2d340b2013-09-23 14:57:05 -040066}
Jamie Madill54ad4f82014-09-03 09:40:46 -040067
Olli Etuaho19515012017-06-26 18:00:17 +030068// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
69// and interface blocks.
70class CollectVariablesTraverser : public TIntermTraverser
71{
72 public:
73 CollectVariablesTraverser(std::vector<Attribute> *attribs,
74 std::vector<OutputVariable> *outputVariables,
75 std::vector<Uniform> *uniforms,
76 std::vector<Varying> *varyings,
77 std::vector<InterfaceBlock> *interfaceBlocks,
78 ShHashFunction64 hashFunction,
79 const TSymbolTable &symbolTable,
80 int shaderVersion,
81 const TExtensionBehavior &extensionBehavior);
82
83 void visitSymbol(TIntermSymbol *symbol) override;
84 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
85 bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
86
87 private:
88 void setCommonVariableProperties(const TType &type,
89 const TString &name,
90 ShaderVariable *variableOut) const;
91
92 Attribute recordAttribute(const TIntermSymbol &variable) const;
93 OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
94 Varying recordVarying(const TIntermSymbol &variable) const;
95 InterfaceBlock recordInterfaceBlock(const TIntermSymbol &variable) const;
96 Uniform recordUniform(const TIntermSymbol &variable) const;
97
98 void setBuiltInInfoFromSymbolTable(const char *name, ShaderVariable *info);
99
100 void recordBuiltInVaryingUsed(const char *name, bool *addedFlag);
101 void recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag);
102 void recordBuiltInAttributeUsed(const char *name, bool *addedFlag);
103
104 std::vector<Attribute> *mAttribs;
105 std::vector<OutputVariable> *mOutputVariables;
106 std::vector<Uniform> *mUniforms;
107 std::vector<Varying> *mVaryings;
108 std::vector<InterfaceBlock> *mInterfaceBlocks;
109
110 std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
111
112 bool mDepthRangeAdded;
113 bool mPointCoordAdded;
114 bool mFrontFacingAdded;
115 bool mFragCoordAdded;
116
117 bool mInstanceIDAdded;
118 bool mVertexIDAdded;
119 bool mPositionAdded;
120 bool mPointSizeAdded;
121 bool mLastFragDataAdded;
122 bool mFragColorAdded;
123 bool mFragDataAdded;
124 bool mFragDepthEXTAdded;
125 bool mFragDepthAdded;
126 bool mSecondaryFragColorEXTAdded;
127 bool mSecondaryFragDataEXTAdded;
128
129 ShHashFunction64 mHashFunction;
130
131 const TSymbolTable &mSymbolTable;
132 int mShaderVersion;
133 const TExtensionBehavior &mExtensionBehavior;
134};
135
136CollectVariablesTraverser::CollectVariablesTraverser(
137 std::vector<sh::Attribute> *attribs,
138 std::vector<sh::OutputVariable> *outputVariables,
139 std::vector<sh::Uniform> *uniforms,
140 std::vector<sh::Varying> *varyings,
141 std::vector<sh::InterfaceBlock> *interfaceBlocks,
142 ShHashFunction64 hashFunction,
143 const TSymbolTable &symbolTable,
144 int shaderVersion,
145 const TExtensionBehavior &extensionBehavior)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +0300146 : TIntermTraverser(true, false, false),
147 mAttribs(attribs),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400148 mOutputVariables(outputVariables),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000149 mUniforms(uniforms),
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400150 mVaryings(varyings),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400151 mInterfaceBlocks(interfaceBlocks),
Jamie Madill55def582015-05-04 11:24:57 -0400152 mDepthRangeAdded(false),
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400153 mPointCoordAdded(false),
154 mFrontFacingAdded(false),
155 mFragCoordAdded(false),
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000156 mInstanceIDAdded(false),
Corentin Wallezb076add2016-01-11 16:45:46 -0500157 mVertexIDAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700158 mPositionAdded(false),
159 mPointSizeAdded(false),
Erik Dahlströmea7a2122014-11-17 16:15:57 +0100160 mLastFragDataAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300161 mFragColorAdded(false),
162 mFragDataAdded(false),
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300163 mFragDepthEXTAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300164 mFragDepthAdded(false),
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +0300165 mSecondaryFragColorEXTAdded(false),
166 mSecondaryFragDataEXTAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700167 mHashFunction(hashFunction),
Zhenyao Mof178d0b2016-07-23 06:59:00 -0700168 mSymbolTable(symbolTable),
Olli Etuaho19515012017-06-26 18:00:17 +0300169 mShaderVersion(shaderVersion),
Zhenyao Mof178d0b2016-07-23 06:59:00 -0700170 mExtensionBehavior(extensionBehavior)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000171{
172}
173
Olli Etuaho19515012017-06-26 18:00:17 +0300174void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
175 ShaderVariable *info)
176{
177 TVariable *symbolTableVar =
178 reinterpret_cast<TVariable *>(mSymbolTable.findBuiltIn(name, mShaderVersion));
179 ASSERT(symbolTableVar);
180 const TType &type = symbolTableVar->getType();
181
182 info->name = name;
183 info->mappedName = name;
184 info->type = GLVariableType(type);
185 info->arraySize = type.isArray() ? type.getArraySize() : 0;
186 info->precision = GLVariablePrecision(type);
187}
188
189void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name, bool *addedFlag)
190{
191 if (!(*addedFlag))
192 {
193 Varying info;
194 setBuiltInInfoFromSymbolTable(name, &info);
195 info.staticUse = true;
196 info.isInvariant = mSymbolTable.isVaryingInvariant(name);
197 mVaryings->push_back(info);
198 (*addedFlag) = true;
199 }
200}
201
202void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag)
203{
204 if (!(*addedFlag))
205 {
206 OutputVariable info;
207 setBuiltInInfoFromSymbolTable(name, &info);
208 info.staticUse = true;
209 mOutputVariables->push_back(info);
210 (*addedFlag) = true;
211 }
212}
213
214void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag)
215{
216 if (!(*addedFlag))
217 {
218 Attribute info;
219 setBuiltInInfoFromSymbolTable(name, &info);
220 info.staticUse = true;
221 info.location = -1;
222 mAttribs->push_back(info);
223 (*addedFlag) = true;
224 }
225}
226
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400227// We want to check whether a uniform/varying is statically used
228// because we only count the used ones in packing computing.
229// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
230// toward varying counting if they are statically used in a fragment
231// shader.
Olli Etuaho19515012017-06-26 18:00:17 +0300232void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000233{
Yunchao He4f285442017-04-21 12:15:49 +0800234 ASSERT(symbol != nullptr);
Yunchao Hed7297bf2017-04-19 15:27:10 +0800235 ShaderVariable *var = nullptr;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400236 const TString &symbolName = symbol->getSymbol();
Jamie Madill4667c452014-07-08 15:02:36 -0400237
Jamie Madilla2fbb842014-09-03 09:40:47 -0400238 if (IsVarying(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400239 {
Jamie Madilld5512cd2014-07-10 17:50:08 -0400240 var = FindVariable(symbolName, mVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400241 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400242 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
243 {
244 UNREACHABLE();
245 }
Jamie Madill55def582015-05-04 11:24:57 -0400246 else if (symbolName == "gl_DepthRange")
247 {
248 ASSERT(symbol->getQualifier() == EvqUniform);
249
250 if (!mDepthRangeAdded)
251 {
252 Uniform info;
253 const char kName[] = "gl_DepthRange";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500254 info.name = kName;
255 info.mappedName = kName;
256 info.type = GL_STRUCT_ANGLEX;
257 info.arraySize = 0;
258 info.precision = GL_NONE;
259 info.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400260
261 ShaderVariable nearInfo;
262 const char kNearName[] = "near";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500263 nearInfo.name = kNearName;
264 nearInfo.mappedName = kNearName;
265 nearInfo.type = GL_FLOAT;
266 nearInfo.arraySize = 0;
267 nearInfo.precision = GL_HIGH_FLOAT;
268 nearInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400269
270 ShaderVariable farInfo;
271 const char kFarName[] = "far";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500272 farInfo.name = kFarName;
273 farInfo.mappedName = kFarName;
274 farInfo.type = GL_FLOAT;
275 farInfo.arraySize = 0;
276 farInfo.precision = GL_HIGH_FLOAT;
277 farInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400278
279 ShaderVariable diffInfo;
280 const char kDiffName[] = "diff";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500281 diffInfo.name = kDiffName;
282 diffInfo.mappedName = kDiffName;
283 diffInfo.type = GL_FLOAT;
284 diffInfo.arraySize = 0;
285 diffInfo.precision = GL_HIGH_FLOAT;
286 diffInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400287
288 info.fields.push_back(nearInfo);
289 info.fields.push_back(farInfo);
290 info.fields.push_back(diffInfo);
291
292 mUniforms->push_back(info);
293 mDepthRangeAdded = true;
294 }
295 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400296 else
Jamie Madill4667c452014-07-08 15:02:36 -0400297 {
298 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400299 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500300 case EvqAttribute:
301 case EvqVertexIn:
302 var = FindVariable(symbolName, mAttribs);
303 break;
304 case EvqFragmentOut:
305 var = FindVariable(symbolName, mOutputVariables);
306 break;
307 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400308 {
309 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
310 if (interfaceBlock)
311 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500312 InterfaceBlock *namedBlock =
313 FindVariable(interfaceBlock->name(), mInterfaceBlocks);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400314 ASSERT(namedBlock);
315 var = FindVariable(symbolName, &namedBlock->fields);
316
317 // Set static use on the parent interface block here
318 namedBlock->staticUse = true;
319 }
320 else
321 {
322 var = FindVariable(symbolName, mUniforms);
323 }
324
325 // It's an internal error to reference an undefined user uniform
Jamie Madill55def582015-05-04 11:24:57 -0400326 ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400327 }
Jamie Madill4667c452014-07-08 15:02:36 -0400328 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500329 case EvqFragCoord:
Olli Etuaho19515012017-06-26 18:00:17 +0300330 recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500331 return;
332 case EvqFrontFacing:
Olli Etuaho19515012017-06-26 18:00:17 +0300333 recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500334 return;
335 case EvqPointCoord:
Olli Etuaho19515012017-06-26 18:00:17 +0300336 recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500337 return;
338 case EvqInstanceID:
Olli Etuaho19515012017-06-26 18:00:17 +0300339 recordBuiltInAttributeUsed("gl_InstanceID", &mInstanceIDAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500340 return;
341 case EvqVertexID:
Olli Etuaho19515012017-06-26 18:00:17 +0300342 recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500343 return;
344 case EvqPosition:
Olli Etuaho19515012017-06-26 18:00:17 +0300345 recordBuiltInVaryingUsed("gl_Position", &mPositionAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500346 return;
347 case EvqPointSize:
Olli Etuaho19515012017-06-26 18:00:17 +0300348 recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500349 return;
350 case EvqLastFragData:
Olli Etuaho19515012017-06-26 18:00:17 +0300351 recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500352 return;
353 case EvqFragColor:
Olli Etuaho19515012017-06-26 18:00:17 +0300354 recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500355 return;
356 case EvqFragData:
357 if (!mFragDataAdded)
358 {
359 OutputVariable info;
Olli Etuaho19515012017-06-26 18:00:17 +0300360 setBuiltInInfoFromSymbolTable("gl_FragData", &info);
361 if (!::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500362 {
363 info.arraySize = 1;
364 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500365 info.staticUse = true;
366 mOutputVariables->push_back(info);
367 mFragDataAdded = true;
368 }
369 return;
370 case EvqFragDepthEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300371 recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500372 return;
373 case EvqFragDepth:
Olli Etuaho19515012017-06-26 18:00:17 +0300374 recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500375 return;
376 case EvqSecondaryFragColorEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300377 recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT",
378 &mSecondaryFragColorEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500379 return;
380 case EvqSecondaryFragDataEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300381 recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
382 &mSecondaryFragDataEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500383 return;
384 default:
385 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400386 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400387 }
388 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400389 {
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400390 var->staticUse = true;
Jamie Madilla718c1e2014-07-02 15:31:22 -0400391 }
392}
393
Olli Etuaho19515012017-06-26 18:00:17 +0300394void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
395 const TString &name,
396 ShaderVariable *variableOut) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400397{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000398 ASSERT(variableOut);
399
400 const TStructure *structure = type.getStruct();
401
402 if (!structure)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500403 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000404 variableOut->type = GLVariableType(type);
405 variableOut->precision = GLVariablePrecision(type);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500406 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000407 else
Jamie Madill23a8a432014-07-09 13:27:42 -0400408 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000409 // Note: this enum value is not exposed outside ANGLE
410 variableOut->type = GL_STRUCT_ANGLEX;
411 variableOut->structName = structure->name().c_str();
412
413 const TFieldList &fields = structure->fields();
414
415 for (TField *field : fields)
416 {
417 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
418 // ShaderVariable objects.
419 ShaderVariable fieldVariable;
420 setCommonVariableProperties(*field->type(), field->name(), &fieldVariable);
421 variableOut->fields.push_back(fieldVariable);
422 }
Jamie Madill23a8a432014-07-09 13:27:42 -0400423 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000424 variableOut->name = name.c_str();
425 variableOut->mappedName = TIntermTraverser::hash(name, mHashFunction).c_str();
426 variableOut->arraySize = type.getArraySize();
427}
Jamie Madill23a8a432014-07-09 13:27:42 -0400428
Olli Etuaho19515012017-06-26 18:00:17 +0300429Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400430{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000431 const TType &type = variable.getType();
Jamie Madill23a8a432014-07-09 13:27:42 -0400432 ASSERT(!type.getStruct());
433
Jamie Madilla2fbb842014-09-03 09:40:47 -0400434 Attribute attribute;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000435 setCommonVariableProperties(type, variable.getSymbol(), &attribute);
Jamie Madill23a8a432014-07-09 13:27:42 -0400436
Olli Etuahoa55102c2017-02-24 12:36:50 +0000437 attribute.location = type.getLayoutQualifier().location;
438 return attribute;
Jamie Madill23a8a432014-07-09 13:27:42 -0400439}
440
Olli Etuaho19515012017-06-26 18:00:17 +0300441OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
Jamie Madilla0a9e122015-09-02 15:54:30 -0400442{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000443 const TType &type = variable.getType();
Jamie Madilla0a9e122015-09-02 15:54:30 -0400444 ASSERT(!type.getStruct());
445
Olli Etuahoa55102c2017-02-24 12:36:50 +0000446 OutputVariable outputVariable;
447 setCommonVariableProperties(type, variable.getSymbol(), &outputVariable);
Jamie Madilla0a9e122015-09-02 15:54:30 -0400448
Olli Etuahoa55102c2017-02-24 12:36:50 +0000449 outputVariable.location = type.getLayoutQualifier().location;
450 return outputVariable;
Jamie Madilla0a9e122015-09-02 15:54:30 -0400451}
452
Olli Etuaho19515012017-06-26 18:00:17 +0300453Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
Jamie Madilld5512cd2014-07-10 17:50:08 -0400454{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000455 const TType &type = variable.getType();
456
457 Varying varying;
458 setCommonVariableProperties(type, variable.getSymbol(), &varying);
459
460 switch (type.getQualifier())
461 {
462 case EvqVaryingIn:
463 case EvqVaryingOut:
464 case EvqVertexOut:
465 case EvqSmoothOut:
466 case EvqFlatOut:
467 case EvqCentroidOut:
468 if (mSymbolTable.isVaryingInvariant(std::string(variable.getSymbol().c_str())) ||
469 type.isInvariant())
470 {
471 varying.isInvariant = true;
472 }
473 break;
474 default:
475 break;
476 }
477
478 varying.interpolation = GetInterpolationType(type.getQualifier());
479 return varying;
480}
481
Olli Etuaho19515012017-06-26 18:00:17 +0300482InterfaceBlock CollectVariablesTraverser::recordInterfaceBlock(const TIntermSymbol &variable) const
Olli Etuahoa55102c2017-02-24 12:36:50 +0000483{
484 const TInterfaceBlock *blockType = variable.getType().getInterfaceBlock();
Jamie Madill42bcf322014-08-25 16:20:46 -0400485 ASSERT(blockType);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400486
Olli Etuahoa55102c2017-02-24 12:36:50 +0000487 InterfaceBlock interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400488 interfaceBlock.name = blockType->name().c_str();
Jeff Muizelaardbfdca82015-11-06 12:46:30 -0500489 interfaceBlock.mappedName =
490 TIntermTraverser::hash(blockType->name().c_str(), mHashFunction).c_str();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500491 interfaceBlock.instanceName =
492 (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
Olli Etuahoa55102c2017-02-24 12:36:50 +0000493 interfaceBlock.arraySize = variable.getArraySize();
Jamie Madill42bcf322014-08-25 16:20:46 -0400494 interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
jchen10af713a22017-04-19 09:10:56 +0800495 interfaceBlock.binding = blockType->blockBinding();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500496 interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
Jamie Madilld5512cd2014-07-10 17:50:08 -0400497
Jamie Madilla6f267f2014-08-27 11:44:15 -0400498 // Gather field information
Jamie Madill39046162016-02-08 15:05:17 -0500499 for (const TField *field : blockType->fields())
Jamie Madill54ad4f82014-09-03 09:40:46 -0400500 {
Jamie Madill39046162016-02-08 15:05:17 -0500501 const TType &fieldType = *field->type();
Jamie Madill54ad4f82014-09-03 09:40:46 -0400502
Olli Etuahoa55102c2017-02-24 12:36:50 +0000503 InterfaceBlockField fieldVariable;
504 setCommonVariableProperties(fieldType, field->name(), &fieldVariable);
505 fieldVariable.isRowMajorLayout =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500506 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
Olli Etuahoa55102c2017-02-24 12:36:50 +0000507 interfaceBlock.fields.push_back(fieldVariable);
Jamie Madill54ad4f82014-09-03 09:40:46 -0400508 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000509 return interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400510}
511
Olli Etuaho19515012017-06-26 18:00:17 +0300512Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
Jamie Madill4667c452014-07-08 15:02:36 -0400513{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000514 Uniform uniform;
515 setCommonVariableProperties(variable.getType(), variable.getSymbol(), &uniform);
Olli Etuaho547cbd42017-02-27 11:54:00 +0200516 uniform.binding = variable.getType().getLayoutQualifier().binding;
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000517 uniform.location = variable.getType().getLayoutQualifier().location;
jchen104cdac9e2017-05-08 11:01:20 +0800518 uniform.offset = variable.getType().getLayoutQualifier().offset;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000519 return uniform;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000520}
521
Olli Etuaho19515012017-06-26 18:00:17 +0300522bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000523{
Olli Etuaho13389b62016-10-16 11:48:18 +0100524 const TIntermSequence &sequence = *(node->getSequence());
525 ASSERT(!sequence.empty());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000526
Olli Etuaho13389b62016-10-16 11:48:18 +0100527 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
528 TQualifier qualifier = typedNode.getQualifier();
529
Olli Etuahoa55102c2017-02-24 12:36:50 +0000530 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
531 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
532 IsVarying(qualifier);
533
534 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000535 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000536 return true;
Olli Etuaho13389b62016-10-16 11:48:18 +0100537 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000538
539 for (TIntermNode *variableNode : sequence)
Olli Etuaho13389b62016-10-16 11:48:18 +0100540 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000541 // The only case in which the sequence will not contain a TIntermSymbol node is
542 // initialization. It will contain a TInterBinary node in that case. Since attributes,
543 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
544 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
545 const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
546 if (typedNode.getBasicType() == EbtInterfaceBlock)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000547 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000548 mInterfaceBlocks->push_back(recordInterfaceBlock(variable));
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000549 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000550 else
551 {
552 switch (qualifier)
553 {
554 case EvqAttribute:
555 case EvqVertexIn:
556 mAttribs->push_back(recordAttribute(variable));
557 break;
558 case EvqFragmentOut:
559 mOutputVariables->push_back(recordOutputVariable(variable));
560 break;
561 case EvqUniform:
562 mUniforms->push_back(recordUniform(variable));
563 break;
564 default:
565 mVaryings->push_back(recordVarying(variable));
566 break;
567 }
568 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000569 }
570
Olli Etuahoa55102c2017-02-24 12:36:50 +0000571 // None of the recorded variables can have initializers, so we don't need to traverse the
572 // declarators.
573 return false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000574}
Jamie Madill23a8a432014-07-09 13:27:42 -0400575
Olli Etuaho19515012017-06-26 18:00:17 +0300576bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
Jamie Madillb547ddf2014-08-25 16:20:46 -0400577{
578 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
579 {
Jamie Madilla6f267f2014-08-27 11:44:15 -0400580 // NOTE: we do not determine static use for individual blocks of an array
581 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
582 ASSERT(blockNode);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400583
584 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
585 ASSERT(constantUnion);
586
Jamie Madilla6f267f2014-08-27 11:44:15 -0400587 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
Jamie Madilla2fbb842014-09-03 09:40:47 -0400588 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400589 ASSERT(namedBlock);
590 namedBlock->staticUse = true;
591
592 unsigned int fieldIndex = constantUnion->getUConst(0);
593 ASSERT(fieldIndex < namedBlock->fields.size());
594 namedBlock->fields[fieldIndex].staticUse = true;
595 return false;
596 }
597
598 return true;
599}
600
Olli Etuaho19515012017-06-26 18:00:17 +0300601} // anonymous namespace
602
603void CollectVariables(TIntermBlock *root,
604 std::vector<Attribute> *attributes,
605 std::vector<OutputVariable> *outputVariables,
606 std::vector<Uniform> *uniforms,
607 std::vector<Varying> *varyings,
608 std::vector<InterfaceBlock> *interfaceBlocks,
609 ShHashFunction64 hashFunction,
610 const TSymbolTable &symbolTable,
611 int shaderVersion,
612 const TExtensionBehavior &extensionBehavior)
613{
614 CollectVariablesTraverser collect(attributes, outputVariables, uniforms, varyings,
615 interfaceBlocks, hashFunction, symbolTable, shaderVersion,
616 extensionBehavior);
617 root->traverse(&collect);
618}
619
Corentin Walleze58e1412016-07-18 16:40:46 -0400620void ExpandVariable(const ShaderVariable &variable,
621 const std::string &name,
622 const std::string &mappedName,
623 bool markStaticUse,
624 std::vector<ShaderVariable> *expanded)
625{
626 if (variable.isStruct())
627 {
628 if (variable.isArray())
629 {
630 for (unsigned int elementIndex = 0; elementIndex < variable.elementCount();
631 elementIndex++)
632 {
633 std::string lname = name + ::ArrayString(elementIndex);
634 std::string lmappedName = mappedName + ::ArrayString(elementIndex);
635 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
636 }
637 }
638 else
639 {
640 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
641 }
642 }
643 else
644 {
645 ShaderVariable expandedVar = variable;
646
647 expandedVar.name = name;
648 expandedVar.mappedName = mappedName;
649
650 // Mark all expanded fields as used if the parent is used
651 if (markStaticUse)
652 {
653 expandedVar.staticUse = true;
654 }
655
656 if (expandedVar.isArray())
657 {
658 expandedVar.name += "[0]";
659 expandedVar.mappedName += "[0]";
660 }
661
662 expanded->push_back(expandedVar);
663 }
664}
665
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500666void ExpandUniforms(const std::vector<Uniform> &compact, std::vector<ShaderVariable> *expanded)
Jamie Madill23a8a432014-07-09 13:27:42 -0400667{
Olli Etuaho19515012017-06-26 18:00:17 +0300668 for (const Uniform &variable : compact)
Jamie Madill23a8a432014-07-09 13:27:42 -0400669 {
Jamie Madill23a8a432014-07-09 13:27:42 -0400670 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
671 }
672}
Olli Etuaho19515012017-06-26 18:00:17 +0300673
674} // namespace sh