blob: 39baef9a12cfac7575d8000e7b4dc1bd5cbf5198 [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
Jiajia Qin9b11ea42017-07-11 16:50:08 +080038BlockType GetBlockType(TQualifier qualifier)
39{
40 switch (qualifier)
41 {
42 case EvqUniform:
43 return BlockType::BLOCK_UNIFORM;
44 case EvqBuffer:
45 return BlockType::BLOCK_BUFFER;
46 default:
47 UNREACHABLE();
48 return BlockType::BLOCK_UNIFORM;
49 }
50}
51
Jamie Madilla2fbb842014-09-03 09:40:47 -040052void ExpandUserDefinedVariable(const ShaderVariable &variable,
Jamie Madill54ad4f82014-09-03 09:40:46 -040053 const std::string &name,
54 const std::string &mappedName,
55 bool markStaticUse,
Jamie Madilla2fbb842014-09-03 09:40:47 -040056 std::vector<ShaderVariable> *expanded)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000057{
Jamie Madill23a8a432014-07-09 13:27:42 -040058 ASSERT(variable.isStruct());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000059
Jamie Madilla2fbb842014-09-03 09:40:47 -040060 const std::vector<ShaderVariable> &fields = variable.fields;
Jamie Madill23a8a432014-07-09 13:27:42 -040061
62 for (size_t fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++)
Jamie Madill4667c452014-07-08 15:02:36 -040063 {
Jamie Madilla2fbb842014-09-03 09:40:47 -040064 const ShaderVariable &field = fields[fieldIndex];
Jamie Madilld7b1ab52016-12-12 14:42:19 -050065 ExpandVariable(field, name + "." + field.name, mappedName + "." + field.mappedName,
66 markStaticUse, expanded);
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +000067 }
68}
69
Jamie Madilla718c1e2014-07-02 15:31:22 -040070template <class VarT>
Jamie Madilld7b1ab52016-12-12 14:42:19 -050071VarT *FindVariable(const TString &name, std::vector<VarT> *infoList)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040072{
73 // TODO(zmo): optimize this function.
Jamie Madilla718c1e2014-07-02 15:31:22 -040074 for (size_t ii = 0; ii < infoList->size(); ++ii)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040075 {
Jamie Madill23a8a432014-07-09 13:27:42 -040076 if ((*infoList)[ii].name.c_str() == name)
Jamie Madilla718c1e2014-07-02 15:31:22 -040077 return &((*infoList)[ii]);
Zhenyao Mod2d340b2013-09-23 14:57:05 -040078 }
Jamie Madilld5512cd2014-07-10 17:50:08 -040079
Yunchao Hef81ce4a2017-04-24 10:49:17 +080080 return nullptr;
Zhenyao Mod2d340b2013-09-23 14:57:05 -040081}
Jamie Madill54ad4f82014-09-03 09:40:46 -040082
Olli Etuaho06a06f52017-07-12 12:22:15 +030083// Note that this shouldn't be called for interface blocks - static use information is collected for
84// individual fields in case of interface blocks.
85void MarkStaticallyUsed(ShaderVariable *variable)
86{
87 if (!variable->staticUse)
88 {
89 if (variable->isStruct())
90 {
91 // Conservatively assume all fields are statically used as well.
92 for (auto &field : variable->fields)
93 {
94 MarkStaticallyUsed(&field);
95 }
96 }
97 variable->staticUse = true;
98 }
99}
100
Olli Etuaho19515012017-06-26 18:00:17 +0300101// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
102// and interface blocks.
103class CollectVariablesTraverser : public TIntermTraverser
104{
105 public:
106 CollectVariablesTraverser(std::vector<Attribute> *attribs,
107 std::vector<OutputVariable> *outputVariables,
108 std::vector<Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800109 std::vector<Varying> *inputVaryings,
110 std::vector<Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800111 std::vector<InterfaceBlock> *uniformBlocks,
112 std::vector<InterfaceBlock> *shaderStorageBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300113 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300114 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300115 int shaderVersion,
116 const TExtensionBehavior &extensionBehavior);
117
118 void visitSymbol(TIntermSymbol *symbol) override;
119 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
120 bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
121
122 private:
123 void setCommonVariableProperties(const TType &type,
124 const TString &name,
125 ShaderVariable *variableOut) const;
126
127 Attribute recordAttribute(const TIntermSymbol &variable) const;
128 OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
129 Varying recordVarying(const TIntermSymbol &variable) const;
130 InterfaceBlock recordInterfaceBlock(const TIntermSymbol &variable) const;
131 Uniform recordUniform(const TIntermSymbol &variable) const;
132
133 void setBuiltInInfoFromSymbolTable(const char *name, ShaderVariable *info);
134
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800135 void recordBuiltInVaryingUsed(const char *name,
136 bool *addedFlag,
137 std::vector<Varying> *varyings);
Olli Etuaho19515012017-06-26 18:00:17 +0300138 void recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag);
139 void recordBuiltInAttributeUsed(const char *name, bool *addedFlag);
140
141 std::vector<Attribute> *mAttribs;
142 std::vector<OutputVariable> *mOutputVariables;
143 std::vector<Uniform> *mUniforms;
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800144 std::vector<Varying> *mInputVaryings;
145 std::vector<Varying> *mOutputVaryings;
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800146 std::vector<InterfaceBlock> *mUniformBlocks;
147 std::vector<InterfaceBlock> *mShaderStorageBlocks;
Olli Etuaho19515012017-06-26 18:00:17 +0300148
149 std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
150
151 bool mDepthRangeAdded;
152 bool mPointCoordAdded;
153 bool mFrontFacingAdded;
154 bool mFragCoordAdded;
155
156 bool mInstanceIDAdded;
157 bool mVertexIDAdded;
158 bool mPositionAdded;
159 bool mPointSizeAdded;
160 bool mLastFragDataAdded;
161 bool mFragColorAdded;
162 bool mFragDataAdded;
163 bool mFragDepthEXTAdded;
164 bool mFragDepthAdded;
165 bool mSecondaryFragColorEXTAdded;
166 bool mSecondaryFragDataEXTAdded;
167
168 ShHashFunction64 mHashFunction;
169
Olli Etuaho19515012017-06-26 18:00:17 +0300170 int mShaderVersion;
171 const TExtensionBehavior &mExtensionBehavior;
172};
173
174CollectVariablesTraverser::CollectVariablesTraverser(
175 std::vector<sh::Attribute> *attribs,
176 std::vector<sh::OutputVariable> *outputVariables,
177 std::vector<sh::Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800178 std::vector<sh::Varying> *inputVaryings,
179 std::vector<sh::Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800180 std::vector<sh::InterfaceBlock> *uniformBlocks,
181 std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300182 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300183 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300184 int shaderVersion,
185 const TExtensionBehavior &extensionBehavior)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300186 : TIntermTraverser(true, false, false, symbolTable),
Olli Etuaho3d0d9a42015-06-01 12:16:36 +0300187 mAttribs(attribs),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400188 mOutputVariables(outputVariables),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000189 mUniforms(uniforms),
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800190 mInputVaryings(inputVaryings),
191 mOutputVaryings(outputVaryings),
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800192 mUniformBlocks(uniformBlocks),
193 mShaderStorageBlocks(shaderStorageBlocks),
Jamie Madill55def582015-05-04 11:24:57 -0400194 mDepthRangeAdded(false),
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400195 mPointCoordAdded(false),
196 mFrontFacingAdded(false),
197 mFragCoordAdded(false),
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000198 mInstanceIDAdded(false),
Corentin Wallezb076add2016-01-11 16:45:46 -0500199 mVertexIDAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700200 mPositionAdded(false),
201 mPointSizeAdded(false),
Erik Dahlströmea7a2122014-11-17 16:15:57 +0100202 mLastFragDataAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300203 mFragColorAdded(false),
204 mFragDataAdded(false),
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300205 mFragDepthEXTAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300206 mFragDepthAdded(false),
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +0300207 mSecondaryFragColorEXTAdded(false),
208 mSecondaryFragDataEXTAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700209 mHashFunction(hashFunction),
Olli Etuaho19515012017-06-26 18:00:17 +0300210 mShaderVersion(shaderVersion),
Zhenyao Mof178d0b2016-07-23 06:59:00 -0700211 mExtensionBehavior(extensionBehavior)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000212{
213}
214
Olli Etuaho19515012017-06-26 18:00:17 +0300215void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
216 ShaderVariable *info)
217{
218 TVariable *symbolTableVar =
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300219 reinterpret_cast<TVariable *>(mSymbolTable->findBuiltIn(name, mShaderVersion));
Olli Etuaho19515012017-06-26 18:00:17 +0300220 ASSERT(symbolTableVar);
221 const TType &type = symbolTableVar->getType();
222
223 info->name = name;
224 info->mappedName = name;
225 info->type = GLVariableType(type);
226 info->arraySize = type.isArray() ? type.getArraySize() : 0;
227 info->precision = GLVariablePrecision(type);
228}
229
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800230void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name,
231 bool *addedFlag,
232 std::vector<Varying> *varyings)
Olli Etuaho19515012017-06-26 18:00:17 +0300233{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800234 ASSERT(varyings);
Olli Etuaho19515012017-06-26 18:00:17 +0300235 if (!(*addedFlag))
236 {
237 Varying info;
238 setBuiltInInfoFromSymbolTable(name, &info);
239 info.staticUse = true;
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300240 info.isInvariant = mSymbolTable->isVaryingInvariant(name);
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800241 varyings->push_back(info);
Olli Etuaho19515012017-06-26 18:00:17 +0300242 (*addedFlag) = true;
243 }
244}
245
246void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag)
247{
248 if (!(*addedFlag))
249 {
250 OutputVariable info;
251 setBuiltInInfoFromSymbolTable(name, &info);
252 info.staticUse = true;
253 mOutputVariables->push_back(info);
254 (*addedFlag) = true;
255 }
256}
257
258void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag)
259{
260 if (!(*addedFlag))
261 {
262 Attribute info;
263 setBuiltInInfoFromSymbolTable(name, &info);
264 info.staticUse = true;
265 info.location = -1;
266 mAttribs->push_back(info);
267 (*addedFlag) = true;
268 }
269}
270
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400271// We want to check whether a uniform/varying is statically used
272// because we only count the used ones in packing computing.
273// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
274// toward varying counting if they are statically used in a fragment
275// shader.
Olli Etuaho19515012017-06-26 18:00:17 +0300276void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000277{
Yunchao He4f285442017-04-21 12:15:49 +0800278 ASSERT(symbol != nullptr);
Olli Etuaho34d20072017-07-18 20:07:18 +0300279
280 if (symbol->getName().isInternal())
281 {
282 // Internal variables are not collected.
283 return;
284 }
285
Yunchao Hed7297bf2017-04-19 15:27:10 +0800286 ShaderVariable *var = nullptr;
Olli Etuaho34d20072017-07-18 20:07:18 +0300287 const TString &symbolName = symbol->getName().getString();
Jamie Madill4667c452014-07-08 15:02:36 -0400288
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800289 if (IsVaryingIn(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400290 {
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800291 var = FindVariable(symbolName, mInputVaryings);
292 }
293 else if (IsVaryingOut(symbol->getQualifier()))
294 {
295 var = FindVariable(symbolName, mOutputVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400296 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400297 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
298 {
299 UNREACHABLE();
300 }
Jamie Madill55def582015-05-04 11:24:57 -0400301 else if (symbolName == "gl_DepthRange")
302 {
303 ASSERT(symbol->getQualifier() == EvqUniform);
304
305 if (!mDepthRangeAdded)
306 {
307 Uniform info;
308 const char kName[] = "gl_DepthRange";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500309 info.name = kName;
310 info.mappedName = kName;
311 info.type = GL_STRUCT_ANGLEX;
312 info.arraySize = 0;
313 info.precision = GL_NONE;
314 info.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400315
316 ShaderVariable nearInfo;
317 const char kNearName[] = "near";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500318 nearInfo.name = kNearName;
319 nearInfo.mappedName = kNearName;
320 nearInfo.type = GL_FLOAT;
321 nearInfo.arraySize = 0;
322 nearInfo.precision = GL_HIGH_FLOAT;
323 nearInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400324
325 ShaderVariable farInfo;
326 const char kFarName[] = "far";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500327 farInfo.name = kFarName;
328 farInfo.mappedName = kFarName;
329 farInfo.type = GL_FLOAT;
330 farInfo.arraySize = 0;
331 farInfo.precision = GL_HIGH_FLOAT;
332 farInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400333
334 ShaderVariable diffInfo;
335 const char kDiffName[] = "diff";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500336 diffInfo.name = kDiffName;
337 diffInfo.mappedName = kDiffName;
338 diffInfo.type = GL_FLOAT;
339 diffInfo.arraySize = 0;
340 diffInfo.precision = GL_HIGH_FLOAT;
341 diffInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400342
343 info.fields.push_back(nearInfo);
344 info.fields.push_back(farInfo);
345 info.fields.push_back(diffInfo);
346
347 mUniforms->push_back(info);
348 mDepthRangeAdded = true;
349 }
350 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400351 else
Jamie Madill4667c452014-07-08 15:02:36 -0400352 {
353 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400354 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500355 case EvqAttribute:
356 case EvqVertexIn:
357 var = FindVariable(symbolName, mAttribs);
358 break;
359 case EvqFragmentOut:
360 var = FindVariable(symbolName, mOutputVariables);
361 break;
362 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400363 {
364 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
365 if (interfaceBlock)
366 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500367 InterfaceBlock *namedBlock =
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800368 FindVariable(interfaceBlock->name(), mUniformBlocks);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400369 ASSERT(namedBlock);
370 var = FindVariable(symbolName, &namedBlock->fields);
371
372 // Set static use on the parent interface block here
373 namedBlock->staticUse = true;
374 }
375 else
376 {
377 var = FindVariable(symbolName, mUniforms);
378 }
379
380 // It's an internal error to reference an undefined user uniform
Jamie Madill55def582015-05-04 11:24:57 -0400381 ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400382 }
Jamie Madill4667c452014-07-08 15:02:36 -0400383 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500384 case EvqFragCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800385 recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500386 return;
387 case EvqFrontFacing:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800388 recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500389 return;
390 case EvqPointCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800391 recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500392 return;
393 case EvqInstanceID:
Martin Radev115fc552017-07-05 17:11:06 +0300394 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
395 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
396 // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders
397 // which makes it necessary to populate the type information explicitly instead of
398 // extracting it from the symbol table.
399 if (!mInstanceIDAdded)
400 {
401 Attribute info;
402 const char kName[] = "gl_InstanceID";
403 info.name = kName;
404 info.mappedName = kName;
405 info.type = GL_INT;
406 info.arraySize = 0;
407 info.precision = GL_HIGH_INT; // Defined by spec.
408 info.staticUse = true;
409 info.location = -1;
410 mAttribs->push_back(info);
411 mInstanceIDAdded = true;
412 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500413 return;
414 case EvqVertexID:
Olli Etuaho19515012017-06-26 18:00:17 +0300415 recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500416 return;
417 case EvqPosition:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800418 recordBuiltInVaryingUsed("gl_Position", &mPositionAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500419 return;
420 case EvqPointSize:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800421 recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500422 return;
423 case EvqLastFragData:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800424 recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500425 return;
426 case EvqFragColor:
Olli Etuaho19515012017-06-26 18:00:17 +0300427 recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500428 return;
429 case EvqFragData:
430 if (!mFragDataAdded)
431 {
432 OutputVariable info;
Olli Etuaho19515012017-06-26 18:00:17 +0300433 setBuiltInInfoFromSymbolTable("gl_FragData", &info);
434 if (!::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500435 {
436 info.arraySize = 1;
437 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500438 info.staticUse = true;
439 mOutputVariables->push_back(info);
440 mFragDataAdded = true;
441 }
442 return;
443 case EvqFragDepthEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300444 recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500445 return;
446 case EvqFragDepth:
Olli Etuaho19515012017-06-26 18:00:17 +0300447 recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500448 return;
449 case EvqSecondaryFragColorEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300450 recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT",
451 &mSecondaryFragColorEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500452 return;
453 case EvqSecondaryFragDataEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300454 recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
455 &mSecondaryFragDataEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500456 return;
457 default:
458 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400459 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400460 }
461 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400462 {
Olli Etuaho06a06f52017-07-12 12:22:15 +0300463 MarkStaticallyUsed(var);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400464 }
465}
466
Olli Etuaho19515012017-06-26 18:00:17 +0300467void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
468 const TString &name,
469 ShaderVariable *variableOut) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400470{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000471 ASSERT(variableOut);
472
473 const TStructure *structure = type.getStruct();
474
475 if (!structure)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500476 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000477 variableOut->type = GLVariableType(type);
478 variableOut->precision = GLVariablePrecision(type);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500479 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000480 else
Jamie Madill23a8a432014-07-09 13:27:42 -0400481 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000482 // Note: this enum value is not exposed outside ANGLE
483 variableOut->type = GL_STRUCT_ANGLEX;
484 variableOut->structName = structure->name().c_str();
485
486 const TFieldList &fields = structure->fields();
487
488 for (TField *field : fields)
489 {
490 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
491 // ShaderVariable objects.
492 ShaderVariable fieldVariable;
493 setCommonVariableProperties(*field->type(), field->name(), &fieldVariable);
494 variableOut->fields.push_back(fieldVariable);
495 }
Jamie Madill23a8a432014-07-09 13:27:42 -0400496 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000497 variableOut->name = name.c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300498 variableOut->mappedName = HashName(name, mHashFunction).c_str();
Olli Etuahoa55102c2017-02-24 12:36:50 +0000499 variableOut->arraySize = type.getArraySize();
500}
Jamie Madill23a8a432014-07-09 13:27:42 -0400501
Olli Etuaho19515012017-06-26 18:00:17 +0300502Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400503{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000504 const TType &type = variable.getType();
Jamie Madill23a8a432014-07-09 13:27:42 -0400505 ASSERT(!type.getStruct());
506
Jamie Madilla2fbb842014-09-03 09:40:47 -0400507 Attribute attribute;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000508 setCommonVariableProperties(type, variable.getSymbol(), &attribute);
Jamie Madill23a8a432014-07-09 13:27:42 -0400509
Olli Etuahoa55102c2017-02-24 12:36:50 +0000510 attribute.location = type.getLayoutQualifier().location;
511 return attribute;
Jamie Madill23a8a432014-07-09 13:27:42 -0400512}
513
Olli Etuaho19515012017-06-26 18:00:17 +0300514OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
Jamie Madilla0a9e122015-09-02 15:54:30 -0400515{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000516 const TType &type = variable.getType();
Jamie Madilla0a9e122015-09-02 15:54:30 -0400517 ASSERT(!type.getStruct());
518
Olli Etuahoa55102c2017-02-24 12:36:50 +0000519 OutputVariable outputVariable;
520 setCommonVariableProperties(type, variable.getSymbol(), &outputVariable);
Jamie Madilla0a9e122015-09-02 15:54:30 -0400521
Olli Etuahoa55102c2017-02-24 12:36:50 +0000522 outputVariable.location = type.getLayoutQualifier().location;
523 return outputVariable;
Jamie Madilla0a9e122015-09-02 15:54:30 -0400524}
525
Olli Etuaho19515012017-06-26 18:00:17 +0300526Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
Jamie Madilld5512cd2014-07-10 17:50:08 -0400527{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000528 const TType &type = variable.getType();
529
530 Varying varying;
531 setCommonVariableProperties(type, variable.getSymbol(), &varying);
532
533 switch (type.getQualifier())
534 {
535 case EvqVaryingIn:
536 case EvqVaryingOut:
537 case EvqVertexOut:
538 case EvqSmoothOut:
539 case EvqFlatOut:
540 case EvqCentroidOut:
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300541 if (mSymbolTable->isVaryingInvariant(std::string(variable.getSymbol().c_str())) ||
Olli Etuahoa55102c2017-02-24 12:36:50 +0000542 type.isInvariant())
543 {
544 varying.isInvariant = true;
545 }
546 break;
547 default:
548 break;
549 }
550
551 varying.interpolation = GetInterpolationType(type.getQualifier());
552 return varying;
553}
554
Olli Etuaho19515012017-06-26 18:00:17 +0300555InterfaceBlock CollectVariablesTraverser::recordInterfaceBlock(const TIntermSymbol &variable) const
Olli Etuahoa55102c2017-02-24 12:36:50 +0000556{
557 const TInterfaceBlock *blockType = variable.getType().getInterfaceBlock();
Jamie Madill42bcf322014-08-25 16:20:46 -0400558 ASSERT(blockType);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400559
Olli Etuahoa55102c2017-02-24 12:36:50 +0000560 InterfaceBlock interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400561 interfaceBlock.name = blockType->name().c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300562 interfaceBlock.mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500563 interfaceBlock.instanceName =
564 (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
Olli Etuahoa55102c2017-02-24 12:36:50 +0000565 interfaceBlock.arraySize = variable.getArraySize();
Jamie Madill42bcf322014-08-25 16:20:46 -0400566 interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
jchen10af713a22017-04-19 09:10:56 +0800567 interfaceBlock.binding = blockType->blockBinding();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500568 interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800569 interfaceBlock.blockType = GetBlockType(variable.getType().getQualifier());
Jamie Madilld5512cd2014-07-10 17:50:08 -0400570
Jamie Madilla6f267f2014-08-27 11:44:15 -0400571 // Gather field information
Jamie Madill39046162016-02-08 15:05:17 -0500572 for (const TField *field : blockType->fields())
Jamie Madill54ad4f82014-09-03 09:40:46 -0400573 {
Jamie Madill39046162016-02-08 15:05:17 -0500574 const TType &fieldType = *field->type();
Jamie Madill54ad4f82014-09-03 09:40:46 -0400575
Olli Etuahoa55102c2017-02-24 12:36:50 +0000576 InterfaceBlockField fieldVariable;
577 setCommonVariableProperties(fieldType, field->name(), &fieldVariable);
578 fieldVariable.isRowMajorLayout =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500579 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
Olli Etuahoa55102c2017-02-24 12:36:50 +0000580 interfaceBlock.fields.push_back(fieldVariable);
Jamie Madill54ad4f82014-09-03 09:40:46 -0400581 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000582 return interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400583}
584
Olli Etuaho19515012017-06-26 18:00:17 +0300585Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
Jamie Madill4667c452014-07-08 15:02:36 -0400586{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000587 Uniform uniform;
588 setCommonVariableProperties(variable.getType(), variable.getSymbol(), &uniform);
Olli Etuaho547cbd42017-02-27 11:54:00 +0200589 uniform.binding = variable.getType().getLayoutQualifier().binding;
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000590 uniform.location = variable.getType().getLayoutQualifier().location;
jchen104cdac9e2017-05-08 11:01:20 +0800591 uniform.offset = variable.getType().getLayoutQualifier().offset;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000592 return uniform;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000593}
594
Olli Etuaho19515012017-06-26 18:00:17 +0300595bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000596{
Olli Etuaho13389b62016-10-16 11:48:18 +0100597 const TIntermSequence &sequence = *(node->getSequence());
598 ASSERT(!sequence.empty());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000599
Olli Etuaho13389b62016-10-16 11:48:18 +0100600 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
601 TQualifier qualifier = typedNode.getQualifier();
602
Olli Etuahoa55102c2017-02-24 12:36:50 +0000603 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
604 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
605 IsVarying(qualifier);
606
607 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000608 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000609 return true;
Olli Etuaho13389b62016-10-16 11:48:18 +0100610 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000611
612 for (TIntermNode *variableNode : sequence)
Olli Etuaho13389b62016-10-16 11:48:18 +0100613 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000614 // The only case in which the sequence will not contain a TIntermSymbol node is
615 // initialization. It will contain a TInterBinary node in that case. Since attributes,
616 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
617 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
618 const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
Olli Etuaho34d20072017-07-18 20:07:18 +0300619 if (variable.getName().isInternal())
620 {
621 // Internal variables are not collected.
622 continue;
623 }
624
Olli Etuahoa55102c2017-02-24 12:36:50 +0000625 if (typedNode.getBasicType() == EbtInterfaceBlock)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000626 {
Jiajia Qinbc585152017-06-23 15:42:17 +0800627 if (qualifier == EvqUniform)
628 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800629 mUniformBlocks->push_back(recordInterfaceBlock(variable));
630 }
631 else if (qualifier == EvqBuffer)
632 {
633 mShaderStorageBlocks->push_back(recordInterfaceBlock(variable));
Jiajia Qinbc585152017-06-23 15:42:17 +0800634 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000635 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000636 else
637 {
638 switch (qualifier)
639 {
640 case EvqAttribute:
641 case EvqVertexIn:
642 mAttribs->push_back(recordAttribute(variable));
643 break;
644 case EvqFragmentOut:
645 mOutputVariables->push_back(recordOutputVariable(variable));
646 break;
647 case EvqUniform:
648 mUniforms->push_back(recordUniform(variable));
649 break;
650 default:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800651 if (IsVaryingIn(qualifier))
652 {
653 mInputVaryings->push_back(recordVarying(variable));
654 }
655 else
656 {
657 ASSERT(IsVaryingOut(qualifier));
658 mOutputVaryings->push_back(recordVarying(variable));
659 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000660 break;
661 }
662 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000663 }
664
Olli Etuahoa55102c2017-02-24 12:36:50 +0000665 // None of the recorded variables can have initializers, so we don't need to traverse the
666 // declarators.
667 return false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000668}
Jamie Madill23a8a432014-07-09 13:27:42 -0400669
Olli Etuaho19515012017-06-26 18:00:17 +0300670bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
Jamie Madillb547ddf2014-08-25 16:20:46 -0400671{
672 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
673 {
Jamie Madilla6f267f2014-08-27 11:44:15 -0400674 // NOTE: we do not determine static use for individual blocks of an array
675 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
676 ASSERT(blockNode);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400677
678 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
679 ASSERT(constantUnion);
680
Jamie Madilla6f267f2014-08-27 11:44:15 -0400681 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800682 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mUniformBlocks);
683 if (!namedBlock)
Jiajia Qinbc585152017-06-23 15:42:17 +0800684 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800685 namedBlock = FindVariable(interfaceBlock->name(), mShaderStorageBlocks);
Jiajia Qinbc585152017-06-23 15:42:17 +0800686 }
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800687 ASSERT(namedBlock);
688 namedBlock->staticUse = true;
689 unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
690 ASSERT(fieldIndex < namedBlock->fields.size());
691 namedBlock->fields[fieldIndex].staticUse = true;
Jamie Madillb547ddf2014-08-25 16:20:46 -0400692 return false;
693 }
694
695 return true;
696}
697
Olli Etuaho19515012017-06-26 18:00:17 +0300698} // anonymous namespace
699
700void CollectVariables(TIntermBlock *root,
701 std::vector<Attribute> *attributes,
702 std::vector<OutputVariable> *outputVariables,
703 std::vector<Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800704 std::vector<Varying> *inputVaryings,
705 std::vector<Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800706 std::vector<InterfaceBlock> *uniformBlocks,
707 std::vector<InterfaceBlock> *shaderStorageBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300708 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300709 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300710 int shaderVersion,
711 const TExtensionBehavior &extensionBehavior)
712{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800713 CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800714 outputVaryings, uniformBlocks, shaderStorageBlocks,
715 hashFunction, symbolTable, shaderVersion, extensionBehavior);
Olli Etuaho19515012017-06-26 18:00:17 +0300716 root->traverse(&collect);
717}
718
Corentin Walleze58e1412016-07-18 16:40:46 -0400719void ExpandVariable(const ShaderVariable &variable,
720 const std::string &name,
721 const std::string &mappedName,
722 bool markStaticUse,
723 std::vector<ShaderVariable> *expanded)
724{
725 if (variable.isStruct())
726 {
727 if (variable.isArray())
728 {
729 for (unsigned int elementIndex = 0; elementIndex < variable.elementCount();
730 elementIndex++)
731 {
732 std::string lname = name + ::ArrayString(elementIndex);
733 std::string lmappedName = mappedName + ::ArrayString(elementIndex);
734 ExpandUserDefinedVariable(variable, lname, lmappedName, markStaticUse, expanded);
735 }
736 }
737 else
738 {
739 ExpandUserDefinedVariable(variable, name, mappedName, markStaticUse, expanded);
740 }
741 }
742 else
743 {
744 ShaderVariable expandedVar = variable;
745
746 expandedVar.name = name;
747 expandedVar.mappedName = mappedName;
748
749 // Mark all expanded fields as used if the parent is used
750 if (markStaticUse)
751 {
752 expandedVar.staticUse = true;
753 }
754
755 if (expandedVar.isArray())
756 {
757 expandedVar.name += "[0]";
758 expandedVar.mappedName += "[0]";
759 }
760
761 expanded->push_back(expandedVar);
762 }
763}
764
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500765void ExpandUniforms(const std::vector<Uniform> &compact, std::vector<ShaderVariable> *expanded)
Jamie Madill23a8a432014-07-09 13:27:42 -0400766{
Olli Etuaho19515012017-06-26 18:00:17 +0300767 for (const Uniform &variable : compact)
Jamie Madill23a8a432014-07-09 13:27:42 -0400768 {
Jamie Madill23a8a432014-07-09 13:27:42 -0400769 ExpandVariable(variable, variable.name, variable.mappedName, variable.staticUse, expanded);
770 }
771}
Olli Etuaho19515012017-06-26 18:00:17 +0300772
773} // namespace sh