blob: 5815940252e2889045e619d7ed86db25f78bfffc [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
Jiawei Shaod8105a02017-08-08 09:54:36 +080039// TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
Jiajia Qin9b11ea42017-07-11 16:50:08 +080040BlockType GetBlockType(TQualifier qualifier)
41{
42 switch (qualifier)
43 {
44 case EvqUniform:
45 return BlockType::BLOCK_UNIFORM;
46 case EvqBuffer:
47 return BlockType::BLOCK_BUFFER;
Jiawei Shaod8105a02017-08-08 09:54:36 +080048 case EvqPerVertexIn:
49 return BlockType::BLOCK_IN;
Jiajia Qin9b11ea42017-07-11 16:50:08 +080050 default:
51 UNREACHABLE();
52 return BlockType::BLOCK_UNIFORM;
53 }
54}
55
Jamie Madilla718c1e2014-07-02 15:31:22 -040056template <class VarT>
Jamie Madilld7b1ab52016-12-12 14:42:19 -050057VarT *FindVariable(const TString &name, std::vector<VarT> *infoList)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040058{
59 // TODO(zmo): optimize this function.
Jamie Madilla718c1e2014-07-02 15:31:22 -040060 for (size_t ii = 0; ii < infoList->size(); ++ii)
Zhenyao Mod2d340b2013-09-23 14:57:05 -040061 {
Jamie Madill23a8a432014-07-09 13:27:42 -040062 if ((*infoList)[ii].name.c_str() == name)
Jamie Madilla718c1e2014-07-02 15:31:22 -040063 return &((*infoList)[ii]);
Zhenyao Mod2d340b2013-09-23 14:57:05 -040064 }
Jamie Madilld5512cd2014-07-10 17:50:08 -040065
Yunchao Hef81ce4a2017-04-24 10:49:17 +080066 return nullptr;
Zhenyao Mod2d340b2013-09-23 14:57:05 -040067}
Jamie Madill54ad4f82014-09-03 09:40:46 -040068
Olli Etuaho06a06f52017-07-12 12:22:15 +030069// Note that this shouldn't be called for interface blocks - static use information is collected for
70// individual fields in case of interface blocks.
71void MarkStaticallyUsed(ShaderVariable *variable)
72{
73 if (!variable->staticUse)
74 {
75 if (variable->isStruct())
76 {
77 // Conservatively assume all fields are statically used as well.
78 for (auto &field : variable->fields)
79 {
80 MarkStaticallyUsed(&field);
81 }
82 }
83 variable->staticUse = true;
84 }
85}
86
Olli Etuaho19515012017-06-26 18:00:17 +030087// Traverses the intermediate tree to collect all attributes, uniforms, varyings, fragment outputs,
88// and interface blocks.
89class CollectVariablesTraverser : public TIntermTraverser
90{
91 public:
92 CollectVariablesTraverser(std::vector<Attribute> *attribs,
93 std::vector<OutputVariable> *outputVariables,
94 std::vector<Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +080095 std::vector<Varying> *inputVaryings,
96 std::vector<Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +080097 std::vector<InterfaceBlock> *uniformBlocks,
98 std::vector<InterfaceBlock> *shaderStorageBlocks,
Jiawei Shaod8105a02017-08-08 09:54:36 +080099 std::vector<InterfaceBlock> *inBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300100 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300101 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300102 int shaderVersion,
103 const TExtensionBehavior &extensionBehavior);
104
105 void visitSymbol(TIntermSymbol *symbol) override;
106 bool visitDeclaration(Visit, TIntermDeclaration *node) override;
107 bool visitBinary(Visit visit, TIntermBinary *binaryNode) override;
108
109 private:
110 void setCommonVariableProperties(const TType &type,
111 const TString &name,
112 ShaderVariable *variableOut) const;
113
114 Attribute recordAttribute(const TIntermSymbol &variable) const;
115 OutputVariable recordOutputVariable(const TIntermSymbol &variable) const;
116 Varying recordVarying(const TIntermSymbol &variable) const;
Jiawei Shaod8105a02017-08-08 09:54:36 +0800117 void recordInterfaceBlock(const TType &interfaceBlockType,
118 InterfaceBlock *interfaceBlock) const;
Olli Etuaho19515012017-06-26 18:00:17 +0300119 Uniform recordUniform(const TIntermSymbol &variable) const;
120
121 void setBuiltInInfoFromSymbolTable(const char *name, ShaderVariable *info);
122
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800123 void recordBuiltInVaryingUsed(const char *name,
124 bool *addedFlag,
125 std::vector<Varying> *varyings);
Olli Etuaho19515012017-06-26 18:00:17 +0300126 void recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag);
127 void recordBuiltInAttributeUsed(const char *name, bool *addedFlag);
Jiawei Shaod8105a02017-08-08 09:54:36 +0800128 InterfaceBlock *recordGLInUsed(const TType &glInType);
129 InterfaceBlock *findNamedInterfaceBlock(const TString &name) const;
Olli Etuaho19515012017-06-26 18:00:17 +0300130
131 std::vector<Attribute> *mAttribs;
132 std::vector<OutputVariable> *mOutputVariables;
133 std::vector<Uniform> *mUniforms;
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800134 std::vector<Varying> *mInputVaryings;
135 std::vector<Varying> *mOutputVaryings;
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800136 std::vector<InterfaceBlock> *mUniformBlocks;
137 std::vector<InterfaceBlock> *mShaderStorageBlocks;
Jiawei Shaod8105a02017-08-08 09:54:36 +0800138 std::vector<InterfaceBlock> *mInBlocks;
Olli Etuaho19515012017-06-26 18:00:17 +0300139
140 std::map<std::string, InterfaceBlockField *> mInterfaceBlockFields;
141
142 bool mDepthRangeAdded;
143 bool mPointCoordAdded;
144 bool mFrontFacingAdded;
145 bool mFragCoordAdded;
146
147 bool mInstanceIDAdded;
148 bool mVertexIDAdded;
149 bool mPositionAdded;
150 bool mPointSizeAdded;
151 bool mLastFragDataAdded;
152 bool mFragColorAdded;
153 bool mFragDataAdded;
154 bool mFragDepthEXTAdded;
155 bool mFragDepthAdded;
156 bool mSecondaryFragColorEXTAdded;
157 bool mSecondaryFragDataEXTAdded;
158
Jiawei Shaod8105a02017-08-08 09:54:36 +0800159 bool mPerVertexInAdded;
160
Olli Etuaho19515012017-06-26 18:00:17 +0300161 ShHashFunction64 mHashFunction;
162
Olli Etuaho19515012017-06-26 18:00:17 +0300163 int mShaderVersion;
164 const TExtensionBehavior &mExtensionBehavior;
165};
166
167CollectVariablesTraverser::CollectVariablesTraverser(
168 std::vector<sh::Attribute> *attribs,
169 std::vector<sh::OutputVariable> *outputVariables,
170 std::vector<sh::Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800171 std::vector<sh::Varying> *inputVaryings,
172 std::vector<sh::Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800173 std::vector<sh::InterfaceBlock> *uniformBlocks,
174 std::vector<sh::InterfaceBlock> *shaderStorageBlocks,
Jiawei Shaod8105a02017-08-08 09:54:36 +0800175 std::vector<sh::InterfaceBlock> *inBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300176 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300177 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300178 int shaderVersion,
179 const TExtensionBehavior &extensionBehavior)
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300180 : TIntermTraverser(true, false, false, symbolTable),
Olli Etuaho3d0d9a42015-06-01 12:16:36 +0300181 mAttribs(attribs),
Jamie Madilld5512cd2014-07-10 17:50:08 -0400182 mOutputVariables(outputVariables),
daniel@transgaming.com0aa3b5a2012-11-28 19:43:24 +0000183 mUniforms(uniforms),
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800184 mInputVaryings(inputVaryings),
185 mOutputVaryings(outputVaryings),
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800186 mUniformBlocks(uniformBlocks),
187 mShaderStorageBlocks(shaderStorageBlocks),
Jiawei Shaod8105a02017-08-08 09:54:36 +0800188 mInBlocks(inBlocks),
Jamie Madill55def582015-05-04 11:24:57 -0400189 mDepthRangeAdded(false),
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400190 mPointCoordAdded(false),
191 mFrontFacingAdded(false),
192 mFragCoordAdded(false),
Gregoire Payen de La Garanderieb3dced22015-01-12 14:54:55 +0000193 mInstanceIDAdded(false),
Corentin Wallezb076add2016-01-11 16:45:46 -0500194 mVertexIDAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700195 mPositionAdded(false),
196 mPointSizeAdded(false),
Erik Dahlströmea7a2122014-11-17 16:15:57 +0100197 mLastFragDataAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300198 mFragColorAdded(false),
199 mFragDataAdded(false),
Kimmo Kinnunen5f0246c2015-07-22 10:30:35 +0300200 mFragDepthEXTAdded(false),
Kimmo Kinnunen0932df62015-07-21 14:35:11 +0300201 mFragDepthAdded(false),
Kimmo Kinnunenb18609b2015-07-16 14:13:11 +0300202 mSecondaryFragColorEXTAdded(false),
203 mSecondaryFragDataEXTAdded(false),
Jiawei Shaod8105a02017-08-08 09:54:36 +0800204 mPerVertexInAdded(false),
Zhenyao Mo94ac7b72014-10-15 18:22:08 -0700205 mHashFunction(hashFunction),
Olli Etuaho19515012017-06-26 18:00:17 +0300206 mShaderVersion(shaderVersion),
Zhenyao Mof178d0b2016-07-23 06:59:00 -0700207 mExtensionBehavior(extensionBehavior)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000208{
209}
210
Olli Etuaho19515012017-06-26 18:00:17 +0300211void CollectVariablesTraverser::setBuiltInInfoFromSymbolTable(const char *name,
212 ShaderVariable *info)
213{
214 TVariable *symbolTableVar =
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300215 reinterpret_cast<TVariable *>(mSymbolTable->findBuiltIn(name, mShaderVersion));
Olli Etuaho19515012017-06-26 18:00:17 +0300216 ASSERT(symbolTableVar);
217 const TType &type = symbolTableVar->getType();
218
219 info->name = name;
220 info->mappedName = name;
221 info->type = GLVariableType(type);
222 info->arraySize = type.isArray() ? type.getArraySize() : 0;
223 info->precision = GLVariablePrecision(type);
224}
225
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800226void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name,
227 bool *addedFlag,
228 std::vector<Varying> *varyings)
Olli Etuaho19515012017-06-26 18:00:17 +0300229{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800230 ASSERT(varyings);
Olli Etuaho19515012017-06-26 18:00:17 +0300231 if (!(*addedFlag))
232 {
233 Varying info;
234 setBuiltInInfoFromSymbolTable(name, &info);
235 info.staticUse = true;
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300236 info.isInvariant = mSymbolTable->isVaryingInvariant(name);
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800237 varyings->push_back(info);
Olli Etuaho19515012017-06-26 18:00:17 +0300238 (*addedFlag) = true;
239 }
240}
241
242void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag)
243{
244 if (!(*addedFlag))
245 {
246 OutputVariable info;
247 setBuiltInInfoFromSymbolTable(name, &info);
248 info.staticUse = true;
249 mOutputVariables->push_back(info);
250 (*addedFlag) = true;
251 }
252}
253
254void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag)
255{
256 if (!(*addedFlag))
257 {
258 Attribute info;
259 setBuiltInInfoFromSymbolTable(name, &info);
260 info.staticUse = true;
261 info.location = -1;
262 mAttribs->push_back(info);
263 (*addedFlag) = true;
264 }
265}
266
Jiawei Shaod8105a02017-08-08 09:54:36 +0800267InterfaceBlock *CollectVariablesTraverser::recordGLInUsed(const TType &glInType)
268{
269 if (!mPerVertexInAdded)
270 {
271 ASSERT(glInType.getQualifier() == EvqPerVertexIn);
272 InterfaceBlock info;
273 recordInterfaceBlock(glInType, &info);
274 info.staticUse = true;
275
276 mPerVertexInAdded = true;
277 mInBlocks->push_back(info);
278 return &mInBlocks->back();
279 }
280 else
281 {
282 return FindVariable("gl_PerVertex", mInBlocks);
283 }
284}
285
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400286// We want to check whether a uniform/varying is statically used
287// because we only count the used ones in packing computing.
288// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
289// toward varying counting if they are statically used in a fragment
290// shader.
Olli Etuaho19515012017-06-26 18:00:17 +0300291void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000292{
Yunchao He4f285442017-04-21 12:15:49 +0800293 ASSERT(symbol != nullptr);
Olli Etuaho34d20072017-07-18 20:07:18 +0300294
295 if (symbol->getName().isInternal())
296 {
297 // Internal variables are not collected.
298 return;
299 }
300
Yunchao Hed7297bf2017-04-19 15:27:10 +0800301 ShaderVariable *var = nullptr;
Olli Etuaho34d20072017-07-18 20:07:18 +0300302 const TString &symbolName = symbol->getName().getString();
Jamie Madill4667c452014-07-08 15:02:36 -0400303
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800304 if (IsVaryingIn(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400305 {
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800306 var = FindVariable(symbolName, mInputVaryings);
307 }
308 else if (IsVaryingOut(symbol->getQualifier()))
309 {
310 var = FindVariable(symbolName, mOutputVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400311 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400312 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
313 {
314 UNREACHABLE();
315 }
Jamie Madill55def582015-05-04 11:24:57 -0400316 else if (symbolName == "gl_DepthRange")
317 {
318 ASSERT(symbol->getQualifier() == EvqUniform);
319
320 if (!mDepthRangeAdded)
321 {
322 Uniform info;
323 const char kName[] = "gl_DepthRange";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500324 info.name = kName;
325 info.mappedName = kName;
326 info.type = GL_STRUCT_ANGLEX;
327 info.arraySize = 0;
328 info.precision = GL_NONE;
329 info.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400330
331 ShaderVariable nearInfo;
332 const char kNearName[] = "near";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500333 nearInfo.name = kNearName;
334 nearInfo.mappedName = kNearName;
335 nearInfo.type = GL_FLOAT;
336 nearInfo.arraySize = 0;
337 nearInfo.precision = GL_HIGH_FLOAT;
338 nearInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400339
340 ShaderVariable farInfo;
341 const char kFarName[] = "far";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500342 farInfo.name = kFarName;
343 farInfo.mappedName = kFarName;
344 farInfo.type = GL_FLOAT;
345 farInfo.arraySize = 0;
346 farInfo.precision = GL_HIGH_FLOAT;
347 farInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400348
349 ShaderVariable diffInfo;
350 const char kDiffName[] = "diff";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500351 diffInfo.name = kDiffName;
352 diffInfo.mappedName = kDiffName;
353 diffInfo.type = GL_FLOAT;
354 diffInfo.arraySize = 0;
355 diffInfo.precision = GL_HIGH_FLOAT;
356 diffInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400357
358 info.fields.push_back(nearInfo);
359 info.fields.push_back(farInfo);
360 info.fields.push_back(diffInfo);
361
362 mUniforms->push_back(info);
363 mDepthRangeAdded = true;
364 }
365 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400366 else
Jamie Madill4667c452014-07-08 15:02:36 -0400367 {
368 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400369 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500370 case EvqAttribute:
371 case EvqVertexIn:
372 var = FindVariable(symbolName, mAttribs);
373 break;
374 case EvqFragmentOut:
375 var = FindVariable(symbolName, mOutputVariables);
376 break;
377 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400378 {
379 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
380 if (interfaceBlock)
381 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500382 InterfaceBlock *namedBlock =
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800383 FindVariable(interfaceBlock->name(), mUniformBlocks);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400384 ASSERT(namedBlock);
385 var = FindVariable(symbolName, &namedBlock->fields);
386
387 // Set static use on the parent interface block here
388 namedBlock->staticUse = true;
389 }
390 else
391 {
392 var = FindVariable(symbolName, mUniforms);
393 }
394
395 // It's an internal error to reference an undefined user uniform
Jamie Madill55def582015-05-04 11:24:57 -0400396 ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400397 }
Jamie Madill4667c452014-07-08 15:02:36 -0400398 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500399 case EvqFragCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800400 recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500401 return;
402 case EvqFrontFacing:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800403 recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500404 return;
405 case EvqPointCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800406 recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500407 return;
408 case EvqInstanceID:
Martin Radev115fc552017-07-05 17:11:06 +0300409 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
410 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
411 // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders
412 // which makes it necessary to populate the type information explicitly instead of
413 // extracting it from the symbol table.
414 if (!mInstanceIDAdded)
415 {
416 Attribute info;
417 const char kName[] = "gl_InstanceID";
418 info.name = kName;
419 info.mappedName = kName;
420 info.type = GL_INT;
421 info.arraySize = 0;
422 info.precision = GL_HIGH_INT; // Defined by spec.
423 info.staticUse = true;
424 info.location = -1;
425 mAttribs->push_back(info);
426 mInstanceIDAdded = true;
427 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500428 return;
429 case EvqVertexID:
Olli Etuaho19515012017-06-26 18:00:17 +0300430 recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500431 return;
432 case EvqPosition:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800433 recordBuiltInVaryingUsed("gl_Position", &mPositionAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500434 return;
435 case EvqPointSize:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800436 recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500437 return;
438 case EvqLastFragData:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800439 recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500440 return;
441 case EvqFragColor:
Olli Etuaho19515012017-06-26 18:00:17 +0300442 recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500443 return;
444 case EvqFragData:
445 if (!mFragDataAdded)
446 {
447 OutputVariable info;
Olli Etuaho19515012017-06-26 18:00:17 +0300448 setBuiltInInfoFromSymbolTable("gl_FragData", &info);
449 if (!::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500450 {
451 info.arraySize = 1;
452 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500453 info.staticUse = true;
454 mOutputVariables->push_back(info);
455 mFragDataAdded = true;
456 }
457 return;
458 case EvqFragDepthEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300459 recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500460 return;
461 case EvqFragDepth:
Olli Etuaho19515012017-06-26 18:00:17 +0300462 recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500463 return;
464 case EvqSecondaryFragColorEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300465 recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT",
466 &mSecondaryFragColorEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500467 return;
468 case EvqSecondaryFragDataEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300469 recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
470 &mSecondaryFragDataEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500471 return;
472 default:
473 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400474 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400475 }
476 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400477 {
Olli Etuaho06a06f52017-07-12 12:22:15 +0300478 MarkStaticallyUsed(var);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400479 }
480}
481
Olli Etuaho19515012017-06-26 18:00:17 +0300482void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
483 const TString &name,
484 ShaderVariable *variableOut) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400485{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000486 ASSERT(variableOut);
487
488 const TStructure *structure = type.getStruct();
489
490 if (!structure)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500491 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000492 variableOut->type = GLVariableType(type);
493 variableOut->precision = GLVariablePrecision(type);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500494 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000495 else
Jamie Madill23a8a432014-07-09 13:27:42 -0400496 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000497 // Note: this enum value is not exposed outside ANGLE
498 variableOut->type = GL_STRUCT_ANGLEX;
499 variableOut->structName = structure->name().c_str();
500
501 const TFieldList &fields = structure->fields();
502
503 for (TField *field : fields)
504 {
505 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
506 // ShaderVariable objects.
507 ShaderVariable fieldVariable;
508 setCommonVariableProperties(*field->type(), field->name(), &fieldVariable);
509 variableOut->fields.push_back(fieldVariable);
510 }
Jamie Madill23a8a432014-07-09 13:27:42 -0400511 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000512 variableOut->name = name.c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300513 variableOut->mappedName = HashName(name, mHashFunction).c_str();
Olli Etuahoa55102c2017-02-24 12:36:50 +0000514 variableOut->arraySize = type.getArraySize();
515}
Jamie Madill23a8a432014-07-09 13:27:42 -0400516
Olli Etuaho19515012017-06-26 18:00:17 +0300517Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400518{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000519 const TType &type = variable.getType();
Jamie Madill23a8a432014-07-09 13:27:42 -0400520 ASSERT(!type.getStruct());
521
Jamie Madilla2fbb842014-09-03 09:40:47 -0400522 Attribute attribute;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000523 setCommonVariableProperties(type, variable.getSymbol(), &attribute);
Jamie Madill23a8a432014-07-09 13:27:42 -0400524
Olli Etuahoa55102c2017-02-24 12:36:50 +0000525 attribute.location = type.getLayoutQualifier().location;
526 return attribute;
Jamie Madill23a8a432014-07-09 13:27:42 -0400527}
528
Olli Etuaho19515012017-06-26 18:00:17 +0300529OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
Jamie Madilla0a9e122015-09-02 15:54:30 -0400530{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000531 const TType &type = variable.getType();
Jamie Madilla0a9e122015-09-02 15:54:30 -0400532 ASSERT(!type.getStruct());
533
Olli Etuahoa55102c2017-02-24 12:36:50 +0000534 OutputVariable outputVariable;
535 setCommonVariableProperties(type, variable.getSymbol(), &outputVariable);
Jamie Madilla0a9e122015-09-02 15:54:30 -0400536
Olli Etuahoa55102c2017-02-24 12:36:50 +0000537 outputVariable.location = type.getLayoutQualifier().location;
538 return outputVariable;
Jamie Madilla0a9e122015-09-02 15:54:30 -0400539}
540
Olli Etuaho19515012017-06-26 18:00:17 +0300541Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
Jamie Madilld5512cd2014-07-10 17:50:08 -0400542{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000543 const TType &type = variable.getType();
544
545 Varying varying;
546 setCommonVariableProperties(type, variable.getSymbol(), &varying);
547
548 switch (type.getQualifier())
549 {
550 case EvqVaryingIn:
551 case EvqVaryingOut:
552 case EvqVertexOut:
553 case EvqSmoothOut:
554 case EvqFlatOut:
555 case EvqCentroidOut:
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300556 if (mSymbolTable->isVaryingInvariant(std::string(variable.getSymbol().c_str())) ||
Olli Etuahoa55102c2017-02-24 12:36:50 +0000557 type.isInvariant())
558 {
559 varying.isInvariant = true;
560 }
561 break;
562 default:
563 break;
564 }
565
566 varying.interpolation = GetInterpolationType(type.getQualifier());
567 return varying;
568}
569
Jiawei Shaod8105a02017-08-08 09:54:36 +0800570// TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
571void CollectVariablesTraverser::recordInterfaceBlock(const TType &interfaceBlockType,
572 InterfaceBlock *interfaceBlock) const
Olli Etuahoa55102c2017-02-24 12:36:50 +0000573{
Jiawei Shaod8105a02017-08-08 09:54:36 +0800574 ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);
575 ASSERT(interfaceBlock);
576
577 const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
Jamie Madill42bcf322014-08-25 16:20:46 -0400578 ASSERT(blockType);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400579
Jiawei Shaod8105a02017-08-08 09:54:36 +0800580 interfaceBlock->name = blockType->name().c_str();
581 interfaceBlock->mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
582 interfaceBlock->instanceName =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500583 (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
Jiawei Shaod8105a02017-08-08 09:54:36 +0800584 interfaceBlock->arraySize = interfaceBlockType.getArraySize();
585
586 interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
587 if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
588 interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
589 {
590 interfaceBlock->isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
591 interfaceBlock->binding = blockType->blockBinding();
592 interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage());
593 }
Jamie Madilld5512cd2014-07-10 17:50:08 -0400594
Jamie Madilla6f267f2014-08-27 11:44:15 -0400595 // Gather field information
Jamie Madill39046162016-02-08 15:05:17 -0500596 for (const TField *field : blockType->fields())
Jamie Madill54ad4f82014-09-03 09:40:46 -0400597 {
Jamie Madill39046162016-02-08 15:05:17 -0500598 const TType &fieldType = *field->type();
Jamie Madill54ad4f82014-09-03 09:40:46 -0400599
Olli Etuahoa55102c2017-02-24 12:36:50 +0000600 InterfaceBlockField fieldVariable;
601 setCommonVariableProperties(fieldType, field->name(), &fieldVariable);
602 fieldVariable.isRowMajorLayout =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500603 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
Jiawei Shaod8105a02017-08-08 09:54:36 +0800604 interfaceBlock->fields.push_back(fieldVariable);
Jamie Madill54ad4f82014-09-03 09:40:46 -0400605 }
Jamie Madilld5512cd2014-07-10 17:50:08 -0400606}
607
Olli Etuaho19515012017-06-26 18:00:17 +0300608Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
Jamie Madill4667c452014-07-08 15:02:36 -0400609{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000610 Uniform uniform;
611 setCommonVariableProperties(variable.getType(), variable.getSymbol(), &uniform);
Olli Etuaho78ed6cd2017-08-09 16:19:00 +0300612 uniform.binding = variable.getType().getLayoutQualifier().binding;
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000613 uniform.location = variable.getType().getLayoutQualifier().location;
jchen104cdac9e2017-05-08 11:01:20 +0800614 uniform.offset = variable.getType().getLayoutQualifier().offset;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000615 return uniform;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000616}
617
Olli Etuaho19515012017-06-26 18:00:17 +0300618bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000619{
Olli Etuaho13389b62016-10-16 11:48:18 +0100620 const TIntermSequence &sequence = *(node->getSequence());
621 ASSERT(!sequence.empty());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000622
Olli Etuaho13389b62016-10-16 11:48:18 +0100623 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
624 TQualifier qualifier = typedNode.getQualifier();
625
Olli Etuahoa55102c2017-02-24 12:36:50 +0000626 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
627 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
628 IsVarying(qualifier);
629
630 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000631 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000632 return true;
Olli Etuaho13389b62016-10-16 11:48:18 +0100633 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000634
635 for (TIntermNode *variableNode : sequence)
Olli Etuaho13389b62016-10-16 11:48:18 +0100636 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000637 // The only case in which the sequence will not contain a TIntermSymbol node is
638 // initialization. It will contain a TInterBinary node in that case. Since attributes,
639 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
640 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
641 const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
Olli Etuaho34d20072017-07-18 20:07:18 +0300642 if (variable.getName().isInternal())
643 {
644 // Internal variables are not collected.
645 continue;
646 }
647
Jiawei Shaod8105a02017-08-08 09:54:36 +0800648 // TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
Olli Etuahoa55102c2017-02-24 12:36:50 +0000649 if (typedNode.getBasicType() == EbtInterfaceBlock)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000650 {
Jiawei Shaod8105a02017-08-08 09:54:36 +0800651 InterfaceBlock interfaceBlock;
652 recordInterfaceBlock(variable.getType(), &interfaceBlock);
653
654 switch (qualifier)
Jiajia Qinbc585152017-06-23 15:42:17 +0800655 {
Jiawei Shaod8105a02017-08-08 09:54:36 +0800656 case EvqUniform:
657 mUniformBlocks->push_back(interfaceBlock);
658 break;
659 case EvqBuffer:
660 mShaderStorageBlocks->push_back(interfaceBlock);
661 break;
662 default:
663 UNREACHABLE();
Jiajia Qinbc585152017-06-23 15:42:17 +0800664 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000665 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000666 else
667 {
668 switch (qualifier)
669 {
670 case EvqAttribute:
671 case EvqVertexIn:
672 mAttribs->push_back(recordAttribute(variable));
673 break;
674 case EvqFragmentOut:
675 mOutputVariables->push_back(recordOutputVariable(variable));
676 break;
677 case EvqUniform:
678 mUniforms->push_back(recordUniform(variable));
679 break;
680 default:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800681 if (IsVaryingIn(qualifier))
682 {
683 mInputVaryings->push_back(recordVarying(variable));
684 }
685 else
686 {
687 ASSERT(IsVaryingOut(qualifier));
688 mOutputVaryings->push_back(recordVarying(variable));
689 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000690 break;
691 }
692 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000693 }
694
Olli Etuahoa55102c2017-02-24 12:36:50 +0000695 // None of the recorded variables can have initializers, so we don't need to traverse the
696 // declarators.
697 return false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000698}
Jamie Madill23a8a432014-07-09 13:27:42 -0400699
Jiawei Shaod8105a02017-08-08 09:54:36 +0800700// TODO(jiawei.shao@intel.com): add search on mInBlocks and mOutBlocks when implementing
701// GL_OES_shader_io_blocks.
702InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(const TString &blockName) const
703{
704 InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);
705 if (!namedBlock)
706 {
707 namedBlock = FindVariable(blockName, mShaderStorageBlocks);
708 }
709 return namedBlock;
710}
711
Olli Etuaho19515012017-06-26 18:00:17 +0300712bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
Jamie Madillb547ddf2014-08-25 16:20:46 -0400713{
714 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
715 {
Jamie Madilla6f267f2014-08-27 11:44:15 -0400716 // NOTE: we do not determine static use for individual blocks of an array
717 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
718 ASSERT(blockNode);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400719
720 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
721 ASSERT(constantUnion);
722
Jiawei Shaod8105a02017-08-08 09:54:36 +0800723 InterfaceBlock *namedBlock = nullptr;
724
725 bool traverseIndexExpression = false;
726 TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();
727 if (interfaceIndexingNode)
728 {
729 TIntermTyped *interfaceNode = interfaceIndexingNode->getLeft()->getAsTyped();
730 ASSERT(interfaceNode);
731
732 const TType &interfaceType = interfaceNode->getType();
733 if (interfaceType.getQualifier() == EvqPerVertexIn)
734 {
735 namedBlock = recordGLInUsed(interfaceType);
736 ASSERT(namedBlock);
737
738 // We need to continue traversing to collect useful variables in the index
739 // expression of gl_in.
740 traverseIndexExpression = true;
741 }
742 }
743
Jamie Madilla6f267f2014-08-27 11:44:15 -0400744 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800745 if (!namedBlock)
Jiajia Qinbc585152017-06-23 15:42:17 +0800746 {
Jiawei Shaod8105a02017-08-08 09:54:36 +0800747 namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
Jiajia Qinbc585152017-06-23 15:42:17 +0800748 }
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800749 ASSERT(namedBlock);
750 namedBlock->staticUse = true;
751 unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
752 ASSERT(fieldIndex < namedBlock->fields.size());
753 namedBlock->fields[fieldIndex].staticUse = true;
Jiawei Shaod8105a02017-08-08 09:54:36 +0800754
755 if (traverseIndexExpression)
756 {
757 ASSERT(interfaceIndexingNode);
758 interfaceIndexingNode->getRight()->traverse(this);
759 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400760 return false;
761 }
762
763 return true;
764}
765
Olli Etuaho19515012017-06-26 18:00:17 +0300766} // anonymous namespace
767
768void CollectVariables(TIntermBlock *root,
769 std::vector<Attribute> *attributes,
770 std::vector<OutputVariable> *outputVariables,
771 std::vector<Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800772 std::vector<Varying> *inputVaryings,
773 std::vector<Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800774 std::vector<InterfaceBlock> *uniformBlocks,
775 std::vector<InterfaceBlock> *shaderStorageBlocks,
Jiawei Shaod8105a02017-08-08 09:54:36 +0800776 std::vector<InterfaceBlock> *inBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300777 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300778 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300779 int shaderVersion,
780 const TExtensionBehavior &extensionBehavior)
781{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800782 CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
Jiawei Shaod8105a02017-08-08 09:54:36 +0800783 outputVaryings, uniformBlocks, shaderStorageBlocks, inBlocks,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800784 hashFunction, symbolTable, shaderVersion, extensionBehavior);
Olli Etuaho19515012017-06-26 18:00:17 +0300785 root->traverse(&collect);
786}
787
Olli Etuaho19515012017-06-26 18:00:17 +0300788} // namespace sh