blob: 18178d799897f45185d0e48f9d85d9618f6da14e [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 Etuaho06a06f52017-07-12 12:22:15 +030069// Note that this shouldn't be called for interface blocks - static use information is collected for
70// individual fields in case of interface blocks.
71void MarkStaticallyUsed(ShaderVariable *variable)
72{
73 if (!variable->staticUse)
74 {
75 if (variable->isStruct())
76 {
77 // Conservatively assume all fields are statically used as well.
78 for (auto &field : variable->fields)
79 {
80 MarkStaticallyUsed(&field);
81 }
82 }
83 variable->staticUse = true;
84 }
85}
86
Olli Etuaho19515012017-06-26 18:00:17 +030087// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
88// and interface blocks.
89class CollectVariablesTraverser : public TIntermTraverser
90{
91 public:
92 CollectVariablesTraverser(std::vector<Attribute> *attribs,
93 std::vector<OutputVariable> *outputVariables,
94 std::vector<Uniform> *uniforms,
95 std::vector<Varying> *varyings,
96 std::vector<InterfaceBlock> *interfaceBlocks,
97 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +030098 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +030099 int shaderVersion,
100 const TExtensionBehavior &extensionBehavior);
101
102 void visitSymbol(TIntermSymbol *symbol) override;
103 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
104 bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
105
106 private:
107 void setCommonVariableProperties(const TType &type,
108 const TString &name,
109 ShaderVariable *variableOut) const;
110
111 Attribute recordAttribute(const TIntermSymbol &variable) const;
112 OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
113 Varying recordVarying(const TIntermSymbol &variable) const;
114 InterfaceBlock recordInterfaceBlock(const TIntermSymbol &variable) const;
115 Uniform recordUniform(const TIntermSymbol &variable) const;
116
117 void setBuiltInInfoFromSymbolTable(const char *name, ShaderVariable *info);
118
119 void recordBuiltInVaryingUsed(const char *name, bool *addedFlag);
120 void recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag);
121 void recordBuiltInAttributeUsed(const char *name, bool *addedFlag);
122
123 std::vector<Attribute> *mAttribs;
124 std::vector<OutputVariable> *mOutputVariables;
125 std::vector<Uniform> *mUniforms;
126 std::vector<Varying> *mVaryings;
127 std::vector<InterfaceBlock> *mInterfaceBlocks;
128
129 std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
130
131 bool mDepthRangeAdded;
132 bool mPointCoordAdded;
133 bool mFrontFacingAdded;
134 bool mFragCoordAdded;
135
136 bool mInstanceIDAdded;
137 bool mVertexIDAdded;
138 bool mPositionAdded;
139 bool mPointSizeAdded;
140 bool mLastFragDataAdded;
141 bool mFragColorAdded;
142 bool mFragDataAdded;
143 bool mFragDepthEXTAdded;
144 bool mFragDepthAdded;
145 bool mSecondaryFragColorEXTAdded;
146 bool mSecondaryFragDataEXTAdded;
147
148 ShHashFunction64 mHashFunction;
149
Olli Etuaho19515012017-06-26 18:00:17 +0300150 int mShaderVersion;
151 const TExtensionBehavior &mExtensionBehavior;
152};
153
154CollectVariablesTraverser::CollectVariablesTraverser(
155 std::vector<sh::Attribute> *attribs,
156 std::vector<sh::OutputVariable> *outputVariables,
157 std::vector<sh::Uniform> *uniforms,
158 std::vector<sh::Varying> *varyings,
159 std::vector<sh::InterfaceBlock> *interfaceBlocks,
160 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300161 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300162 int shaderVersion,
163 const TExtensionBehavior &extensionBehavior)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300164 : TIntermTraverser(true, false, false, symbolTable),
Olli Etuaho3d0d9a42015-06-01 12:16:36 +0300165 mAttribs(attribs),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400166 mOutputVariables(outputVariables),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000167 mUniforms(uniforms),
Zhenyao Mo74da9f22013-09-23 14:57:01 -0400168 mVaryings(varyings),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400169 mInterfaceBlocks(interfaceBlocks),
Jamie Madill55def582015-05-04 11:24:57 -0400170 mDepthRangeAdded(false),
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400171 mPointCoordAdded(false),
172 mFrontFacingAdded(false),
173 mFragCoordAdded(false),
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000174 mInstanceIDAdded(false),
Corentin Wallezb076add2016-01-11 16:45:46 -0500175 mVertexIDAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700176 mPositionAdded(false),
177 mPointSizeAdded(false),
Erik Dahlströmea7a2122014-11-17 16:15:57 +0100178 mLastFragDataAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300179 mFragColorAdded(false),
180 mFragDataAdded(false),
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300181 mFragDepthEXTAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300182 mFragDepthAdded(false),
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +0300183 mSecondaryFragColorEXTAdded(false),
184 mSecondaryFragDataEXTAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700185 mHashFunction(hashFunction),
Olli Etuaho19515012017-06-26 18:00:17 +0300186 mShaderVersion(shaderVersion),
Zhenyao Mof178d0b2016-07-23 06:59:00 -0700187 mExtensionBehavior(extensionBehavior)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000188{
189}
190
Olli Etuaho19515012017-06-26 18:00:17 +0300191void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
192 ShaderVariable *info)
193{
194 TVariable *symbolTableVar =
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300195 reinterpret_cast<TVariable *>(mSymbolTable->findBuiltIn(name, mShaderVersion));
Olli Etuaho19515012017-06-26 18:00:17 +0300196 ASSERT(symbolTableVar);
197 const TType &type = symbolTableVar->getType();
198
199 info->name = name;
200 info->mappedName = name;
201 info->type = GLVariableType(type);
202 info->arraySize = type.isArray() ? type.getArraySize() : 0;
203 info->precision = GLVariablePrecision(type);
204}
205
206void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name, bool *addedFlag)
207{
208 if (!(*addedFlag))
209 {
210 Varying info;
211 setBuiltInInfoFromSymbolTable(name, &info);
212 info.staticUse = true;
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300213 info.isInvariant = mSymbolTable->isVaryingInvariant(name);
Olli Etuaho19515012017-06-26 18:00:17 +0300214 mVaryings->push_back(info);
215 (*addedFlag) = true;
216 }
217}
218
219void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag)
220{
221 if (!(*addedFlag))
222 {
223 OutputVariable info;
224 setBuiltInInfoFromSymbolTable(name, &info);
225 info.staticUse = true;
226 mOutputVariables->push_back(info);
227 (*addedFlag) = true;
228 }
229}
230
231void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag)
232{
233 if (!(*addedFlag))
234 {
235 Attribute info;
236 setBuiltInInfoFromSymbolTable(name, &info);
237 info.staticUse = true;
238 info.location = -1;
239 mAttribs->push_back(info);
240 (*addedFlag) = true;
241 }
242}
243
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400244// We want to check whether a uniform/varying is statically used
245// because we only count the used ones in packing computing.
246// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
247// toward varying counting if they are statically used in a fragment
248// shader.
Olli Etuaho19515012017-06-26 18:00:17 +0300249void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000250{
Yunchao He4f285442017-04-21 12:15:49 +0800251 ASSERT(symbol != nullptr);
Olli Etuaho34d20072017-07-18 20:07:18 +0300252
253 if (symbol->getName().isInternal())
254 {
255 // Internal variables are not collected.
256 return;
257 }
258
Yunchao Hed7297bf2017-04-19 15:27:10 +0800259 ShaderVariable *var = nullptr;
Olli Etuaho34d20072017-07-18 20:07:18 +0300260 const TString &symbolName = symbol->getName().getString();
Jamie Madill4667c452014-07-08 15:02:36 -0400261
Jamie Madilla2fbb842014-09-03 09:40:47 -0400262 if (IsVarying(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400263 {
Jamie Madilld5512cd2014-07-10 17:50:08 -0400264 var = FindVariable(symbolName, mVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400265 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400266 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
267 {
268 UNREACHABLE();
269 }
Jamie Madill55def582015-05-04 11:24:57 -0400270 else if (symbolName == "gl_DepthRange")
271 {
272 ASSERT(symbol->getQualifier() == EvqUniform);
273
274 if (!mDepthRangeAdded)
275 {
276 Uniform info;
277 const char kName[] = "gl_DepthRange";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500278 info.name = kName;
279 info.mappedName = kName;
280 info.type = GL_STRUCT_ANGLEX;
281 info.arraySize = 0;
282 info.precision = GL_NONE;
283 info.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400284
285 ShaderVariable nearInfo;
286 const char kNearName[] = "near";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500287 nearInfo.name = kNearName;
288 nearInfo.mappedName = kNearName;
289 nearInfo.type = GL_FLOAT;
290 nearInfo.arraySize = 0;
291 nearInfo.precision = GL_HIGH_FLOAT;
292 nearInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400293
294 ShaderVariable farInfo;
295 const char kFarName[] = "far";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500296 farInfo.name = kFarName;
297 farInfo.mappedName = kFarName;
298 farInfo.type = GL_FLOAT;
299 farInfo.arraySize = 0;
300 farInfo.precision = GL_HIGH_FLOAT;
301 farInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400302
303 ShaderVariable diffInfo;
304 const char kDiffName[] = "diff";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500305 diffInfo.name = kDiffName;
306 diffInfo.mappedName = kDiffName;
307 diffInfo.type = GL_FLOAT;
308 diffInfo.arraySize = 0;
309 diffInfo.precision = GL_HIGH_FLOAT;
310 diffInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400311
312 info.fields.push_back(nearInfo);
313 info.fields.push_back(farInfo);
314 info.fields.push_back(diffInfo);
315
316 mUniforms->push_back(info);
317 mDepthRangeAdded = true;
318 }
319 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400320 else
Jamie Madill4667c452014-07-08 15:02:36 -0400321 {
322 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400323 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500324 case EvqAttribute:
325 case EvqVertexIn:
326 var = FindVariable(symbolName, mAttribs);
327 break;
328 case EvqFragmentOut:
329 var = FindVariable(symbolName, mOutputVariables);
330 break;
331 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400332 {
333 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
334 if (interfaceBlock)
335 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500336 InterfaceBlock *namedBlock =
337 FindVariable(interfaceBlock->name(), mInterfaceBlocks);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400338 ASSERT(namedBlock);
339 var = FindVariable(symbolName, &namedBlock->fields);
340
341 // Set static use on the parent interface block here
342 namedBlock->staticUse = true;
343 }
344 else
345 {
346 var = FindVariable(symbolName, mUniforms);
347 }
348
349 // It's an internal error to reference an undefined user uniform
Jamie Madill55def582015-05-04 11:24:57 -0400350 ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400351 }
Jamie Madill4667c452014-07-08 15:02:36 -0400352 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500353 case EvqFragCoord:
Olli Etuaho19515012017-06-26 18:00:17 +0300354 recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500355 return;
356 case EvqFrontFacing:
Olli Etuaho19515012017-06-26 18:00:17 +0300357 recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500358 return;
359 case EvqPointCoord:
Olli Etuaho19515012017-06-26 18:00:17 +0300360 recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500361 return;
362 case EvqInstanceID:
Martin Radev115fc552017-07-05 17:11:06 +0300363 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
364 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
365 // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders
366 // which makes it necessary to populate the type information explicitly instead of
367 // extracting it from the symbol table.
368 if (!mInstanceIDAdded)
369 {
370 Attribute info;
371 const char kName[] = "gl_InstanceID";
372 info.name = kName;
373 info.mappedName = kName;
374 info.type = GL_INT;
375 info.arraySize = 0;
376 info.precision = GL_HIGH_INT; // Defined by spec.
377 info.staticUse = true;
378 info.location = -1;
379 mAttribs->push_back(info);
380 mInstanceIDAdded = true;
381 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500382 return;
383 case EvqVertexID:
Olli Etuaho19515012017-06-26 18:00:17 +0300384 recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500385 return;
386 case EvqPosition:
Olli Etuaho19515012017-06-26 18:00:17 +0300387 recordBuiltInVaryingUsed("gl_Position", &mPositionAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500388 return;
389 case EvqPointSize:
Olli Etuaho19515012017-06-26 18:00:17 +0300390 recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500391 return;
392 case EvqLastFragData:
Olli Etuaho19515012017-06-26 18:00:17 +0300393 recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500394 return;
395 case EvqFragColor:
Olli Etuaho19515012017-06-26 18:00:17 +0300396 recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500397 return;
398 case EvqFragData:
399 if (!mFragDataAdded)
400 {
401 OutputVariable info;
Olli Etuaho19515012017-06-26 18:00:17 +0300402 setBuiltInInfoFromSymbolTable("gl_FragData", &info);
403 if (!::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500404 {
405 info.arraySize = 1;
406 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500407 info.staticUse = true;
408 mOutputVariables->push_back(info);
409 mFragDataAdded = true;
410 }
411 return;
412 case EvqFragDepthEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300413 recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500414 return;
415 case EvqFragDepth:
Olli Etuaho19515012017-06-26 18:00:17 +0300416 recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500417 return;
418 case EvqSecondaryFragColorEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300419 recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT",
420 &mSecondaryFragColorEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500421 return;
422 case EvqSecondaryFragDataEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300423 recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
424 &mSecondaryFragDataEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500425 return;
426 default:
427 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400428 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400429 }
430 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400431 {
Olli Etuaho06a06f52017-07-12 12:22:15 +0300432 MarkStaticallyUsed(var);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400433 }
434}
435
Olli Etuaho19515012017-06-26 18:00:17 +0300436void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
437 const TString &name,
438 ShaderVariable *variableOut) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400439{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000440 ASSERT(variableOut);
441
442 const TStructure *structure = type.getStruct();
443
444 if (!structure)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500445 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000446 variableOut->type = GLVariableType(type);
447 variableOut->precision = GLVariablePrecision(type);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500448 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000449 else
Jamie Madill23a8a432014-07-09 13:27:42 -0400450 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000451 // Note: this enum value is not exposed outside ANGLE
452 variableOut->type = GL_STRUCT_ANGLEX;
453 variableOut->structName = structure->name().c_str();
454
455 const TFieldList &fields = structure->fields();
456
457 for (TField *field : fields)
458 {
459 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
460 // ShaderVariable objects.
461 ShaderVariable fieldVariable;
462 setCommonVariableProperties(*field->type(), field->name(), &fieldVariable);
463 variableOut->fields.push_back(fieldVariable);
464 }
Jamie Madill23a8a432014-07-09 13:27:42 -0400465 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000466 variableOut->name = name.c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300467 variableOut->mappedName = HashName(name, mHashFunction).c_str();
Olli Etuahoa55102c2017-02-24 12:36:50 +0000468 variableOut->arraySize = type.getArraySize();
469}
Jamie Madill23a8a432014-07-09 13:27:42 -0400470
Olli Etuaho19515012017-06-26 18:00:17 +0300471Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400472{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000473 const TType &type = variable.getType();
Jamie Madill23a8a432014-07-09 13:27:42 -0400474 ASSERT(!type.getStruct());
475
Jamie Madilla2fbb842014-09-03 09:40:47 -0400476 Attribute attribute;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000477 setCommonVariableProperties(type, variable.getSymbol(), &attribute);
Jamie Madill23a8a432014-07-09 13:27:42 -0400478
Olli Etuahoa55102c2017-02-24 12:36:50 +0000479 attribute.location = type.getLayoutQualifier().location;
480 return attribute;
Jamie Madill23a8a432014-07-09 13:27:42 -0400481}
482
Olli Etuaho19515012017-06-26 18:00:17 +0300483OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
Jamie Madilla0a9e122015-09-02 15:54:30 -0400484{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000485 const TType &type = variable.getType();
Jamie Madilla0a9e122015-09-02 15:54:30 -0400486 ASSERT(!type.getStruct());
487
Olli Etuahoa55102c2017-02-24 12:36:50 +0000488 OutputVariable outputVariable;
489 setCommonVariableProperties(type, variable.getSymbol(), &outputVariable);
Jamie Madilla0a9e122015-09-02 15:54:30 -0400490
Olli Etuahoa55102c2017-02-24 12:36:50 +0000491 outputVariable.location = type.getLayoutQualifier().location;
492 return outputVariable;
Jamie Madilla0a9e122015-09-02 15:54:30 -0400493}
494
Olli Etuaho19515012017-06-26 18:00:17 +0300495Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
Jamie Madilld5512cd2014-07-10 17:50:08 -0400496{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000497 const TType &type = variable.getType();
498
499 Varying varying;
500 setCommonVariableProperties(type, variable.getSymbol(), &varying);
501
502 switch (type.getQualifier())
503 {
504 case EvqVaryingIn:
505 case EvqVaryingOut:
506 case EvqVertexOut:
507 case EvqSmoothOut:
508 case EvqFlatOut:
509 case EvqCentroidOut:
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300510 if (mSymbolTable->isVaryingInvariant(std::string(variable.getSymbol().c_str())) ||
Olli Etuahoa55102c2017-02-24 12:36:50 +0000511 type.isInvariant())
512 {
513 varying.isInvariant = true;
514 }
515 break;
516 default:
517 break;
518 }
519
520 varying.interpolation = GetInterpolationType(type.getQualifier());
521 return varying;
522}
523
Olli Etuaho19515012017-06-26 18:00:17 +0300524InterfaceBlock CollectVariablesTraverser::recordInterfaceBlock(const TIntermSymbol &variable) const
Olli Etuahoa55102c2017-02-24 12:36:50 +0000525{
526 const TInterfaceBlock *blockType = variable.getType().getInterfaceBlock();
Jamie Madill42bcf322014-08-25 16:20:46 -0400527 ASSERT(blockType);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400528
Olli Etuahoa55102c2017-02-24 12:36:50 +0000529 InterfaceBlock interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400530 interfaceBlock.name = blockType->name().c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300531 interfaceBlock.mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500532 interfaceBlock.instanceName =
533 (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
Olli Etuahoa55102c2017-02-24 12:36:50 +0000534 interfaceBlock.arraySize = variable.getArraySize();
Jamie Madill42bcf322014-08-25 16:20:46 -0400535 interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
jchen10af713a22017-04-19 09:10:56 +0800536 interfaceBlock.binding = blockType->blockBinding();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500537 interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
Jamie Madilld5512cd2014-07-10 17:50:08 -0400538
Jamie Madilla6f267f2014-08-27 11:44:15 -0400539 // Gather field information
Jamie Madill39046162016-02-08 15:05:17 -0500540 for (const TField *field : blockType->fields())
Jamie Madill54ad4f82014-09-03 09:40:46 -0400541 {
Jamie Madill39046162016-02-08 15:05:17 -0500542 const TType &fieldType = *field->type();
Jamie Madill54ad4f82014-09-03 09:40:46 -0400543
Olli Etuahoa55102c2017-02-24 12:36:50 +0000544 InterfaceBlockField fieldVariable;
545 setCommonVariableProperties(fieldType, field->name(), &fieldVariable);
546 fieldVariable.isRowMajorLayout =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500547 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
Olli Etuahoa55102c2017-02-24 12:36:50 +0000548 interfaceBlock.fields.push_back(fieldVariable);
Jamie Madill54ad4f82014-09-03 09:40:46 -0400549 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000550 return interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400551}
552
Olli Etuaho19515012017-06-26 18:00:17 +0300553Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
Jamie Madill4667c452014-07-08 15:02:36 -0400554{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000555 Uniform uniform;
556 setCommonVariableProperties(variable.getType(), variable.getSymbol(), &uniform);
Olli Etuaho547cbd42017-02-27 11:54:00 +0200557 uniform.binding = variable.getType().getLayoutQualifier().binding;
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000558 uniform.location = variable.getType().getLayoutQualifier().location;
jchen104cdac9e2017-05-08 11:01:20 +0800559 uniform.offset = variable.getType().getLayoutQualifier().offset;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000560 return uniform;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000561}
562
Olli Etuaho19515012017-06-26 18:00:17 +0300563bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000564{
Olli Etuaho13389b62016-10-16 11:48:18 +0100565 const TIntermSequence &sequence = *(node->getSequence());
566 ASSERT(!sequence.empty());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000567
Olli Etuaho13389b62016-10-16 11:48:18 +0100568 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
569 TQualifier qualifier = typedNode.getQualifier();
570
Olli Etuahoa55102c2017-02-24 12:36:50 +0000571 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
572 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
573 IsVarying(qualifier);
574
575 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000576 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000577 return true;
Olli Etuaho13389b62016-10-16 11:48:18 +0100578 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000579
580 for (TIntermNode *variableNode : sequence)
Olli Etuaho13389b62016-10-16 11:48:18 +0100581 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000582 // The only case in which the sequence will not contain a TIntermSymbol node is
583 // initialization. It will contain a TInterBinary node in that case. Since attributes,
584 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
585 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
586 const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
Olli Etuaho34d20072017-07-18 20:07:18 +0300587 if (variable.getName().isInternal())
588 {
589 // Internal variables are not collected.
590 continue;
591 }
592
Olli Etuahoa55102c2017-02-24 12:36:50 +0000593 if (typedNode.getBasicType() == EbtInterfaceBlock)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000594 {
Jiajia Qinbc585152017-06-23 15:42:17 +0800595 // TODO(jiajia.qin@intel.com): In order not to affect the old set of mInterfaceBlocks,
596 // only uniform blocks are added into mInterfaceBlocks. Refactor it to gather
597 // uniformBlocks and shaderStorageBlocks separately.
598 if (qualifier == EvqUniform)
599 {
600 mInterfaceBlocks->push_back(recordInterfaceBlock(variable));
601 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000602 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000603 else
604 {
605 switch (qualifier)
606 {
607 case EvqAttribute:
608 case EvqVertexIn:
609 mAttribs->push_back(recordAttribute(variable));
610 break;
611 case EvqFragmentOut:
612 mOutputVariables->push_back(recordOutputVariable(variable));
613 break;
614 case EvqUniform:
615 mUniforms->push_back(recordUniform(variable));
616 break;
617 default:
618 mVaryings->push_back(recordVarying(variable));
619 break;
620 }
621 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000622 }
623
Olli Etuahoa55102c2017-02-24 12:36:50 +0000624 // None of the recorded variables can have initializers, so we don't need to traverse the
625 // declarators.
626 return false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000627}
Jamie Madill23a8a432014-07-09 13:27:42 -0400628
Olli Etuaho19515012017-06-26 18:00:17 +0300629bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
Jamie Madillb547ddf2014-08-25 16:20:46 -0400630{
631 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
632 {
Jamie Madilla6f267f2014-08-27 11:44:15 -0400633 // NOTE: we do not determine static use for individual blocks of an array
634 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
635 ASSERT(blockNode);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400636
637 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
638 ASSERT(constantUnion);
639
Jamie Madilla6f267f2014-08-27 11:44:15 -0400640 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
Jamie Madilla2fbb842014-09-03 09:40:47 -0400641 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mInterfaceBlocks);
Jiajia Qinbc585152017-06-23 15:42:17 +0800642 // TODO(jiajia.qin@intel.com): Currently, only uniform blocks are added into
643 // mInterfaceBlocks.
644 if (namedBlock)
645 {
646 namedBlock->staticUse = true;
647 unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
648 ASSERT(fieldIndex < namedBlock->fields.size());
649 namedBlock->fields[fieldIndex].staticUse = true;
650 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400651 return false;
652 }
653
654 return true;
655}
656
Olli Etuaho19515012017-06-26 18:00:17 +0300657} // anonymous namespace
658
659void CollectVariables(TIntermBlock *root,
660 std::vector<Attribute> *attributes,
661 std::vector<OutputVariable> *outputVariables,
662 std::vector<Uniform> *uniforms,
663 std::vector<Varying> *varyings,
664 std::vector<InterfaceBlock> *interfaceBlocks,
665 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300666 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300667 int shaderVersion,
668 const TExtensionBehavior &extensionBehavior)
669{
670 CollectVariablesTraverser collect(attributes, outputVariables, uniforms, varyings,
671 interfaceBlocks, hashFunction, symbolTable, shaderVersion,
672 extensionBehavior);
673 root->traverse(&collect);
674}
675
Corentin Walleze58e1412016-07-18 16:40:46 -0400676void ExpandVariable(const ShaderVariable &variable,
677 const std::string &name,
678 const std::string &mappedName,
679 bool markStaticUse,
680 std::vector<ShaderVariable> *expanded)
681{
682 if (variable.isStruct())
683 {
684 if (variable.isArray())
685 {
686 for (unsigned int elementIndex = 0; elementIndex < variable.elementCount();
687 elementIndex++)
688 {
689 std::string lname = name + ::ArrayString(elementIndex);
690 std::string lmappedName = mappedName + ::ArrayString(elementIndex);
691 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
692 }
693 }
694 else
695 {
696 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
697 }
698 }
699 else
700 {
701 ShaderVariable expandedVar = variable;
702
703 expandedVar.name = name;
704 expandedVar.mappedName = mappedName;
705
706 // Mark all expanded fields as used if the parent is used
707 if (markStaticUse)
708 {
709 expandedVar.staticUse = true;
710 }
711
712 if (expandedVar.isArray())
713 {
714 expandedVar.name += "[0]";
715 expandedVar.mappedName += "[0]";
716 }
717
718 expanded->push_back(expandedVar);
719 }
720}
721
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500722void ExpandUniforms(const std::vector<Uniform> &compact, std::vector<ShaderVariable> *expanded)
Jamie Madill23a8a432014-07-09 13:27:42 -0400723{
Olli Etuaho19515012017-06-26 18:00:17 +0300724 for (const Uniform &variable : compact)
Jamie Madill23a8a432014-07-09 13:27:42 -0400725 {
Jamie Madill23a8a432014-07-09 13:27:42 -0400726 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
727 }
728}
Olli Etuaho19515012017-06-26 18:00:17 +0300729
730} // namespace sh