blob: f48abd3ced64ec14237b0644726a5304cb777f71 [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 Madilla718c1e2014-07-02 15:31:22 -040052template <class VarT>
Jamie Madilld7b1ab52016-12-12 14:42:19 -050053VarT *FindVariable(const TString &name, std::vector<VarT> *infoList)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040054{
55 // TODO(zmo): optimize this function.
Jamie Madilla718c1e2014-07-02 15:31:22 -040056 for (size_t ii = 0; ii < infoList->size(); ++ii)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040057 {
Jamie Madill23a8a432014-07-09 13:27:42 -040058 if ((*infoList)[ii].name.c_str() == name)
Jamie Madilla718c1e2014-07-02 15:31:22 -040059 return &((*infoList)[ii]);
Zhenyao Mod2d340b2013-09-23 14:57:05 -040060 }
Jamie Madilld5512cd2014-07-10 17:50:08 -040061
Yunchao Hef81ce4a2017-04-24 10:49:17 +080062 return nullptr;
Zhenyao Mod2d340b2013-09-23 14:57:05 -040063}
Jamie Madill54ad4f82014-09-03 09:40:46 -040064
Olli Etuaho06a06f52017-07-12 12:22:15 +030065// Note that this shouldn't be called for interface blocks - static use information is collected for
66// individual fields in case of interface blocks.
67void MarkStaticallyUsed(ShaderVariable *variable)
68{
69 if (!variable->staticUse)
70 {
71 if (variable->isStruct())
72 {
73 // Conservatively assume all fields are statically used as well.
74 for (auto &field : variable->fields)
75 {
76 MarkStaticallyUsed(&field);
77 }
78 }
79 variable->staticUse = true;
80 }
81}
82
Olli Etuaho19515012017-06-26 18:00:17 +030083// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
84// and interface blocks.
85class CollectVariablesTraverser : public TIntermTraverser
86{
87 public:
88 CollectVariablesTraverser(std::vector<Attribute> *attribs,
89 std::vector<OutputVariable> *outputVariables,
90 std::vector<Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +080091 std::vector<Varying> *inputVaryings,
92 std::vector<Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +080093 std::vector<InterfaceBlock> *uniformBlocks,
94 std::vector<InterfaceBlock> *shaderStorageBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +030095 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +030096 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +030097 int shaderVersion,
98 const TExtensionBehavior &extensionBehavior);
99
100 void visitSymbol(TIntermSymbol *symbol) override;
101 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
102 bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
103
104 private:
105 void setCommonVariableProperties(const TType &type,
106 const TString &name,
107 ShaderVariable *variableOut) const;
108
109 Attribute recordAttribute(const TIntermSymbol &variable) const;
110 OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
111 Varying recordVarying(const TIntermSymbol &variable) const;
112 InterfaceBlock recordInterfaceBlock(const TIntermSymbol &variable) const;
113 Uniform recordUniform(const TIntermSymbol &variable) const;
114
115 void setBuiltInInfoFromSymbolTable(const char *name, ShaderVariable *info);
116
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800117 void recordBuiltInVaryingUsed(const char *name,
118 bool *addedFlag,
119 std::vector<Varying> *varyings);
Olli Etuaho19515012017-06-26 18:00:17 +0300120 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;
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800126 std::vector<Varying> *mInputVaryings;
127 std::vector<Varying> *mOutputVaryings;
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800128 std::vector<InterfaceBlock> *mUniformBlocks;
129 std::vector<InterfaceBlock> *mShaderStorageBlocks;
Olli Etuaho19515012017-06-26 18:00:17 +0300130
131 std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
132
133 bool mDepthRangeAdded;
134 bool mPointCoordAdded;
135 bool mFrontFacingAdded;
136 bool mFragCoordAdded;
137
138 bool mInstanceIDAdded;
139 bool mVertexIDAdded;
140 bool mPositionAdded;
141 bool mPointSizeAdded;
142 bool mLastFragDataAdded;
143 bool mFragColorAdded;
144 bool mFragDataAdded;
145 bool mFragDepthEXTAdded;
146 bool mFragDepthAdded;
147 bool mSecondaryFragColorEXTAdded;
148 bool mSecondaryFragDataEXTAdded;
149
150 ShHashFunction64 mHashFunction;
151
Olli Etuaho19515012017-06-26 18:00:17 +0300152 int mShaderVersion;
153 const TExtensionBehavior &mExtensionBehavior;
154};
155
156CollectVariablesTraverser::CollectVariablesTraverser(
157 std::vector<sh::Attribute> *attribs,
158 std::vector<sh::OutputVariable> *outputVariables,
159 std::vector<sh::Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800160 std::vector<sh::Varying> *inputVaryings,
161 std::vector<sh::Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800162 std::vector<sh::InterfaceBlock> *uniformBlocks,
163 std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300164 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300165 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300166 int shaderVersion,
167 const TExtensionBehavior &extensionBehavior)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300168 : TIntermTraverser(true, false, false, symbolTable),
Olli Etuaho3d0d9a42015-06-01 12:16:36 +0300169 mAttribs(attribs),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400170 mOutputVariables(outputVariables),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000171 mUniforms(uniforms),
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800172 mInputVaryings(inputVaryings),
173 mOutputVaryings(outputVaryings),
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800174 mUniformBlocks(uniformBlocks),
175 mShaderStorageBlocks(shaderStorageBlocks),
Jamie Madill55def582015-05-04 11:24:57 -0400176 mDepthRangeAdded(false),
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400177 mPointCoordAdded(false),
178 mFrontFacingAdded(false),
179 mFragCoordAdded(false),
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000180 mInstanceIDAdded(false),
Corentin Wallezb076add2016-01-11 16:45:46 -0500181 mVertexIDAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700182 mPositionAdded(false),
183 mPointSizeAdded(false),
Erik Dahlströmea7a2122014-11-17 16:15:57 +0100184 mLastFragDataAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300185 mFragColorAdded(false),
186 mFragDataAdded(false),
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300187 mFragDepthEXTAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300188 mFragDepthAdded(false),
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +0300189 mSecondaryFragColorEXTAdded(false),
190 mSecondaryFragDataEXTAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700191 mHashFunction(hashFunction),
Olli Etuaho19515012017-06-26 18:00:17 +0300192 mShaderVersion(shaderVersion),
Zhenyao Mof178d0b2016-07-23 06:59:00 -0700193 mExtensionBehavior(extensionBehavior)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000194{
195}
196
Olli Etuaho19515012017-06-26 18:00:17 +0300197void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
198 ShaderVariable *info)
199{
200 TVariable *symbolTableVar =
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300201 reinterpret_cast<TVariable *>(mSymbolTable->findBuiltIn(name, mShaderVersion));
Olli Etuaho19515012017-06-26 18:00:17 +0300202 ASSERT(symbolTableVar);
203 const TType &type = symbolTableVar->getType();
204
205 info->name = name;
206 info->mappedName = name;
207 info->type = GLVariableType(type);
208 info->arraySize = type.isArray() ? type.getArraySize() : 0;
209 info->precision = GLVariablePrecision(type);
210}
211
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800212void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name,
213 bool *addedFlag,
214 std::vector<Varying> *varyings)
Olli Etuaho19515012017-06-26 18:00:17 +0300215{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800216 ASSERT(varyings);
Olli Etuaho19515012017-06-26 18:00:17 +0300217 if (!(*addedFlag))
218 {
219 Varying info;
220 setBuiltInInfoFromSymbolTable(name, &info);
221 info.staticUse = true;
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300222 info.isInvariant = mSymbolTable->isVaryingInvariant(name);
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800223 varyings->push_back(info);
Olli Etuaho19515012017-06-26 18:00:17 +0300224 (*addedFlag) = true;
225 }
226}
227
228void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag)
229{
230 if (!(*addedFlag))
231 {
232 OutputVariable info;
233 setBuiltInInfoFromSymbolTable(name, &info);
234 info.staticUse = true;
235 mOutputVariables->push_back(info);
236 (*addedFlag) = true;
237 }
238}
239
240void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag)
241{
242 if (!(*addedFlag))
243 {
244 Attribute info;
245 setBuiltInInfoFromSymbolTable(name, &info);
246 info.staticUse = true;
247 info.location = -1;
248 mAttribs->push_back(info);
249 (*addedFlag) = true;
250 }
251}
252
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400253// We want to check whether a uniform/varying is statically used
254// because we only count the used ones in packing computing.
255// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
256// toward varying counting if they are statically used in a fragment
257// shader.
Olli Etuaho19515012017-06-26 18:00:17 +0300258void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000259{
Yunchao He4f285442017-04-21 12:15:49 +0800260 ASSERT(symbol != nullptr);
Olli Etuaho34d20072017-07-18 20:07:18 +0300261
262 if (symbol->getName().isInternal())
263 {
264 // Internal variables are not collected.
265 return;
266 }
267
Yunchao Hed7297bf2017-04-19 15:27:10 +0800268 ShaderVariable *var = nullptr;
Olli Etuaho34d20072017-07-18 20:07:18 +0300269 const TString &symbolName = symbol->getName().getString();
Jamie Madill4667c452014-07-08 15:02:36 -0400270
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800271 if (IsVaryingIn(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400272 {
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800273 var = FindVariable(symbolName, mInputVaryings);
274 }
275 else if (IsVaryingOut(symbol->getQualifier()))
276 {
277 var = FindVariable(symbolName, mOutputVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400278 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400279 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
280 {
281 UNREACHABLE();
282 }
Jamie Madill55def582015-05-04 11:24:57 -0400283 else if (symbolName == "gl_DepthRange")
284 {
285 ASSERT(symbol->getQualifier() == EvqUniform);
286
287 if (!mDepthRangeAdded)
288 {
289 Uniform info;
290 const char kName[] = "gl_DepthRange";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500291 info.name = kName;
292 info.mappedName = kName;
293 info.type = GL_STRUCT_ANGLEX;
294 info.arraySize = 0;
295 info.precision = GL_NONE;
296 info.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400297
298 ShaderVariable nearInfo;
299 const char kNearName[] = "near";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500300 nearInfo.name = kNearName;
301 nearInfo.mappedName = kNearName;
302 nearInfo.type = GL_FLOAT;
303 nearInfo.arraySize = 0;
304 nearInfo.precision = GL_HIGH_FLOAT;
305 nearInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400306
307 ShaderVariable farInfo;
308 const char kFarName[] = "far";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500309 farInfo.name = kFarName;
310 farInfo.mappedName = kFarName;
311 farInfo.type = GL_FLOAT;
312 farInfo.arraySize = 0;
313 farInfo.precision = GL_HIGH_FLOAT;
314 farInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400315
316 ShaderVariable diffInfo;
317 const char kDiffName[] = "diff";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500318 diffInfo.name = kDiffName;
319 diffInfo.mappedName = kDiffName;
320 diffInfo.type = GL_FLOAT;
321 diffInfo.arraySize = 0;
322 diffInfo.precision = GL_HIGH_FLOAT;
323 diffInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400324
325 info.fields.push_back(nearInfo);
326 info.fields.push_back(farInfo);
327 info.fields.push_back(diffInfo);
328
329 mUniforms->push_back(info);
330 mDepthRangeAdded = true;
331 }
332 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400333 else
Jamie Madill4667c452014-07-08 15:02:36 -0400334 {
335 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400336 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500337 case EvqAttribute:
338 case EvqVertexIn:
339 var = FindVariable(symbolName, mAttribs);
340 break;
341 case EvqFragmentOut:
342 var = FindVariable(symbolName, mOutputVariables);
343 break;
344 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400345 {
346 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
347 if (interfaceBlock)
348 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500349 InterfaceBlock *namedBlock =
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800350 FindVariable(interfaceBlock->name(), mUniformBlocks);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400351 ASSERT(namedBlock);
352 var = FindVariable(symbolName, &namedBlock->fields);
353
354 // Set static use on the parent interface block here
355 namedBlock->staticUse = true;
356 }
357 else
358 {
359 var = FindVariable(symbolName, mUniforms);
360 }
361
362 // It's an internal error to reference an undefined user uniform
Jamie Madill55def582015-05-04 11:24:57 -0400363 ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400364 }
Jamie Madill4667c452014-07-08 15:02:36 -0400365 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500366 case EvqFragCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800367 recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500368 return;
369 case EvqFrontFacing:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800370 recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500371 return;
372 case EvqPointCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800373 recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500374 return;
375 case EvqInstanceID:
Martin Radev115fc552017-07-05 17:11:06 +0300376 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
377 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
378 // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders
379 // which makes it necessary to populate the type information explicitly instead of
380 // extracting it from the symbol table.
381 if (!mInstanceIDAdded)
382 {
383 Attribute info;
384 const char kName[] = "gl_InstanceID";
385 info.name = kName;
386 info.mappedName = kName;
387 info.type = GL_INT;
388 info.arraySize = 0;
389 info.precision = GL_HIGH_INT; // Defined by spec.
390 info.staticUse = true;
391 info.location = -1;
392 mAttribs->push_back(info);
393 mInstanceIDAdded = true;
394 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500395 return;
396 case EvqVertexID:
Olli Etuaho19515012017-06-26 18:00:17 +0300397 recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500398 return;
399 case EvqPosition:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800400 recordBuiltInVaryingUsed("gl_Position", &mPositionAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500401 return;
402 case EvqPointSize:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800403 recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500404 return;
405 case EvqLastFragData:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800406 recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500407 return;
408 case EvqFragColor:
Olli Etuaho19515012017-06-26 18:00:17 +0300409 recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500410 return;
411 case EvqFragData:
412 if (!mFragDataAdded)
413 {
414 OutputVariable info;
Olli Etuaho19515012017-06-26 18:00:17 +0300415 setBuiltInInfoFromSymbolTable("gl_FragData", &info);
416 if (!::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500417 {
418 info.arraySize = 1;
419 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500420 info.staticUse = true;
421 mOutputVariables->push_back(info);
422 mFragDataAdded = true;
423 }
424 return;
425 case EvqFragDepthEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300426 recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500427 return;
428 case EvqFragDepth:
Olli Etuaho19515012017-06-26 18:00:17 +0300429 recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500430 return;
431 case EvqSecondaryFragColorEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300432 recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT",
433 &mSecondaryFragColorEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500434 return;
435 case EvqSecondaryFragDataEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300436 recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
437 &mSecondaryFragDataEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500438 return;
439 default:
440 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400441 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400442 }
443 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400444 {
Olli Etuaho06a06f52017-07-12 12:22:15 +0300445 MarkStaticallyUsed(var);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400446 }
447}
448
Olli Etuaho19515012017-06-26 18:00:17 +0300449void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
450 const TString &name,
451 ShaderVariable *variableOut) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400452{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000453 ASSERT(variableOut);
454
455 const TStructure *structure = type.getStruct();
456
457 if (!structure)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500458 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000459 variableOut->type = GLVariableType(type);
460 variableOut->precision = GLVariablePrecision(type);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500461 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000462 else
Jamie Madill23a8a432014-07-09 13:27:42 -0400463 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000464 // Note: this enum value is not exposed outside ANGLE
465 variableOut->type = GL_STRUCT_ANGLEX;
466 variableOut->structName = structure->name().c_str();
467
468 const TFieldList &fields = structure->fields();
469
470 for (TField *field : fields)
471 {
472 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
473 // ShaderVariable objects.
474 ShaderVariable fieldVariable;
475 setCommonVariableProperties(*field->type(), field->name(), &fieldVariable);
476 variableOut->fields.push_back(fieldVariable);
477 }
Jamie Madill23a8a432014-07-09 13:27:42 -0400478 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000479 variableOut->name = name.c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300480 variableOut->mappedName = HashName(name, mHashFunction).c_str();
Olli Etuahoa55102c2017-02-24 12:36:50 +0000481 variableOut->arraySize = type.getArraySize();
482}
Jamie Madill23a8a432014-07-09 13:27:42 -0400483
Olli Etuaho19515012017-06-26 18:00:17 +0300484Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400485{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000486 const TType &type = variable.getType();
Jamie Madill23a8a432014-07-09 13:27:42 -0400487 ASSERT(!type.getStruct());
488
Jamie Madilla2fbb842014-09-03 09:40:47 -0400489 Attribute attribute;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000490 setCommonVariableProperties(type, variable.getSymbol(), &attribute);
Jamie Madill23a8a432014-07-09 13:27:42 -0400491
Olli Etuahoa55102c2017-02-24 12:36:50 +0000492 attribute.location = type.getLayoutQualifier().location;
493 return attribute;
Jamie Madill23a8a432014-07-09 13:27:42 -0400494}
495
Olli Etuaho19515012017-06-26 18:00:17 +0300496OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
Jamie Madilla0a9e122015-09-02 15:54:30 -0400497{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000498 const TType &type = variable.getType();
Jamie Madilla0a9e122015-09-02 15:54:30 -0400499 ASSERT(!type.getStruct());
500
Olli Etuahoa55102c2017-02-24 12:36:50 +0000501 OutputVariable outputVariable;
502 setCommonVariableProperties(type, variable.getSymbol(), &outputVariable);
Jamie Madilla0a9e122015-09-02 15:54:30 -0400503
Olli Etuahoa55102c2017-02-24 12:36:50 +0000504 outputVariable.location = type.getLayoutQualifier().location;
505 return outputVariable;
Jamie Madilla0a9e122015-09-02 15:54:30 -0400506}
507
Olli Etuaho19515012017-06-26 18:00:17 +0300508Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
Jamie Madilld5512cd2014-07-10 17:50:08 -0400509{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000510 const TType &type = variable.getType();
511
512 Varying varying;
513 setCommonVariableProperties(type, variable.getSymbol(), &varying);
514
515 switch (type.getQualifier())
516 {
517 case EvqVaryingIn:
518 case EvqVaryingOut:
519 case EvqVertexOut:
520 case EvqSmoothOut:
521 case EvqFlatOut:
522 case EvqCentroidOut:
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300523 if (mSymbolTable->isVaryingInvariant(std::string(variable.getSymbol().c_str())) ||
Olli Etuahoa55102c2017-02-24 12:36:50 +0000524 type.isInvariant())
525 {
526 varying.isInvariant = true;
527 }
528 break;
529 default:
530 break;
531 }
532
533 varying.interpolation = GetInterpolationType(type.getQualifier());
534 return varying;
535}
536
Olli Etuaho19515012017-06-26 18:00:17 +0300537InterfaceBlock CollectVariablesTraverser::recordInterfaceBlock(const TIntermSymbol &variable) const
Olli Etuahoa55102c2017-02-24 12:36:50 +0000538{
539 const TInterfaceBlock *blockType = variable.getType().getInterfaceBlock();
Jamie Madill42bcf322014-08-25 16:20:46 -0400540 ASSERT(blockType);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400541
Olli Etuahoa55102c2017-02-24 12:36:50 +0000542 InterfaceBlock interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400543 interfaceBlock.name = blockType->name().c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300544 interfaceBlock.mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500545 interfaceBlock.instanceName =
546 (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
Olli Etuahoa55102c2017-02-24 12:36:50 +0000547 interfaceBlock.arraySize = variable.getArraySize();
Jamie Madill42bcf322014-08-25 16:20:46 -0400548 interfaceBlock.isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
jchen10af713a22017-04-19 09:10:56 +0800549 interfaceBlock.binding = blockType->blockBinding();
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500550 interfaceBlock.layout = GetBlockLayoutType(blockType->blockStorage());
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800551 interfaceBlock.blockType = GetBlockType(variable.getType().getQualifier());
Jamie Madilld5512cd2014-07-10 17:50:08 -0400552
Jamie Madilla6f267f2014-08-27 11:44:15 -0400553 // Gather field information
Jamie Madill39046162016-02-08 15:05:17 -0500554 for (const TField *field : blockType->fields())
Jamie Madill54ad4f82014-09-03 09:40:46 -0400555 {
Jamie Madill39046162016-02-08 15:05:17 -0500556 const TType &fieldType = *field->type();
Jamie Madill54ad4f82014-09-03 09:40:46 -0400557
Olli Etuahoa55102c2017-02-24 12:36:50 +0000558 InterfaceBlockField fieldVariable;
559 setCommonVariableProperties(fieldType, field->name(), &fieldVariable);
560 fieldVariable.isRowMajorLayout =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500561 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
Olli Etuahoa55102c2017-02-24 12:36:50 +0000562 interfaceBlock.fields.push_back(fieldVariable);
Jamie Madill54ad4f82014-09-03 09:40:46 -0400563 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000564 return interfaceBlock;
Jamie Madilld5512cd2014-07-10 17:50:08 -0400565}
566
Olli Etuaho19515012017-06-26 18:00:17 +0300567Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
Jamie Madill4667c452014-07-08 15:02:36 -0400568{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000569 Uniform uniform;
570 setCommonVariableProperties(variable.getType(), variable.getSymbol(), &uniform);
Olli Etuaho547cbd42017-02-27 11:54:00 +0200571 uniform.binding = variable.getType().getLayoutQualifier().binding;
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000572 uniform.location = variable.getType().getLayoutQualifier().location;
jchen104cdac9e2017-05-08 11:01:20 +0800573 uniform.offset = variable.getType().getLayoutQualifier().offset;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000574 return uniform;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000575}
576
Olli Etuaho19515012017-06-26 18:00:17 +0300577bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000578{
Olli Etuaho13389b62016-10-16 11:48:18 +0100579 const TIntermSequence &sequence = *(node->getSequence());
580 ASSERT(!sequence.empty());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000581
Olli Etuaho13389b62016-10-16 11:48:18 +0100582 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
583 TQualifier qualifier = typedNode.getQualifier();
584
Olli Etuahoa55102c2017-02-24 12:36:50 +0000585 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
586 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
587 IsVarying(qualifier);
588
589 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000590 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000591 return true;
Olli Etuaho13389b62016-10-16 11:48:18 +0100592 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000593
594 for (TIntermNode *variableNode : sequence)
Olli Etuaho13389b62016-10-16 11:48:18 +0100595 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000596 // The only case in which the sequence will not contain a TIntermSymbol node is
597 // initialization. It will contain a TInterBinary node in that case. Since attributes,
598 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
599 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
600 const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
Olli Etuaho34d20072017-07-18 20:07:18 +0300601 if (variable.getName().isInternal())
602 {
603 // Internal variables are not collected.
604 continue;
605 }
606
Olli Etuahoa55102c2017-02-24 12:36:50 +0000607 if (typedNode.getBasicType() == EbtInterfaceBlock)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000608 {
Jiajia Qinbc585152017-06-23 15:42:17 +0800609 if (qualifier == EvqUniform)
610 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800611 mUniformBlocks->push_back(recordInterfaceBlock(variable));
612 }
613 else if (qualifier == EvqBuffer)
614 {
615 mShaderStorageBlocks->push_back(recordInterfaceBlock(variable));
Jiajia Qinbc585152017-06-23 15:42:17 +0800616 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000617 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000618 else
619 {
620 switch (qualifier)
621 {
622 case EvqAttribute:
623 case EvqVertexIn:
624 mAttribs->push_back(recordAttribute(variable));
625 break;
626 case EvqFragmentOut:
627 mOutputVariables->push_back(recordOutputVariable(variable));
628 break;
629 case EvqUniform:
630 mUniforms->push_back(recordUniform(variable));
631 break;
632 default:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800633 if (IsVaryingIn(qualifier))
634 {
635 mInputVaryings->push_back(recordVarying(variable));
636 }
637 else
638 {
639 ASSERT(IsVaryingOut(qualifier));
640 mOutputVaryings->push_back(recordVarying(variable));
641 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000642 break;
643 }
644 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000645 }
646
Olli Etuahoa55102c2017-02-24 12:36:50 +0000647 // None of the recorded variables can have initializers, so we don't need to traverse the
648 // declarators.
649 return false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000650}
Jamie Madill23a8a432014-07-09 13:27:42 -0400651
Olli Etuaho19515012017-06-26 18:00:17 +0300652bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
Jamie Madillb547ddf2014-08-25 16:20:46 -0400653{
654 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
655 {
Jamie Madilla6f267f2014-08-27 11:44:15 -0400656 // NOTE: we do not determine static use for individual blocks of an array
657 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
658 ASSERT(blockNode);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400659
660 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
661 ASSERT(constantUnion);
662
Jamie Madilla6f267f2014-08-27 11:44:15 -0400663 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800664 InterfaceBlock *namedBlock = FindVariable(interfaceBlock->name(), mUniformBlocks);
665 if (!namedBlock)
Jiajia Qinbc585152017-06-23 15:42:17 +0800666 {
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800667 namedBlock = FindVariable(interfaceBlock->name(), mShaderStorageBlocks);
Jiajia Qinbc585152017-06-23 15:42:17 +0800668 }
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800669 ASSERT(namedBlock);
670 namedBlock->staticUse = true;
671 unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
672 ASSERT(fieldIndex < namedBlock->fields.size());
673 namedBlock->fields[fieldIndex].staticUse = true;
Jamie Madillb547ddf2014-08-25 16:20:46 -0400674 return false;
675 }
676
677 return true;
678}
679
Olli Etuaho19515012017-06-26 18:00:17 +0300680} // anonymous namespace
681
682void CollectVariables(TIntermBlock *root,
683 std::vector<Attribute> *attributes,
684 std::vector<OutputVariable> *outputVariables,
685 std::vector<Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800686 std::vector<Varying> *inputVaryings,
687 std::vector<Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800688 std::vector<InterfaceBlock> *uniformBlocks,
689 std::vector<InterfaceBlock> *shaderStorageBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300690 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300691 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300692 int shaderVersion,
693 const TExtensionBehavior &extensionBehavior)
694{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800695 CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800696 outputVaryings, uniformBlocks, shaderStorageBlocks,
697 hashFunction, symbolTable, shaderVersion, extensionBehavior);
Olli Etuaho19515012017-06-26 18:00:17 +0300698 root->traverse(&collect);
699}
700
Olli Etuaho19515012017-06-26 18:00:17 +0300701} // namespace sh