blob: 83eba117545667fef1a5074f31f5d7d2e359878e [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 Etuahocccf2b02017-07-05 14:50:54 +030011#include "compiler/translator/HashNames.h"
12#include "compiler/translator/IntermTraverse.h"
Olli Etuaho19515012017-06-26 18:00:17 +030013#include "compiler/translator/SymbolTable.h"
14#include "compiler/translator/util.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000015
Jamie Madilla2fbb842014-09-03 09:40:47 -040016namespace sh
17{
18
Jamie Madill54ad4f82014-09-03 09:40:46 -040019namespace
20{
Zhenyao Mod2d340b2013-09-23 14:57:05 -040021
Jamie Madilla2fbb842014-09-03 09:40:47 -040022BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
Jamie Madill54ad4f82014-09-03 09:40:46 -040023{
24 switch (blockStorage)
25 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050026 case EbsPacked:
27 return BLOCKLAYOUT_PACKED;
28 case EbsShared:
29 return BLOCKLAYOUT_SHARED;
30 case EbsStd140:
31 return BLOCKLAYOUT_STANDARD;
32 default:
33 UNREACHABLE();
34 return BLOCKLAYOUT_SHARED;
Jamie Madill54ad4f82014-09-03 09:40:46 -040035 }
36}
37
Jamie Madilla2fbb842014-09-03 09:40:47 -040038void ExpandUserDefinedVariable(const ShaderVariable &variable,
Jamie Madill54ad4f82014-09-03 09:40:46 -040039 const std::string &name,
40 const std::string &mappedName,
41 bool markStaticUse,
Jamie Madilla2fbb842014-09-03 09:40:47 -040042 std::vector<ShaderVariable> *expanded)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000043{
Jamie Madill23a8a432014-07-09 13:27:42 -040044 ASSERT(variable.isStruct());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000045
Jamie Madilla2fbb842014-09-03 09:40:47 -040046 const std::vector<ShaderVariable> &fields = variable.fields;
Jamie Madill23a8a432014-07-09 13:27:42 -040047
48 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill4667c452014-07-08 15:02:36 -040049 {
Jamie Madilla2fbb842014-09-03 09:40:47 -040050 const ShaderVariable &field = fields[fieldIndex];
Jamie Madilld7b1ab52016-12-12 14:42:19 -050051 ExpandVariable(field, name + "." + field.name, mappedName + "." + field.mappedName,
52 markStaticUse, expanded);
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000053 }
54}
55
Jamie Madilla718c1e2014-07-02 15:31:22 -040056template <class VarT>
Jamie Madilld7b1ab52016-12-12 14:42:19 -050057VarT *FindVariable(const TString &name, std::vector<VarT> *infoList)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040058{
59 // TODO(zmo): optimize this function.
Jamie Madilla718c1e2014-07-02 15:31:22 -040060 for (size_t ii = 0; ii < infoList->size(); ++ii)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040061 {
Jamie Madill23a8a432014-07-09 13:27:42 -040062 if ((*infoList)[ii].name.c_str() == name)
Jamie Madilla718c1e2014-07-02 15:31:22 -040063 return &((*infoList)[ii]);
Zhenyao Mod2d340b2013-09-23 14:57:05 -040064 }
Jamie Madilld5512cd2014-07-10 17:50:08 -040065
Yunchao Hef81ce4a2017-04-24 10:49:17 +080066 return nullptr;
Zhenyao Mod2d340b2013-09-23 14:57:05 -040067}
Jamie Madill54ad4f82014-09-03 09:40:46 -040068
Olli Etuaho19515012017-06-26 18:00:17 +030069// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
70// and interface blocks.
71class CollectVariablesTraverser : public TIntermTraverser
72{
73 public:
74 CollectVariablesTraverser(std::vector<Attribute> *attribs,
75 std::vector<OutputVariable> *outputVariables,
76 std::vector<Uniform> *uniforms,
77 std::vector<Varying> *varyings,
78 std::vector<InterfaceBlock> *interfaceBlocks,
79 ShHashFunction64 hashFunction,
80 const TSymbolTable &symbolTable,
81 int shaderVersion,
82 const TExtensionBehavior &extensionBehavior);
83
84 void visitSymbol(TIntermSymbol *symbol) override;
85 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
86 bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
87
88 private:
89 void setCommonVariableProperties(const TType &type,
90 const TString &name,
91 ShaderVariable *variableOut) const;
92
93 Attribute recordAttribute(const TIntermSymbol &variable) const;
94 OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
95 Varying recordVarying(const TIntermSymbol &variable) const;
96 InterfaceBlock recordInterfaceBlock(const TIntermSymbol &variable) const;
97 Uniform recordUniform(const TIntermSymbol &variable) const;
98
99 void setBuiltInInfoFromSymbolTable(const char *name, ShaderVariable *info);
100
101 void recordBuiltInVaryingUsed(const char *name, bool *addedFlag);
102 void recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag);
103 void recordBuiltInAttributeUsed(const char *name, bool *addedFlag);
104
105 std::vector<Attribute> *mAttribs;
106 std::vector<OutputVariable> *mOutputVariables;
107 std::vector<Uniform> *mUniforms;
108 std::vector<Varying> *mVaryings;
109 std::vector<InterfaceBlock> *mInterfaceBlocks;
110
111 std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
112
113 bool mDepthRangeAdded;
114 bool mPointCoordAdded;
115 bool mFrontFacingAdded;
116 bool mFragCoordAdded;
117
118 bool mInstanceIDAdded;
119 bool mVertexIDAdded;
120 bool mPositionAdded;
121 bool mPointSizeAdded;
122 bool mLastFragDataAdded;
123 bool mFragColorAdded;
124 bool mFragDataAdded;
125 bool mFragDepthEXTAdded;
126 bool mFragDepthAdded;
127 bool mSecondaryFragColorEXTAdded;
128 bool mSecondaryFragDataEXTAdded;
129
130 ShHashFunction64 mHashFunction;
131
132 const TSymbolTable &mSymbolTable;
133 int mShaderVersion;
134 const TExtensionBehavior &mExtensionBehavior;
135};
136
137CollectVariablesTraverser::CollectVariablesTraverser(
138 std::vector<sh::Attribute> *attribs,
139 std::vector<sh::OutputVariable> *outputVariables,
140 std::vector<sh::Uniform> *uniforms,
141 std::vector<sh::Varying> *varyings,
142 std::vector<sh::InterfaceBlock> *interfaceBlocks,
143 ShHashFunction64 hashFunction,
144 const TSymbolTable &symbolTable,
145 int shaderVersion,
146 const TExtensionBehavior &extensionBehavior)
Olli Etuaho3d0d9a42015-06-01 12:16:36 +0300147 : TIntermTraverser(true, false, false),
148 mAttribs(attribs),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400149 mOutputVariables(outputVariables),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000150 mUniforms(uniforms),
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400151 mVaryings(varyings),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400152 mInterfaceBlocks(interfaceBlocks),
Jamie Madill55def582015-05-04 11:24:57 -0400153 mDepthRangeAdded(false),
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400154 mPointCoordAdded(false),
155 mFrontFacingAdded(false),
156 mFragCoordAdded(false),
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000157 mInstanceIDAdded(false),
Corentin Wallezb076add2016-01-11 16:45:46 -0500158 mVertexIDAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700159 mPositionAdded(false),
160 mPointSizeAdded(false),
Erik Dahlströmea7a2122014-11-17 16:15:57 +0100161 mLastFragDataAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300162 mFragColorAdded(false),
163 mFragDataAdded(false),
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300164 mFragDepthEXTAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300165 mFragDepthAdded(false),
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +0300166 mSecondaryFragColorEXTAdded(false),
167 mSecondaryFragDataEXTAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700168 mHashFunction(hashFunction),
Zhenyao Mof178d0b2016-07-23 06:59:00 -0700169 mSymbolTable(symbolTable),
Olli Etuaho19515012017-06-26 18:00:17 +0300170 mShaderVersion(shaderVersion),
Zhenyao Mof178d0b2016-07-23 06:59:00 -0700171 mExtensionBehavior(extensionBehavior)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000172{
173}
174
Olli Etuaho19515012017-06-26 18:00:17 +0300175void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
176 ShaderVariable *info)
177{
178 TVariable *symbolTableVar =
179 reinterpret_cast<TVariable *>(mSymbolTable.findBuiltIn(name, mShaderVersion));
180 ASSERT(symbolTableVar);
181 const TType &type = symbolTableVar->getType();
182
183 info->name = name;
184 info->mappedName = name;
185 info->type = GLVariableType(type);
186 info->arraySize = type.isArray() ? type.getArraySize() : 0;
187 info->precision = GLVariablePrecision(type);
188}
189
190void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name, bool *addedFlag)
191{
192 if (!(*addedFlag))
193 {
194 Varying info;
195 setBuiltInInfoFromSymbolTable(name, &info);
196 info.staticUse = true;
197 info.isInvariant = mSymbolTable.isVaryingInvariant(name);
198 mVaryings->push_back(info);
199 (*addedFlag) = true;
200 }
201}
202
203void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag)
204{
205 if (!(*addedFlag))
206 {
207 OutputVariable info;
208 setBuiltInInfoFromSymbolTable(name, &info);
209 info.staticUse = true;
210 mOutputVariables->push_back(info);
211 (*addedFlag) = true;
212 }
213}
214
215void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag)
216{
217 if (!(*addedFlag))
218 {
219 Attribute info;
220 setBuiltInInfoFromSymbolTable(name, &info);
221 info.staticUse = true;
222 info.location = -1;
223 mAttribs->push_back(info);
224 (*addedFlag) = true;
225 }
226}
227
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400228// We want to check whether a uniform/varying is statically used
229// because we only count the used ones in packing computing.
230// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
231// toward varying counting if they are statically used in a fragment
232// shader.
Olli Etuaho19515012017-06-26 18:00:17 +0300233void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000234{
Yunchao He4f285442017-04-21 12:15:49 +0800235 ASSERT(symbol != nullptr);
Yunchao Hed7297bf2017-04-19 15:27:10 +0800236 ShaderVariable *var = nullptr;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400237 const TString &symbolName = symbol->getSymbol();
Jamie Madill4667c452014-07-08 15:02:36 -0400238
Jamie Madilla2fbb842014-09-03 09:40:47 -0400239 if (IsVarying(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400240 {
Jamie Madilld5512cd2014-07-10 17:50:08 -0400241 var = FindVariable(symbolName, mVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400242 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400243 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
244 {
245 UNREACHABLE();
246 }
Jamie Madill55def582015-05-04 11:24:57 -0400247 else if (symbolName == "gl_DepthRange")
248 {
249 ASSERT(symbol->getQualifier() == EvqUniform);
250
251 if (!mDepthRangeAdded)
252 {
253 Uniform info;
254 const char kName[] = "gl_DepthRange";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500255 info.name = kName;
256 info.mappedName = kName;
257 info.type = GL_STRUCT_ANGLEX;
258 info.arraySize = 0;
259 info.precision = GL_NONE;
260 info.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400261
262 ShaderVariable nearInfo;
263 const char kNearName[] = "near";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500264 nearInfo.name = kNearName;
265 nearInfo.mappedName = kNearName;
266 nearInfo.type = GL_FLOAT;
267 nearInfo.arraySize = 0;
268 nearInfo.precision = GL_HIGH_FLOAT;
269 nearInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400270
271 ShaderVariable farInfo;
272 const char kFarName[] = "far";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500273 farInfo.name = kFarName;
274 farInfo.mappedName = kFarName;
275 farInfo.type = GL_FLOAT;
276 farInfo.arraySize = 0;
277 farInfo.precision = GL_HIGH_FLOAT;
278 farInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400279
280 ShaderVariable diffInfo;
281 const char kDiffName[] = "diff";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500282 diffInfo.name = kDiffName;
283 diffInfo.mappedName = kDiffName;
284 diffInfo.type = GL_FLOAT;
285 diffInfo.arraySize = 0;
286 diffInfo.precision = GL_HIGH_FLOAT;
287 diffInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400288
289 info.fields.push_back(nearInfo);
290 info.fields.push_back(farInfo);
291 info.fields.push_back(diffInfo);
292
293 mUniforms->push_back(info);
294 mDepthRangeAdded = true;
295 }
296 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400297 else
Jamie Madill4667c452014-07-08 15:02:36 -0400298 {
299 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400300 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500301 case EvqAttribute:
302 case EvqVertexIn:
303 var = FindVariable(symbolName, mAttribs);
304 break;
305 case EvqFragmentOut:
306 var = FindVariable(symbolName, mOutputVariables);
307 break;
308 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400309 {
310 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
311 if (interfaceBlock)
312 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500313 InterfaceBlock *namedBlock =
314 FindVariable(interfaceBlock->name(), mInterfaceBlocks);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400315 ASSERT(namedBlock);
316 var = FindVariable(symbolName, &namedBlock->fields);
317
318 // Set static use on the parent interface block here
319 namedBlock->staticUse = true;
320 }
321 else
322 {
323 var = FindVariable(symbolName, mUniforms);
324 }
325
326 // It's an internal error to reference an undefined user uniform
Jamie Madill55def582015-05-04 11:24:57 -0400327 ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400328 }
Jamie Madill4667c452014-07-08 15:02:36 -0400329 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500330 case EvqFragCoord:
Olli Etuaho19515012017-06-26 18:00:17 +0300331 recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500332 return;
333 case EvqFrontFacing:
Olli Etuaho19515012017-06-26 18:00:17 +0300334 recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500335 return;
336 case EvqPointCoord:
Olli Etuaho19515012017-06-26 18:00:17 +0300337 recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500338 return;
339 case EvqInstanceID:
Martin Radev115fc552017-07-05 17:11:06 +0300340 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
341 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
342 // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders
343 // which makes it necessary to populate the type information explicitly instead of
344 // extracting it from the symbol table.
345 if (!mInstanceIDAdded)
346 {
347 Attribute info;
348 const char kName[] = "gl_InstanceID";
349 info.name = kName;
350 info.mappedName = kName;
351 info.type = GL_INT;
352 info.arraySize = 0;
353 info.precision = GL_HIGH_INT; // Defined by spec.
354 info.staticUse = true;
355 info.location = -1;
356 mAttribs->push_back(info);
357 mInstanceIDAdded = true;
358 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500359 return;
360 case EvqVertexID:
Olli Etuaho19515012017-06-26 18:00:17 +0300361 recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500362 return;
363 case EvqPosition:
Olli Etuaho19515012017-06-26 18:00:17 +0300364 recordBuiltInVaryingUsed("gl_Position", &mPositionAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500365 return;
366 case EvqPointSize:
Olli Etuaho19515012017-06-26 18:00:17 +0300367 recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500368 return;
369 case EvqLastFragData:
Olli Etuaho19515012017-06-26 18:00:17 +0300370 recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500371 return;
372 case EvqFragColor:
Olli Etuaho19515012017-06-26 18:00:17 +0300373 recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500374 return;
375 case EvqFragData:
376 if (!mFragDataAdded)
377 {
378 OutputVariable info;
Olli Etuaho19515012017-06-26 18:00:17 +0300379 setBuiltInInfoFromSymbolTable("gl_FragData", &info);
380 if (!::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500381 {
382 info.arraySize = 1;
383 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500384 info.staticUse = true;
385 mOutputVariables->push_back(info);
386 mFragDataAdded = true;
387 }
388 return;
389 case EvqFragDepthEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300390 recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500391 return;
392 case EvqFragDepth:
Olli Etuaho19515012017-06-26 18:00:17 +0300393 recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500394 return;
395 case EvqSecondaryFragColorEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300396 recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT",
397 &mSecondaryFragColorEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500398 return;
399 case EvqSecondaryFragDataEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300400 recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
401 &mSecondaryFragDataEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500402 return;
403 default:
404 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400405 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400406 }
407 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400408 {
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400409 var->staticUse = true;
Jamie Madilla718c1e2014-07-02 15:31:22 -0400410 }
411}
412
Olli Etuaho19515012017-06-26 18:00:17 +0300413void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
414 const TString &name,
415 ShaderVariable *variableOut) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400416{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000417 ASSERT(variableOut);
418
419 const TStructure *structure = type.getStruct();
420
421 if (!structure)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500422 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000423 variableOut->type = GLVariableType(type);
424 variableOut->precision = GLVariablePrecision(type);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500425 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000426 else
Jamie Madill23a8a432014-07-09 13:27:42 -0400427 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000428 // Note: this enum value is not exposed outside ANGLE
429 variableOut->type = GL_STRUCT_ANGLEX;
430 variableOut->structName = structure->name().c_str();
431
432 const TFieldList &fields = structure->fields();
433
434 for (TField *field : fields)
435 {
436 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
437 // ShaderVariable objects.
438 ShaderVariable fieldVariable;
439 setCommonVariableProperties(*field->type(), field->name(), &fieldVariable);
440 variableOut->fields.push_back(fieldVariable);
441 }
Jamie Madill23a8a432014-07-09 13:27:42 -0400442 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000443 variableOut->name = name.c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300444 variableOut->mappedName = HashName(name, mHashFunction).c_str();
Olli Etuahoa55102c2017-02-24 12:36:50 +0000445 variableOut->arraySize = type.getArraySize();
446}
Jamie Madill23a8a432014-07-09 13:27:42 -0400447
Olli Etuaho19515012017-06-26 18:00:17 +0300448Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400449{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000450 const TType &type = variable.getType();
Jamie Madill23a8a432014-07-09 13:27:42 -0400451 ASSERT(!type.getStruct());
452
Jamie Madilla2fbb842014-09-03 09:40:47 -0400453 Attribute attribute;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000454 setCommonVariableProperties(type, variable.getSymbol(), &attribute);
Jamie Madill23a8a432014-07-09 13:27:42 -0400455
Olli Etuahoa55102c2017-02-24 12:36:50 +0000456 attribute.location = type.getLayoutQualifier().location;
457 return attribute;
Jamie Madill23a8a432014-07-09 13:27:42 -0400458}
459
Olli Etuaho19515012017-06-26 18:00:17 +0300460OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
Jamie Madilla0a9e122015-09-02 15:54:30 -0400461{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000462 const TType &type = variable.getType();
Jamie Madilla0a9e122015-09-02 15:54:30 -0400463 ASSERT(!type.getStruct());
464
Olli Etuahoa55102c2017-02-24 12:36:50 +0000465 OutputVariable outputVariable;
466 setCommonVariableProperties(type, variable.getSymbol(), &outputVariable);
Jamie Madilla0a9e122015-09-02 15:54:30 -0400467
Olli Etuahoa55102c2017-02-24 12:36:50 +0000468 outputVariable.location = type.getLayoutQualifier().location;
469 return outputVariable;
Jamie Madilla0a9e122015-09-02 15:54:30 -0400470}
471
Olli Etuaho19515012017-06-26 18:00:17 +0300472Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
Jamie Madilld5512cd2014-07-10 17:50:08 -0400473{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000474 const TType &type = variable.getType();
475
476 Varying varying;
477 setCommonVariableProperties(type, variable.getSymbol(), &varying);
478
479 switch (type.getQualifier())
480 {
481 case EvqVaryingIn:
482 case EvqVaryingOut:
483 case EvqVertexOut:
484 case EvqSmoothOut:
485 case EvqFlatOut:
486 case EvqCentroidOut:
487 if (mSymbolTable.isVaryingInvariant(std::string(variable.getSymbol().c_str())) ||
488 type.isInvariant())
489 {
490 varying.isInvariant = true;
491 }
492 break;
493 default:
494 break;
495 }
496
497 varying.interpolation = GetInterpolationType(type.getQualifier());
498 return varying;
499}
500
Olli Etuaho19515012017-06-26 18:00:17 +0300501InterfaceBlock CollectVariablesTraverser::recordInterfaceBlock(const TIntermSymbol &variable) const
Olli Etuahoa55102c2017-02-24 12:36:50 +0000502{
503 const TInterfaceBlock *blockType = variable.getType().getInterfaceBlock();
Jamie Madill42bcf322014-08-25 16:20:46 -0400504 ASSERT(blockType);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400505
Olli Etuahoa55102c2017-02-24 12:36:50 +0000506 InterfaceBlock interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400507 interfaceBlock.name = blockType->name().c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300508 interfaceBlock.mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500509 interfaceBlock.instanceName =
510 (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
Olli Etuahoa55102c2017-02-24 12:36:50 +0000511 interfaceBlock.arraySize = variable.getArraySize();
Jamie Madill42bcf322014-08-25 16:20:46 -0400512 interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
jchen10af713a22017-04-19 09:10:56 +0800513 interfaceBlock.binding = blockType->blockBinding();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500514 interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
Jamie Madilld5512cd2014-07-10 17:50:08 -0400515
Jamie Madilla6f267f2014-08-27 11:44:15 -0400516 // Gather field information
Jamie Madill39046162016-02-08 15:05:17 -0500517 for (const TField *field : blockType->fields())
Jamie Madill54ad4f82014-09-03 09:40:46 -0400518 {
Jamie Madill39046162016-02-08 15:05:17 -0500519 const TType &fieldType = *field->type();
Jamie Madill54ad4f82014-09-03 09:40:46 -0400520
Olli Etuahoa55102c2017-02-24 12:36:50 +0000521 InterfaceBlockField fieldVariable;
522 setCommonVariableProperties(fieldType, field->name(), &fieldVariable);
523 fieldVariable.isRowMajorLayout =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500524 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
Olli Etuahoa55102c2017-02-24 12:36:50 +0000525 interfaceBlock.fields.push_back(fieldVariable);
Jamie Madill54ad4f82014-09-03 09:40:46 -0400526 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000527 return interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400528}
529
Olli Etuaho19515012017-06-26 18:00:17 +0300530Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
Jamie Madill4667c452014-07-08 15:02:36 -0400531{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000532 Uniform uniform;
533 setCommonVariableProperties(variable.getType(), variable.getSymbol(), &uniform);
Olli Etuaho547cbd42017-02-27 11:54:00 +0200534 uniform.binding = variable.getType().getLayoutQualifier().binding;
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000535 uniform.location = variable.getType().getLayoutQualifier().location;
jchen104cdac9e2017-05-08 11:01:20 +0800536 uniform.offset = variable.getType().getLayoutQualifier().offset;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000537 return uniform;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000538}
539
Olli Etuaho19515012017-06-26 18:00:17 +0300540bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000541{
Olli Etuaho13389b62016-10-16 11:48:18 +0100542 const TIntermSequence &sequence = *(node->getSequence());
543 ASSERT(!sequence.empty());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000544
Olli Etuaho13389b62016-10-16 11:48:18 +0100545 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
546 TQualifier qualifier = typedNode.getQualifier();
547
Olli Etuahoa55102c2017-02-24 12:36:50 +0000548 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
549 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
550 IsVarying(qualifier);
551
552 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000553 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000554 return true;
Olli Etuaho13389b62016-10-16 11:48:18 +0100555 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000556
557 for (TIntermNode *variableNode : sequence)
Olli Etuaho13389b62016-10-16 11:48:18 +0100558 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000559 // The only case in which the sequence will not contain a TIntermSymbol node is
560 // initialization. It will contain a TInterBinary node in that case. Since attributes,
561 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
562 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
563 const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
564 if (typedNode.getBasicType() == EbtInterfaceBlock)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000565 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000566 mInterfaceBlocks->push_back(recordInterfaceBlock(variable));
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000567 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000568 else
569 {
570 switch (qualifier)
571 {
572 case EvqAttribute:
573 case EvqVertexIn:
574 mAttribs->push_back(recordAttribute(variable));
575 break;
576 case EvqFragmentOut:
577 mOutputVariables->push_back(recordOutputVariable(variable));
578 break;
579 case EvqUniform:
580 mUniforms->push_back(recordUniform(variable));
581 break;
582 default:
583 mVaryings->push_back(recordVarying(variable));
584 break;
585 }
586 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000587 }
588
Olli Etuahoa55102c2017-02-24 12:36:50 +0000589 // None of the recorded variables can have initializers, so we don't need to traverse the
590 // declarators.
591 return false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000592}
Jamie Madill23a8a432014-07-09 13:27:42 -0400593
Olli Etuaho19515012017-06-26 18:00:17 +0300594bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
Jamie Madillb547ddf2014-08-25 16:20:46 -0400595{
596 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
597 {
Jamie Madilla6f267f2014-08-27 11:44:15 -0400598 // NOTE: we do not determine static use for individual blocks of an array
599 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
600 ASSERT(blockNode);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400601
602 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
603 ASSERT(constantUnion);
604
Jamie Madilla6f267f2014-08-27 11:44:15 -0400605 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
Jamie Madilla2fbb842014-09-03 09:40:47 -0400606 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400607 ASSERT(namedBlock);
608 namedBlock->staticUse = true;
609
Olli Etuaho56229f12017-07-10 14:16:33 +0300610 unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
Jamie Madillb547ddf2014-08-25 16:20:46 -0400611 ASSERT(fieldIndex < namedBlock->fields.size());
612 namedBlock->fields[fieldIndex].staticUse = true;
613 return false;
614 }
615
616 return true;
617}
618
Olli Etuaho19515012017-06-26 18:00:17 +0300619} // anonymous namespace
620
621void CollectVariables(TIntermBlock *root,
622 std::vector<Attribute> *attributes,
623 std::vector<OutputVariable> *outputVariables,
624 std::vector<Uniform> *uniforms,
625 std::vector<Varying> *varyings,
626 std::vector<InterfaceBlock> *interfaceBlocks,
627 ShHashFunction64 hashFunction,
628 const TSymbolTable &symbolTable,
629 int shaderVersion,
630 const TExtensionBehavior &extensionBehavior)
631{
632 CollectVariablesTraverser collect(attributes, outputVariables, uniforms, varyings,
633 interfaceBlocks, hashFunction, symbolTable, shaderVersion,
634 extensionBehavior);
635 root->traverse(&collect);
636}
637
Corentin Walleze58e1412016-07-18 16:40:46 -0400638void ExpandVariable(const ShaderVariable &variable,
639 const std::string &name,
640 const std::string &mappedName,
641 bool markStaticUse,
642 std::vector<ShaderVariable> *expanded)
643{
644 if (variable.isStruct())
645 {
646 if (variable.isArray())
647 {
648 for (unsigned int elementIndex = 0; elementIndex < variable.elementCount();
649 elementIndex++)
650 {
651 std::string lname = name + ::ArrayString(elementIndex);
652 std::string lmappedName = mappedName + ::ArrayString(elementIndex);
653 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
654 }
655 }
656 else
657 {
658 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
659 }
660 }
661 else
662 {
663 ShaderVariable expandedVar = variable;
664
665 expandedVar.name = name;
666 expandedVar.mappedName = mappedName;
667
668 // Mark all expanded fields as used if the parent is used
669 if (markStaticUse)
670 {
671 expandedVar.staticUse = true;
672 }
673
674 if (expandedVar.isArray())
675 {
676 expandedVar.name += "[0]";
677 expandedVar.mappedName += "[0]";
678 }
679
680 expanded->push_back(expandedVar);
681 }
682}
683
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500684void ExpandUniforms(const std::vector<Uniform> &compact, std::vector<ShaderVariable> *expanded)
Jamie Madill23a8a432014-07-09 13:27:42 -0400685{
Olli Etuaho19515012017-06-26 18:00:17 +0300686 for (const Uniform &variable : compact)
Jamie Madill23a8a432014-07-09 13:27:42 -0400687 {
Jamie Madill23a8a432014-07-09 13:27:42 -0400688 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
689 }
690}
Olli Etuaho19515012017-06-26 18:00:17 +0300691
692} // namespace sh