blob: 4ffae59ecdbaef4f629b2a1dc46c9722059039a9 [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//
Olli Etuaho78ed6cd2017-08-09 16:19:00 +03006// CollectVariables.cpp: Collect lists of shader interface variables based on the AST.
alokp@chromium.org07620a52010-09-23 17:53:56 +00007
Olli Etuaho78ed6cd2017-08-09 16:19:00 +03008#include "compiler/translator/CollectVariables.h"
Olli Etuaho19515012017-06-26 18:00:17 +03009
10#include "angle_gl.h"
Jamie Madilld5512cd2014-07-10 17:50:08 -040011#include "common/utilities.h"
Olli Etuahocccf2b02017-07-05 14:50:54 +030012#include "compiler/translator/HashNames.h"
13#include "compiler/translator/IntermTraverse.h"
Olli Etuaho19515012017-06-26 18:00:17 +030014#include "compiler/translator/SymbolTable.h"
15#include "compiler/translator/util.h"
alokp@chromium.org07620a52010-09-23 17:53:56 +000016
Jamie Madilla2fbb842014-09-03 09:40:47 -040017namespace sh
18{
19
Jamie Madill54ad4f82014-09-03 09:40:46 -040020namespace
21{
Zhenyao Mod2d340b2013-09-23 14:57:05 -040022
Jamie Madilla2fbb842014-09-03 09:40:47 -040023BlockLayoutType GetBlockLayoutType(TLayoutBlockStorage blockStorage)
Jamie Madill54ad4f82014-09-03 09:40:46 -040024{
25 switch (blockStorage)
26 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -050027 case EbsPacked:
28 return BLOCKLAYOUT_PACKED;
29 case EbsShared:
30 return BLOCKLAYOUT_SHARED;
31 case EbsStd140:
32 return BLOCKLAYOUT_STANDARD;
33 default:
34 UNREACHABLE();
35 return BLOCKLAYOUT_SHARED;
Jamie Madill54ad4f82014-09-03 09:40:46 -040036 }
37}
38
Jiajia Qin9b11ea42017-07-11 16:50:08 +080039BlockType GetBlockType(TQualifier qualifier)
40{
41 switch (qualifier)
42 {
43 case EvqUniform:
44 return BlockType::BLOCK_UNIFORM;
45 case EvqBuffer:
46 return BlockType::BLOCK_BUFFER;
47 default:
48 UNREACHABLE();
49 return BlockType::BLOCK_UNIFORM;
50 }
51}
52
Jamie Madilla718c1e2014-07-02 15:31:22 -040053template <class VarT>
Jamie Madilld7b1ab52016-12-12 14:42:19 -050054VarT *FindVariable(const TString &name, std::vector<VarT> *infoList)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040055{
56 // TODO(zmo): optimize this function.
Jamie Madilla718c1e2014-07-02 15:31:22 -040057 for (size_t ii = 0; ii < infoList->size(); ++ii)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040058 {
Jamie Madill23a8a432014-07-09 13:27:42 -040059 if ((*infoList)[ii].name.c_str() == name)
Jamie Madilla718c1e2014-07-02 15:31:22 -040060 return &((*infoList)[ii]);
Zhenyao Mod2d340b2013-09-23 14:57:05 -040061 }
Jamie Madilld5512cd2014-07-10 17:50:08 -040062
Yunchao Hef81ce4a2017-04-24 10:49:17 +080063 return nullptr;
Zhenyao Mod2d340b2013-09-23 14:57:05 -040064}
Jamie Madill54ad4f82014-09-03 09:40:46 -040065
Olli Etuaho06a06f52017-07-12 12:22:15 +030066// Note that this shouldn't be called for interface blocks - static use information is collected for
67// individual fields in case of interface blocks.
68void MarkStaticallyUsed(ShaderVariable *variable)
69{
70 if (!variable->staticUse)
71 {
72 if (variable->isStruct())
73 {
74 // Conservatively assume all fields are statically used as well.
75 for (auto &field : variable->fields)
76 {
77 MarkStaticallyUsed(&field);
78 }
79 }
80 variable->staticUse = true;
81 }
82}
83
Olli Etuaho19515012017-06-26 18:00:17 +030084// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
85// and interface blocks.
86class CollectVariablesTraverser : public TIntermTraverser
87{
88 public:
89 CollectVariablesTraverser(std::vector<Attribute> *attribs,
90 std::vector<OutputVariable> *outputVariables,
91 std::vector<Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +080092 std::vector<Varying> *inputVaryings,
93 std::vector<Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +080094 std::vector<InterfaceBlock> *uniformBlocks,
95 std::vector<InterfaceBlock> *shaderStorageBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +030096 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +030097 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +030098 int shaderVersion,
99 const TExtensionBehavior &extensionBehavior);
100
101 void visitSymbol(TIntermSymbol *symbol) override;
102 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
103 bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
104
105 private:
106 void setCommonVariableProperties(const TType &type,
107 const TString &name,
108 ShaderVariable *variableOut) const;
109
110 Attribute recordAttribute(const TIntermSymbol &variable) const;
111 OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
112 Varying recordVarying(const TIntermSymbol &variable) const;
113 InterfaceBlock recordInterfaceBlock(const TIntermSymbol &variable) const;
114 Uniform recordUniform(const TIntermSymbol &variable) const;
115
116 void setBuiltInInfoFromSymbolTable(const char *name, ShaderVariable *info);
117
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800118 void recordBuiltInVaryingUsed(const char *name,
119 bool *addedFlag,
120 std::vector<Varying> *varyings);
Olli Etuaho19515012017-06-26 18:00:17 +0300121 void recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag);
122 void recordBuiltInAttributeUsed(const char *name, bool *addedFlag);
123
124 std::vector<Attribute> *mAttribs;
125 std::vector<OutputVariable> *mOutputVariables;
126 std::vector<Uniform> *mUniforms;
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800127 std::vector<Varying> *mInputVaryings;
128 std::vector<Varying> *mOutputVaryings;
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800129 std::vector<InterfaceBlock> *mUniformBlocks;
130 std::vector<InterfaceBlock> *mShaderStorageBlocks;
Olli Etuaho19515012017-06-26 18:00:17 +0300131
132 std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
133
134 bool mDepthRangeAdded;
135 bool mPointCoordAdded;
136 bool mFrontFacingAdded;
137 bool mFragCoordAdded;
138
139 bool mInstanceIDAdded;
140 bool mVertexIDAdded;
141 bool mPositionAdded;
142 bool mPointSizeAdded;
143 bool mLastFragDataAdded;
144 bool mFragColorAdded;
145 bool mFragDataAdded;
146 bool mFragDepthEXTAdded;
147 bool mFragDepthAdded;
148 bool mSecondaryFragColorEXTAdded;
149 bool mSecondaryFragDataEXTAdded;
150
151 ShHashFunction64 mHashFunction;
152
Olli Etuaho19515012017-06-26 18:00:17 +0300153 int mShaderVersion;
154 const TExtensionBehavior &mExtensionBehavior;
155};
156
157CollectVariablesTraverser::CollectVariablesTraverser(
158 std::vector<sh::Attribute> *attribs,
159 std::vector<sh::OutputVariable> *outputVariables,
160 std::vector<sh::Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800161 std::vector<sh::Varying> *inputVaryings,
162 std::vector<sh::Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800163 std::vector<sh::InterfaceBlock> *uniformBlocks,
164 std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300165 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300166 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300167 int shaderVersion,
168 const TExtensionBehavior &extensionBehavior)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300169 : TIntermTraverser(true, false, false, symbolTable),
Olli Etuaho3d0d9a42015-06-01 12:16:36 +0300170 mAttribs(attribs),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400171 mOutputVariables(outputVariables),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000172 mUniforms(uniforms),
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800173 mInputVaryings(inputVaryings),
174 mOutputVaryings(outputVaryings),
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800175 mUniformBlocks(uniformBlocks),
176 mShaderStorageBlocks(shaderStorageBlocks),
Jamie Madill55def582015-05-04 11:24:57 -0400177 mDepthRangeAdded(false),
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400178 mPointCoordAdded(false),
179 mFrontFacingAdded(false),
180 mFragCoordAdded(false),
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000181 mInstanceIDAdded(false),
Corentin Wallezb076add2016-01-11 16:45:46 -0500182 mVertexIDAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700183 mPositionAdded(false),
184 mPointSizeAdded(false),
Erik Dahlströmea7a2122014-11-17 16:15:57 +0100185 mLastFragDataAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300186 mFragColorAdded(false),
187 mFragDataAdded(false),
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300188 mFragDepthEXTAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300189 mFragDepthAdded(false),
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +0300190 mSecondaryFragColorEXTAdded(false),
191 mSecondaryFragDataEXTAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700192 mHashFunction(hashFunction),
Olli Etuaho19515012017-06-26 18:00:17 +0300193 mShaderVersion(shaderVersion),
Zhenyao Mof178d0b2016-07-23 06:59:00 -0700194 mExtensionBehavior(extensionBehavior)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000195{
196}
197
Olli Etuaho19515012017-06-26 18:00:17 +0300198void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
199 ShaderVariable *info)
200{
201 TVariable *symbolTableVar =
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300202 reinterpret_cast<TVariable *>(mSymbolTable->findBuiltIn(name, mShaderVersion));
Olli Etuaho19515012017-06-26 18:00:17 +0300203 ASSERT(symbolTableVar);
204 const TType &type = symbolTableVar->getType();
205
206 info->name = name;
207 info->mappedName = name;
208 info->type = GLVariableType(type);
209 info->arraySize = type.isArray() ? type.getArraySize() : 0;
210 info->precision = GLVariablePrecision(type);
211}
212
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800213void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name,
214 bool *addedFlag,
215 std::vector<Varying> *varyings)
Olli Etuaho19515012017-06-26 18:00:17 +0300216{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800217 ASSERT(varyings);
Olli Etuaho19515012017-06-26 18:00:17 +0300218 if (!(*addedFlag))
219 {
220 Varying info;
221 setBuiltInInfoFromSymbolTable(name, &info);
222 info.staticUse = true;
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300223 info.isInvariant = mSymbolTable->isVaryingInvariant(name);
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800224 varyings->push_back(info);
Olli Etuaho19515012017-06-26 18:00:17 +0300225 (*addedFlag) = true;
226 }
227}
228
229void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag)
230{
231 if (!(*addedFlag))
232 {
233 OutputVariable info;
234 setBuiltInInfoFromSymbolTable(name, &info);
235 info.staticUse = true;
236 mOutputVariables->push_back(info);
237 (*addedFlag) = true;
238 }
239}
240
241void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag)
242{
243 if (!(*addedFlag))
244 {
245 Attribute info;
246 setBuiltInInfoFromSymbolTable(name, &info);
247 info.staticUse = true;
248 info.location = -1;
249 mAttribs->push_back(info);
250 (*addedFlag) = true;
251 }
252}
253
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400254// We want to check whether a uniform/varying is statically used
255// because we only count the used ones in packing computing.
256// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
257// toward varying counting if they are statically used in a fragment
258// shader.
Olli Etuaho19515012017-06-26 18:00:17 +0300259void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000260{
Yunchao He4f285442017-04-21 12:15:49 +0800261 ASSERT(symbol != nullptr);
Olli Etuaho34d20072017-07-18 20:07:18 +0300262
263 if (symbol->getName().isInternal())
264 {
265 // Internal variables are not collected.
266 return;
267 }
268
Yunchao Hed7297bf2017-04-19 15:27:10 +0800269 ShaderVariable *var = nullptr;
Olli Etuaho34d20072017-07-18 20:07:18 +0300270 const TString &symbolName = symbol->getName().getString();
Jamie Madill4667c452014-07-08 15:02:36 -0400271
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800272 if (IsVaryingIn(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400273 {
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800274 var = FindVariable(symbolName, mInputVaryings);
275 }
276 else if (IsVaryingOut(symbol->getQualifier()))
277 {
278 var = FindVariable(symbolName, mOutputVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400279 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400280 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
281 {
282 UNREACHABLE();
283 }
Jamie Madill55def582015-05-04 11:24:57 -0400284 else if (symbolName == "gl_DepthRange")
285 {
286 ASSERT(symbol->getQualifier() == EvqUniform);
287
288 if (!mDepthRangeAdded)
289 {
290 Uniform info;
291 const char kName[] = "gl_DepthRange";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500292 info.name = kName;
293 info.mappedName = kName;
294 info.type = GL_STRUCT_ANGLEX;
295 info.arraySize = 0;
296 info.precision = GL_NONE;
297 info.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400298
299 ShaderVariable nearInfo;
300 const char kNearName[] = "near";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500301 nearInfo.name = kNearName;
302 nearInfo.mappedName = kNearName;
303 nearInfo.type = GL_FLOAT;
304 nearInfo.arraySize = 0;
305 nearInfo.precision = GL_HIGH_FLOAT;
306 nearInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400307
308 ShaderVariable farInfo;
309 const char kFarName[] = "far";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500310 farInfo.name = kFarName;
311 farInfo.mappedName = kFarName;
312 farInfo.type = GL_FLOAT;
313 farInfo.arraySize = 0;
314 farInfo.precision = GL_HIGH_FLOAT;
315 farInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400316
317 ShaderVariable diffInfo;
318 const char kDiffName[] = "diff";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500319 diffInfo.name = kDiffName;
320 diffInfo.mappedName = kDiffName;
321 diffInfo.type = GL_FLOAT;
322 diffInfo.arraySize = 0;
323 diffInfo.precision = GL_HIGH_FLOAT;
324 diffInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400325
326 info.fields.push_back(nearInfo);
327 info.fields.push_back(farInfo);
328 info.fields.push_back(diffInfo);
329
330 mUniforms->push_back(info);
331 mDepthRangeAdded = true;
332 }
333 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400334 else
Jamie Madill4667c452014-07-08 15:02:36 -0400335 {
336 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400337 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500338 case EvqAttribute:
339 case EvqVertexIn:
340 var = FindVariable(symbolName, mAttribs);
341 break;
342 case EvqFragmentOut:
343 var = FindVariable(symbolName, mOutputVariables);
344 break;
345 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400346 {
347 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
348 if (interfaceBlock)
349 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500350 InterfaceBlock *namedBlock =
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800351 FindVariable(interfaceBlock->name(), mUniformBlocks);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400352 ASSERT(namedBlock);
353 var = FindVariable(symbolName, &namedBlock->fields);
354
355 // Set static use on the parent interface block here
356 namedBlock->staticUse = true;
357 }
358 else
359 {
360 var = FindVariable(symbolName, mUniforms);
361 }
362
363 // It's an internal error to reference an undefined user uniform
Jamie Madill55def582015-05-04 11:24:57 -0400364 ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400365 }
Jamie Madill4667c452014-07-08 15:02:36 -0400366 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500367 case EvqFragCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800368 recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500369 return;
370 case EvqFrontFacing:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800371 recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500372 return;
373 case EvqPointCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800374 recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500375 return;
376 case EvqInstanceID:
Martin Radev115fc552017-07-05 17:11:06 +0300377 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
378 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
379 // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders
380 // which makes it necessary to populate the type information explicitly instead of
381 // extracting it from the symbol table.
382 if (!mInstanceIDAdded)
383 {
384 Attribute info;
385 const char kName[] = "gl_InstanceID";
386 info.name = kName;
387 info.mappedName = kName;
388 info.type = GL_INT;
389 info.arraySize = 0;
390 info.precision = GL_HIGH_INT; // Defined by spec.
391 info.staticUse = true;
392 info.location = -1;
393 mAttribs->push_back(info);
394 mInstanceIDAdded = true;
395 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500396 return;
397 case EvqVertexID:
Olli Etuaho19515012017-06-26 18:00:17 +0300398 recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500399 return;
400 case EvqPosition:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800401 recordBuiltInVaryingUsed("gl_Position", &mPositionAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500402 return;
403 case EvqPointSize:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800404 recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500405 return;
406 case EvqLastFragData:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800407 recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500408 return;
409 case EvqFragColor:
Olli Etuaho19515012017-06-26 18:00:17 +0300410 recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500411 return;
412 case EvqFragData:
413 if (!mFragDataAdded)
414 {
415 OutputVariable info;
Olli Etuaho19515012017-06-26 18:00:17 +0300416 setBuiltInInfoFromSymbolTable("gl_FragData", &info);
417 if (!::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500418 {
419 info.arraySize = 1;
420 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500421 info.staticUse = true;
422 mOutputVariables->push_back(info);
423 mFragDataAdded = true;
424 }
425 return;
426 case EvqFragDepthEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300427 recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500428 return;
429 case EvqFragDepth:
Olli Etuaho19515012017-06-26 18:00:17 +0300430 recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500431 return;
432 case EvqSecondaryFragColorEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300433 recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT",
434 &mSecondaryFragColorEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500435 return;
436 case EvqSecondaryFragDataEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300437 recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
438 &mSecondaryFragDataEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500439 return;
440 default:
441 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400442 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400443 }
444 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400445 {
Olli Etuaho06a06f52017-07-12 12:22:15 +0300446 MarkStaticallyUsed(var);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400447 }
448}
449
Olli Etuaho19515012017-06-26 18:00:17 +0300450void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
451 const TString &name,
452 ShaderVariable *variableOut) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400453{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000454 ASSERT(variableOut);
455
456 const TStructure *structure = type.getStruct();
457
458 if (!structure)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500459 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000460 variableOut->type = GLVariableType(type);
461 variableOut->precision = GLVariablePrecision(type);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500462 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000463 else
Jamie Madill23a8a432014-07-09 13:27:42 -0400464 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000465 // Note: this enum value is not exposed outside ANGLE
466 variableOut->type = GL_STRUCT_ANGLEX;
467 variableOut->structName = structure->name().c_str();
468
469 const TFieldList &fields = structure->fields();
470
471 for (TField *field : fields)
472 {
473 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
474 // ShaderVariable objects.
475 ShaderVariable fieldVariable;
476 setCommonVariableProperties(*field->type(), field->name(), &fieldVariable);
477 variableOut->fields.push_back(fieldVariable);
478 }
Jamie Madill23a8a432014-07-09 13:27:42 -0400479 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000480 variableOut->name = name.c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300481 variableOut->mappedName = HashName(name, mHashFunction).c_str();
Olli Etuahoa55102c2017-02-24 12:36:50 +0000482 variableOut->arraySize = type.getArraySize();
483}
Jamie Madill23a8a432014-07-09 13:27:42 -0400484
Olli Etuaho19515012017-06-26 18:00:17 +0300485Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400486{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000487 const TType &type = variable.getType();
Jamie Madill23a8a432014-07-09 13:27:42 -0400488 ASSERT(!type.getStruct());
489
Jamie Madilla2fbb842014-09-03 09:40:47 -0400490 Attribute attribute;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000491 setCommonVariableProperties(type, variable.getSymbol(), &attribute);
Jamie Madill23a8a432014-07-09 13:27:42 -0400492
Olli Etuahoa55102c2017-02-24 12:36:50 +0000493 attribute.location = type.getLayoutQualifier().location;
494 return attribute;
Jamie Madill23a8a432014-07-09 13:27:42 -0400495}
496
Olli Etuaho19515012017-06-26 18:00:17 +0300497OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
Jamie Madilla0a9e122015-09-02 15:54:30 -0400498{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000499 const TType &type = variable.getType();
Jamie Madilla0a9e122015-09-02 15:54:30 -0400500 ASSERT(!type.getStruct());
501
Olli Etuahoa55102c2017-02-24 12:36:50 +0000502 OutputVariable outputVariable;
503 setCommonVariableProperties(type, variable.getSymbol(), &outputVariable);
Jamie Madilla0a9e122015-09-02 15:54:30 -0400504
Olli Etuahoa55102c2017-02-24 12:36:50 +0000505 outputVariable.location = type.getLayoutQualifier().location;
506 return outputVariable;
Jamie Madilla0a9e122015-09-02 15:54:30 -0400507}
508
Olli Etuaho19515012017-06-26 18:00:17 +0300509Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
Jamie Madilld5512cd2014-07-10 17:50:08 -0400510{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000511 const TType &type = variable.getType();
512
513 Varying varying;
514 setCommonVariableProperties(type, variable.getSymbol(), &varying);
515
516 switch (type.getQualifier())
517 {
518 case EvqVaryingIn:
519 case EvqVaryingOut:
520 case EvqVertexOut:
521 case EvqSmoothOut:
522 case EvqFlatOut:
523 case EvqCentroidOut:
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300524 if (mSymbolTable->isVaryingInvariant(std::string(variable.getSymbol().c_str())) ||
Olli Etuahoa55102c2017-02-24 12:36:50 +0000525 type.isInvariant())
526 {
527 varying.isInvariant = true;
528 }
529 break;
530 default:
531 break;
532 }
533
534 varying.interpolation = GetInterpolationType(type.getQualifier());
535 return varying;
536}
537
Olli Etuaho19515012017-06-26 18:00:17 +0300538InterfaceBlock CollectVariablesTraverser::recordInterfaceBlock(const TIntermSymbol &variable) const
Olli Etuahoa55102c2017-02-24 12:36:50 +0000539{
540 const TInterfaceBlock *blockType = variable.getType().getInterfaceBlock();
Jamie Madill42bcf322014-08-25 16:20:46 -0400541 ASSERT(blockType);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400542
Olli Etuahoa55102c2017-02-24 12:36:50 +0000543 InterfaceBlock interfaceBlock;
Olli Etuaho78ed6cd2017-08-09 16:19:00 +0300544 interfaceBlock.name = blockType->name().c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300545 interfaceBlock.mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500546 interfaceBlock.instanceName =
547 (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
Olli Etuahoa55102c2017-02-24 12:36:50 +0000548 interfaceBlock.arraySize = variable.getArraySize();
Jamie Madill42bcf322014-08-25 16:20:46 -0400549 interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
jchen10af713a22017-04-19 09:10:56 +0800550 interfaceBlock.binding = blockType->blockBinding();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500551 interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800552 interfaceBlock.blockType = GetBlockType(variable.getType().getQualifier());
Jamie Madilld5512cd2014-07-10 17:50:08 -0400553
Jamie Madilla6f267f2014-08-27 11:44:15 -0400554 // Gather field information
Jamie Madill39046162016-02-08 15:05:17 -0500555 for (const TField *field : blockType->fields())
Jamie Madill54ad4f82014-09-03 09:40:46 -0400556 {
Jamie Madill39046162016-02-08 15:05:17 -0500557 const TType &fieldType = *field->type();
Jamie Madill54ad4f82014-09-03 09:40:46 -0400558
Olli Etuahoa55102c2017-02-24 12:36:50 +0000559 InterfaceBlockField fieldVariable;
560 setCommonVariableProperties(fieldType, field->name(), &fieldVariable);
561 fieldVariable.isRowMajorLayout =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500562 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
Olli Etuahoa55102c2017-02-24 12:36:50 +0000563 interfaceBlock.fields.push_back(fieldVariable);
Jamie Madill54ad4f82014-09-03 09:40:46 -0400564 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000565 return interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400566}
567
Olli Etuaho19515012017-06-26 18:00:17 +0300568Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
Jamie Madill4667c452014-07-08 15:02:36 -0400569{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000570 Uniform uniform;
571 setCommonVariableProperties(variable.getType(), variable.getSymbol(), &uniform);
Olli Etuaho78ed6cd2017-08-09 16:19:00 +0300572 uniform.binding = variable.getType().getLayoutQualifier().binding;
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000573 uniform.location = variable.getType().getLayoutQualifier().location;
jchen104cdac9e2017-05-08 11:01:20 +0800574 uniform.offset = variable.getType().getLayoutQualifier().offset;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000575 return uniform;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000576}
577
Olli Etuaho19515012017-06-26 18:00:17 +0300578bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000579{
Olli Etuaho13389b62016-10-16 11:48:18 +0100580 const TIntermSequence &sequence = *(node->getSequence());
581 ASSERT(!sequence.empty());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000582
Olli Etuaho13389b62016-10-16 11:48:18 +0100583 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
584 TQualifier qualifier = typedNode.getQualifier();
585
Olli Etuahoa55102c2017-02-24 12:36:50 +0000586 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
587 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
588 IsVarying(qualifier);
589
590 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000591 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000592 return true;
Olli Etuaho13389b62016-10-16 11:48:18 +0100593 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000594
595 for (TIntermNode *variableNode : sequence)
Olli Etuaho13389b62016-10-16 11:48:18 +0100596 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000597 // The only case in which the sequence will not contain a TIntermSymbol node is
598 // initialization. It will contain a TInterBinary node in that case. Since attributes,
599 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
600 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
601 const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
Olli Etuaho34d20072017-07-18 20:07:18 +0300602 if (variable.getName().isInternal())
603 {
604 // Internal variables are not collected.
605 continue;
606 }
607
Olli Etuahoa55102c2017-02-24 12:36:50 +0000608 if (typedNode.getBasicType() == EbtInterfaceBlock)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000609 {
Jiajia Qinbc585152017-06-23 15:42:17 +0800610 if (qualifier == EvqUniform)
611 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800612 mUniformBlocks->push_back(recordInterfaceBlock(variable));
613 }
614 else if (qualifier == EvqBuffer)
615 {
616 mShaderStorageBlocks->push_back(recordInterfaceBlock(variable));
Jiajia Qinbc585152017-06-23 15:42:17 +0800617 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000618 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000619 else
620 {
621 switch (qualifier)
622 {
623 case EvqAttribute:
624 case EvqVertexIn:
625 mAttribs->push_back(recordAttribute(variable));
626 break;
627 case EvqFragmentOut:
628 mOutputVariables->push_back(recordOutputVariable(variable));
629 break;
630 case EvqUniform:
631 mUniforms->push_back(recordUniform(variable));
632 break;
633 default:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800634 if (IsVaryingIn(qualifier))
635 {
636 mInputVaryings->push_back(recordVarying(variable));
637 }
638 else
639 {
640 ASSERT(IsVaryingOut(qualifier));
641 mOutputVaryings->push_back(recordVarying(variable));
642 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000643 break;
644 }
645 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000646 }
647
Olli Etuahoa55102c2017-02-24 12:36:50 +0000648 // None of the recorded variables can have initializers, so we don't need to traverse the
649 // declarators.
650 return false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000651}
Jamie Madill23a8a432014-07-09 13:27:42 -0400652
Olli Etuaho19515012017-06-26 18:00:17 +0300653bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
Jamie Madillb547ddf2014-08-25 16:20:46 -0400654{
655 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
656 {
Jamie Madilla6f267f2014-08-27 11:44:15 -0400657 // NOTE: we do not determine static use for individual blocks of an array
658 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
659 ASSERT(blockNode);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400660
661 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
662 ASSERT(constantUnion);
663
Jamie Madilla6f267f2014-08-27 11:44:15 -0400664 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800665 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mUniformBlocks);
666 if (!namedBlock)
Jiajia Qinbc585152017-06-23 15:42:17 +0800667 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800668 namedBlock = FindVariable(interfaceBlock->name(), mShaderStorageBlocks);
Jiajia Qinbc585152017-06-23 15:42:17 +0800669 }
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800670 ASSERT(namedBlock);
671 namedBlock->staticUse = true;
672 unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
673 ASSERT(fieldIndex < namedBlock->fields.size());
674 namedBlock->fields[fieldIndex].staticUse = true;
Jamie Madillb547ddf2014-08-25 16:20:46 -0400675 return false;
676 }
677
678 return true;
679}
680
Olli Etuaho19515012017-06-26 18:00:17 +0300681} // anonymous namespace
682
683void CollectVariables(TIntermBlock *root,
684 std::vector<Attribute> *attributes,
685 std::vector<OutputVariable> *outputVariables,
686 std::vector<Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800687 std::vector<Varying> *inputVaryings,
688 std::vector<Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800689 std::vector<InterfaceBlock> *uniformBlocks,
690 std::vector<InterfaceBlock> *shaderStorageBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300691 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300692 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300693 int shaderVersion,
694 const TExtensionBehavior &extensionBehavior)
695{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800696 CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800697 outputVaryings, uniformBlocks, shaderStorageBlocks,
698 hashFunction, symbolTable, shaderVersion, extensionBehavior);
Olli Etuaho19515012017-06-26 18:00:17 +0300699 root->traverse(&collect);
700}
701
Olli Etuaho19515012017-06-26 18:00:17 +0300702} // namespace sh