blob: abe4592cbf27e1eb13f73c64ab4c4fb3166d3bf4 [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);
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300222 ASSERT(!type.isArrayOfArrays());
223 info->arraySize = type.isArray() ? type.getOutermostArraySize() : 0;
224 info->precision = GLVariablePrecision(type);
Olli Etuaho19515012017-06-26 18:00:17 +0300225}
226
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800227void CollectVariablesTraverser::recordBuiltInVaryingUsed(const char *name,
228 bool *addedFlag,
229 std::vector<Varying> *varyings)
Olli Etuaho19515012017-06-26 18:00:17 +0300230{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800231 ASSERT(varyings);
Olli Etuaho19515012017-06-26 18:00:17 +0300232 if (!(*addedFlag))
233 {
234 Varying info;
235 setBuiltInInfoFromSymbolTable(name, &info);
236 info.staticUse = true;
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300237 info.isInvariant = mSymbolTable->isVaryingInvariant(name);
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800238 varyings->push_back(info);
Olli Etuaho19515012017-06-26 18:00:17 +0300239 (*addedFlag) = true;
240 }
241}
242
243void CollectVariablesTraverser::recordBuiltInFragmentOutputUsed(const char *name, bool *addedFlag)
244{
245 if (!(*addedFlag))
246 {
247 OutputVariable info;
248 setBuiltInInfoFromSymbolTable(name, &info);
249 info.staticUse = true;
250 mOutputVariables->push_back(info);
251 (*addedFlag) = true;
252 }
253}
254
255void CollectVariablesTraverser::recordBuiltInAttributeUsed(const char *name, bool *addedFlag)
256{
257 if (!(*addedFlag))
258 {
259 Attribute info;
260 setBuiltInInfoFromSymbolTable(name, &info);
261 info.staticUse = true;
262 info.location = -1;
263 mAttribs->push_back(info);
264 (*addedFlag) = true;
265 }
266}
267
Jiawei Shaod8105a02017-08-08 09:54:36 +0800268InterfaceBlock *CollectVariablesTraverser::recordGLInUsed(const TType &glInType)
269{
270 if (!mPerVertexInAdded)
271 {
272 ASSERT(glInType.getQualifier() == EvqPerVertexIn);
273 InterfaceBlock info;
274 recordInterfaceBlock(glInType, &info);
275 info.staticUse = true;
276
277 mPerVertexInAdded = true;
278 mInBlocks->push_back(info);
279 return &mInBlocks->back();
280 }
281 else
282 {
283 return FindVariable("gl_PerVertex", mInBlocks);
284 }
285}
286
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400287// We want to check whether a uniform/varying is statically used
288// because we only count the used ones in packing computing.
289// Also, gl_FragCoord, gl_PointCoord, and gl_FrontFacing count
290// toward varying counting if they are statically used in a fragment
291// shader.
Olli Etuaho19515012017-06-26 18:00:17 +0300292void CollectVariablesTraverser::visitSymbol(TIntermSymbol *symbol)
alokp@chromium.org07620a52010-09-23 17:53:56 +0000293{
Yunchao He4f285442017-04-21 12:15:49 +0800294 ASSERT(symbol != nullptr);
Olli Etuaho34d20072017-07-18 20:07:18 +0300295
296 if (symbol->getName().isInternal())
297 {
298 // Internal variables are not collected.
299 return;
300 }
301
Yunchao Hed7297bf2017-04-19 15:27:10 +0800302 ShaderVariable *var = nullptr;
Olli Etuaho34d20072017-07-18 20:07:18 +0300303 const TString &symbolName = symbol->getName().getString();
Jamie Madill4667c452014-07-08 15:02:36 -0400304
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800305 if (IsVaryingIn(symbol->getQualifier()))
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400306 {
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800307 var = FindVariable(symbolName, mInputVaryings);
308 }
309 else if (IsVaryingOut(symbol->getQualifier()))
310 {
311 var = FindVariable(symbolName, mOutputVaryings);
Jamie Madill4667c452014-07-08 15:02:36 -0400312 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400313 else if (symbol->getType().getBasicType() == EbtInterfaceBlock)
314 {
315 UNREACHABLE();
316 }
Jamie Madill55def582015-05-04 11:24:57 -0400317 else if (symbolName == "gl_DepthRange")
318 {
319 ASSERT(symbol->getQualifier() == EvqUniform);
320
321 if (!mDepthRangeAdded)
322 {
323 Uniform info;
324 const char kName[] = "gl_DepthRange";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500325 info.name = kName;
326 info.mappedName = kName;
327 info.type = GL_STRUCT_ANGLEX;
328 info.arraySize = 0;
329 info.precision = GL_NONE;
330 info.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400331
332 ShaderVariable nearInfo;
333 const char kNearName[] = "near";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500334 nearInfo.name = kNearName;
335 nearInfo.mappedName = kNearName;
336 nearInfo.type = GL_FLOAT;
337 nearInfo.arraySize = 0;
338 nearInfo.precision = GL_HIGH_FLOAT;
339 nearInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400340
341 ShaderVariable farInfo;
342 const char kFarName[] = "far";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500343 farInfo.name = kFarName;
344 farInfo.mappedName = kFarName;
345 farInfo.type = GL_FLOAT;
346 farInfo.arraySize = 0;
347 farInfo.precision = GL_HIGH_FLOAT;
348 farInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400349
350 ShaderVariable diffInfo;
351 const char kDiffName[] = "diff";
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500352 diffInfo.name = kDiffName;
353 diffInfo.mappedName = kDiffName;
354 diffInfo.type = GL_FLOAT;
355 diffInfo.arraySize = 0;
356 diffInfo.precision = GL_HIGH_FLOAT;
357 diffInfo.staticUse = true;
Jamie Madill55def582015-05-04 11:24:57 -0400358
359 info.fields.push_back(nearInfo);
360 info.fields.push_back(farInfo);
361 info.fields.push_back(diffInfo);
362
363 mUniforms->push_back(info);
364 mDepthRangeAdded = true;
365 }
366 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400367 else
Jamie Madill4667c452014-07-08 15:02:36 -0400368 {
369 switch (symbol->getQualifier())
Jamie Madilla718c1e2014-07-02 15:31:22 -0400370 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500371 case EvqAttribute:
372 case EvqVertexIn:
373 var = FindVariable(symbolName, mAttribs);
374 break;
375 case EvqFragmentOut:
376 var = FindVariable(symbolName, mOutputVariables);
377 break;
378 case EvqUniform:
Jamie Madilld5512cd2014-07-10 17:50:08 -0400379 {
380 const TInterfaceBlock *interfaceBlock = symbol->getType().getInterfaceBlock();
381 if (interfaceBlock)
382 {
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500383 InterfaceBlock *namedBlock =
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800384 FindVariable(interfaceBlock->name(), mUniformBlocks);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400385 ASSERT(namedBlock);
386 var = FindVariable(symbolName, &namedBlock->fields);
387
388 // Set static use on the parent interface block here
389 namedBlock->staticUse = true;
390 }
391 else
392 {
393 var = FindVariable(symbolName, mUniforms);
394 }
395
396 // It's an internal error to reference an undefined user uniform
Jamie Madill55def582015-05-04 11:24:57 -0400397 ASSERT(symbolName.compare(0, 3, "gl_") != 0 || var);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400398 }
Jamie Madill4667c452014-07-08 15:02:36 -0400399 break;
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500400 case EvqFragCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800401 recordBuiltInVaryingUsed("gl_FragCoord", &mFragCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500402 return;
403 case EvqFrontFacing:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800404 recordBuiltInVaryingUsed("gl_FrontFacing", &mFrontFacingAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500405 return;
406 case EvqPointCoord:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800407 recordBuiltInVaryingUsed("gl_PointCoord", &mPointCoordAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500408 return;
409 case EvqInstanceID:
Martin Radev115fc552017-07-05 17:11:06 +0300410 // Whenever the SH_INITIALIZE_BUILTINS_FOR_INSTANCED_MULTIVIEW option is set,
411 // gl_InstanceID is added inside expressions to initialize ViewID_OVR and
412 // InstanceID. gl_InstanceID is not added to the symbol table for ESSL1 shaders
413 // which makes it necessary to populate the type information explicitly instead of
414 // extracting it from the symbol table.
415 if (!mInstanceIDAdded)
416 {
417 Attribute info;
418 const char kName[] = "gl_InstanceID";
419 info.name = kName;
420 info.mappedName = kName;
421 info.type = GL_INT;
422 info.arraySize = 0;
423 info.precision = GL_HIGH_INT; // Defined by spec.
424 info.staticUse = true;
425 info.location = -1;
426 mAttribs->push_back(info);
427 mInstanceIDAdded = true;
428 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500429 return;
430 case EvqVertexID:
Olli Etuaho19515012017-06-26 18:00:17 +0300431 recordBuiltInAttributeUsed("gl_VertexID", &mVertexIDAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500432 return;
433 case EvqPosition:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800434 recordBuiltInVaryingUsed("gl_Position", &mPositionAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500435 return;
436 case EvqPointSize:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800437 recordBuiltInVaryingUsed("gl_PointSize", &mPointSizeAdded, mOutputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500438 return;
439 case EvqLastFragData:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800440 recordBuiltInVaryingUsed("gl_LastFragData", &mLastFragDataAdded, mInputVaryings);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500441 return;
442 case EvqFragColor:
Olli Etuaho19515012017-06-26 18:00:17 +0300443 recordBuiltInFragmentOutputUsed("gl_FragColor", &mFragColorAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500444 return;
445 case EvqFragData:
446 if (!mFragDataAdded)
447 {
448 OutputVariable info;
Olli Etuaho19515012017-06-26 18:00:17 +0300449 setBuiltInInfoFromSymbolTable("gl_FragData", &info);
450 if (!::IsExtensionEnabled(mExtensionBehavior, "GL_EXT_draw_buffers"))
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500451 {
452 info.arraySize = 1;
453 }
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500454 info.staticUse = true;
455 mOutputVariables->push_back(info);
456 mFragDataAdded = true;
457 }
458 return;
459 case EvqFragDepthEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300460 recordBuiltInFragmentOutputUsed("gl_FragDepthEXT", &mFragDepthEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500461 return;
462 case EvqFragDepth:
Olli Etuaho19515012017-06-26 18:00:17 +0300463 recordBuiltInFragmentOutputUsed("gl_FragDepth", &mFragDepthAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500464 return;
465 case EvqSecondaryFragColorEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300466 recordBuiltInFragmentOutputUsed("gl_SecondaryFragColorEXT",
467 &mSecondaryFragColorEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500468 return;
469 case EvqSecondaryFragDataEXT:
Olli Etuaho19515012017-06-26 18:00:17 +0300470 recordBuiltInFragmentOutputUsed("gl_SecondaryFragDataEXT",
471 &mSecondaryFragDataEXTAdded);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500472 return;
473 default:
474 break;
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400475 }
Zhenyao Mod2d340b2013-09-23 14:57:05 -0400476 }
477 if (var)
Jamie Madilla718c1e2014-07-02 15:31:22 -0400478 {
Olli Etuaho06a06f52017-07-12 12:22:15 +0300479 MarkStaticallyUsed(var);
Jamie Madilla718c1e2014-07-02 15:31:22 -0400480 }
481}
482
Olli Etuaho19515012017-06-26 18:00:17 +0300483void CollectVariablesTraverser::setCommonVariableProperties(const TType &type,
484 const TString &name,
485 ShaderVariable *variableOut) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400486{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000487 ASSERT(variableOut);
488
489 const TStructure *structure = type.getStruct();
490
491 if (!structure)
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500492 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000493 variableOut->type = GLVariableType(type);
494 variableOut->precision = GLVariablePrecision(type);
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500495 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000496 else
Jamie Madill23a8a432014-07-09 13:27:42 -0400497 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000498 // Note: this enum value is not exposed outside ANGLE
499 variableOut->type = GL_STRUCT_ANGLEX;
500 variableOut->structName = structure->name().c_str();
501
502 const TFieldList &fields = structure->fields();
503
504 for (TField *field : fields)
505 {
506 // Regardless of the variable type (uniform, in/out etc.) its fields are always plain
507 // ShaderVariable objects.
508 ShaderVariable fieldVariable;
509 setCommonVariableProperties(*field->type(), field->name(), &fieldVariable);
510 variableOut->fields.push_back(fieldVariable);
511 }
Jamie Madill23a8a432014-07-09 13:27:42 -0400512 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000513 variableOut->name = name.c_str();
Olli Etuahocccf2b02017-07-05 14:50:54 +0300514 variableOut->mappedName = HashName(name, mHashFunction).c_str();
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300515
516 // TODO(oetuaho@nvidia.com): Uniforms can be arrays of arrays, so this assert will need to be
517 // removed.
518 ASSERT(!type.isArrayOfArrays());
519 variableOut->arraySize = type.isArray() ? type.getOutermostArraySize() : 0;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000520}
Jamie Madill23a8a432014-07-09 13:27:42 -0400521
Olli Etuaho19515012017-06-26 18:00:17 +0300522Attribute CollectVariablesTraverser::recordAttribute(const TIntermSymbol &variable) const
Jamie Madill23a8a432014-07-09 13:27:42 -0400523{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000524 const TType &type = variable.getType();
Jamie Madill23a8a432014-07-09 13:27:42 -0400525 ASSERT(!type.getStruct());
526
Jamie Madilla2fbb842014-09-03 09:40:47 -0400527 Attribute attribute;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000528 setCommonVariableProperties(type, variable.getSymbol(), &attribute);
Jamie Madill23a8a432014-07-09 13:27:42 -0400529
Olli Etuahoa55102c2017-02-24 12:36:50 +0000530 attribute.location = type.getLayoutQualifier().location;
531 return attribute;
Jamie Madill23a8a432014-07-09 13:27:42 -0400532}
533
Olli Etuaho19515012017-06-26 18:00:17 +0300534OutputVariable CollectVariablesTraverser::recordOutputVariable(const TIntermSymbol &variable) const
Jamie Madilla0a9e122015-09-02 15:54:30 -0400535{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000536 const TType &type = variable.getType();
Jamie Madilla0a9e122015-09-02 15:54:30 -0400537 ASSERT(!type.getStruct());
538
Olli Etuahoa55102c2017-02-24 12:36:50 +0000539 OutputVariable outputVariable;
540 setCommonVariableProperties(type, variable.getSymbol(), &outputVariable);
Jamie Madilla0a9e122015-09-02 15:54:30 -0400541
Olli Etuahoa55102c2017-02-24 12:36:50 +0000542 outputVariable.location = type.getLayoutQualifier().location;
543 return outputVariable;
Jamie Madilla0a9e122015-09-02 15:54:30 -0400544}
545
Olli Etuaho19515012017-06-26 18:00:17 +0300546Varying CollectVariablesTraverser::recordVarying(const TIntermSymbol &variable) const
Jamie Madilld5512cd2014-07-10 17:50:08 -0400547{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000548 const TType &type = variable.getType();
549
550 Varying varying;
551 setCommonVariableProperties(type, variable.getSymbol(), &varying);
552
553 switch (type.getQualifier())
554 {
555 case EvqVaryingIn:
556 case EvqVaryingOut:
557 case EvqVertexOut:
558 case EvqSmoothOut:
559 case EvqFlatOut:
560 case EvqCentroidOut:
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300561 if (mSymbolTable->isVaryingInvariant(std::string(variable.getSymbol().c_str())) ||
Olli Etuahoa55102c2017-02-24 12:36:50 +0000562 type.isInvariant())
563 {
564 varying.isInvariant = true;
565 }
566 break;
567 default:
568 break;
569 }
570
571 varying.interpolation = GetInterpolationType(type.getQualifier());
572 return varying;
573}
574
Jiawei Shaod8105a02017-08-08 09:54:36 +0800575// TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
576void CollectVariablesTraverser::recordInterfaceBlock(const TType &interfaceBlockType,
577 InterfaceBlock *interfaceBlock) const
Olli Etuahoa55102c2017-02-24 12:36:50 +0000578{
Jiawei Shaod8105a02017-08-08 09:54:36 +0800579 ASSERT(interfaceBlockType.getBasicType() == EbtInterfaceBlock);
580 ASSERT(interfaceBlock);
581
582 const TInterfaceBlock *blockType = interfaceBlockType.getInterfaceBlock();
Jamie Madill42bcf322014-08-25 16:20:46 -0400583 ASSERT(blockType);
Jamie Madilld5512cd2014-07-10 17:50:08 -0400584
Jiawei Shaod8105a02017-08-08 09:54:36 +0800585 interfaceBlock->name = blockType->name().c_str();
586 interfaceBlock->mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
587 interfaceBlock->instanceName =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500588 (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
Olli Etuaho96f6adf2017-08-16 11:18:54 +0300589 ASSERT(!interfaceBlockType.isArrayOfArrays()); // Disallowed by GLSL ES 3.10 section 4.3.9
590 interfaceBlock->arraySize = interfaceBlockType.isArray() ? interfaceBlockType.getOutermostArraySize() : 0;
Jiawei Shaod8105a02017-08-08 09:54:36 +0800591
592 interfaceBlock->blockType = GetBlockType(interfaceBlockType.getQualifier());
593 if (interfaceBlock->blockType == BlockType::BLOCK_UNIFORM ||
594 interfaceBlock->blockType == BlockType::BLOCK_BUFFER)
595 {
596 interfaceBlock->isRowMajorLayout = (blockType->matrixPacking() == EmpRowMajor);
597 interfaceBlock->binding = blockType->blockBinding();
598 interfaceBlock->layout = GetBlockLayoutType(blockType->blockStorage());
599 }
Jamie Madilld5512cd2014-07-10 17:50:08 -0400600
Jamie Madilla6f267f2014-08-27 11:44:15 -0400601 // Gather field information
Jamie Madill39046162016-02-08 15:05:17 -0500602 for (const TField *field : blockType->fields())
Jamie Madill54ad4f82014-09-03 09:40:46 -0400603 {
Jamie Madill39046162016-02-08 15:05:17 -0500604 const TType &fieldType = *field->type();
Jamie Madill54ad4f82014-09-03 09:40:46 -0400605
Olli Etuahoa55102c2017-02-24 12:36:50 +0000606 InterfaceBlockField fieldVariable;
607 setCommonVariableProperties(fieldType, field->name(), &fieldVariable);
608 fieldVariable.isRowMajorLayout =
Jamie Madilld7b1ab52016-12-12 14:42:19 -0500609 (fieldType.getLayoutQualifier().matrixPacking == EmpRowMajor);
Jiawei Shaod8105a02017-08-08 09:54:36 +0800610 interfaceBlock->fields.push_back(fieldVariable);
Jamie Madill54ad4f82014-09-03 09:40:46 -0400611 }
Jamie Madilld5512cd2014-07-10 17:50:08 -0400612}
613
Olli Etuaho19515012017-06-26 18:00:17 +0300614Uniform CollectVariablesTraverser::recordUniform(const TIntermSymbol &variable) const
Jamie Madill4667c452014-07-08 15:02:36 -0400615{
Olli Etuahoa55102c2017-02-24 12:36:50 +0000616 Uniform uniform;
617 setCommonVariableProperties(variable.getType(), variable.getSymbol(), &uniform);
Olli Etuaho78ed6cd2017-08-09 16:19:00 +0300618 uniform.binding = variable.getType().getLayoutQualifier().binding;
Olli Etuaho6ca2b652017-02-19 18:05:10 +0000619 uniform.location = variable.getType().getLayoutQualifier().location;
jchen104cdac9e2017-05-08 11:01:20 +0800620 uniform.offset = variable.getType().getLayoutQualifier().offset;
Olli Etuahoa55102c2017-02-24 12:36:50 +0000621 return uniform;
alokp@chromium.org07620a52010-09-23 17:53:56 +0000622}
623
Olli Etuaho19515012017-06-26 18:00:17 +0300624bool CollectVariablesTraverser::visitDeclaration(Visit, TIntermDeclaration *node)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000625{
Olli Etuaho13389b62016-10-16 11:48:18 +0100626 const TIntermSequence &sequence = *(node->getSequence());
627 ASSERT(!sequence.empty());
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000628
Olli Etuaho13389b62016-10-16 11:48:18 +0100629 const TIntermTyped &typedNode = *(sequence.front()->getAsTyped());
630 TQualifier qualifier = typedNode.getQualifier();
631
Olli Etuahoa55102c2017-02-24 12:36:50 +0000632 bool isShaderVariable = qualifier == EvqAttribute || qualifier == EvqVertexIn ||
633 qualifier == EvqFragmentOut || qualifier == EvqUniform ||
634 IsVarying(qualifier);
635
636 if (typedNode.getBasicType() != EbtInterfaceBlock && !isShaderVariable)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000637 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000638 return true;
Olli Etuaho13389b62016-10-16 11:48:18 +0100639 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000640
641 for (TIntermNode *variableNode : sequence)
Olli Etuaho13389b62016-10-16 11:48:18 +0100642 {
Olli Etuahoa55102c2017-02-24 12:36:50 +0000643 // The only case in which the sequence will not contain a TIntermSymbol node is
644 // initialization. It will contain a TInterBinary node in that case. Since attributes,
645 // uniforms, varyings, outputs and interface blocks cannot be initialized in a shader, we
646 // must have only TIntermSymbol nodes in the sequence in the cases we are interested in.
647 const TIntermSymbol &variable = *variableNode->getAsSymbolNode();
Olli Etuaho34d20072017-07-18 20:07:18 +0300648 if (variable.getName().isInternal())
649 {
650 // Internal variables are not collected.
651 continue;
652 }
653
Jiawei Shaod8105a02017-08-08 09:54:36 +0800654 // TODO(jiawei.shao@intel.com): implement GL_OES_shader_io_blocks.
Olli Etuahoa55102c2017-02-24 12:36:50 +0000655 if (typedNode.getBasicType() == EbtInterfaceBlock)
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000656 {
Jiawei Shaod8105a02017-08-08 09:54:36 +0800657 InterfaceBlock interfaceBlock;
658 recordInterfaceBlock(variable.getType(), &interfaceBlock);
659
660 switch (qualifier)
Jiajia Qinbc585152017-06-23 15:42:17 +0800661 {
Jiawei Shaod8105a02017-08-08 09:54:36 +0800662 case EvqUniform:
663 mUniformBlocks->push_back(interfaceBlock);
664 break;
665 case EvqBuffer:
666 mShaderStorageBlocks->push_back(interfaceBlock);
667 break;
668 default:
669 UNREACHABLE();
Jiajia Qinbc585152017-06-23 15:42:17 +0800670 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000671 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000672 else
673 {
674 switch (qualifier)
675 {
676 case EvqAttribute:
677 case EvqVertexIn:
678 mAttribs->push_back(recordAttribute(variable));
679 break;
680 case EvqFragmentOut:
681 mOutputVariables->push_back(recordOutputVariable(variable));
682 break;
683 case EvqUniform:
684 mUniforms->push_back(recordUniform(variable));
685 break;
686 default:
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800687 if (IsVaryingIn(qualifier))
688 {
689 mInputVaryings->push_back(recordVarying(variable));
690 }
691 else
692 {
693 ASSERT(IsVaryingOut(qualifier));
694 mOutputVaryings->push_back(recordVarying(variable));
695 }
Olli Etuahoa55102c2017-02-24 12:36:50 +0000696 break;
697 }
698 }
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000699 }
700
Olli Etuahoa55102c2017-02-24 12:36:50 +0000701 // None of the recorded variables can have initializers, so we don't need to traverse the
702 // declarators.
703 return false;
alokp@chromium.orgee76f6a2010-09-27 19:28:55 +0000704}
Jamie Madill23a8a432014-07-09 13:27:42 -0400705
Jiawei Shaod8105a02017-08-08 09:54:36 +0800706// TODO(jiawei.shao@intel.com): add search on mInBlocks and mOutBlocks when implementing
707// GL_OES_shader_io_blocks.
708InterfaceBlock *CollectVariablesTraverser::findNamedInterfaceBlock(const TString &blockName) const
709{
710 InterfaceBlock *namedBlock = FindVariable(blockName, mUniformBlocks);
711 if (!namedBlock)
712 {
713 namedBlock = FindVariable(blockName, mShaderStorageBlocks);
714 }
715 return namedBlock;
716}
717
Olli Etuaho19515012017-06-26 18:00:17 +0300718bool CollectVariablesTraverser::visitBinary(Visit, TIntermBinary *binaryNode)
Jamie Madillb547ddf2014-08-25 16:20:46 -0400719{
720 if (binaryNode->getOp() == EOpIndexDirectInterfaceBlock)
721 {
Jamie Madilla6f267f2014-08-27 11:44:15 -0400722 // NOTE: we do not determine static use for individual blocks of an array
723 TIntermTyped *blockNode = binaryNode->getLeft()->getAsTyped();
724 ASSERT(blockNode);
Jamie Madillb547ddf2014-08-25 16:20:46 -0400725
726 TIntermConstantUnion *constantUnion = binaryNode->getRight()->getAsConstantUnion();
727 ASSERT(constantUnion);
728
Jiawei Shaod8105a02017-08-08 09:54:36 +0800729 InterfaceBlock *namedBlock = nullptr;
730
731 bool traverseIndexExpression = false;
732 TIntermBinary *interfaceIndexingNode = blockNode->getAsBinaryNode();
733 if (interfaceIndexingNode)
734 {
735 TIntermTyped *interfaceNode = interfaceIndexingNode->getLeft()->getAsTyped();
736 ASSERT(interfaceNode);
737
738 const TType &interfaceType = interfaceNode->getType();
739 if (interfaceType.getQualifier() == EvqPerVertexIn)
740 {
741 namedBlock = recordGLInUsed(interfaceType);
742 ASSERT(namedBlock);
743
744 // We need to continue traversing to collect useful variables in the index
745 // expression of gl_in.
746 traverseIndexExpression = true;
747 }
748 }
749
Jamie Madilla6f267f2014-08-27 11:44:15 -0400750 const TInterfaceBlock *interfaceBlock = blockNode->getType().getInterfaceBlock();
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800751 if (!namedBlock)
Jiajia Qinbc585152017-06-23 15:42:17 +0800752 {
Jiawei Shaod8105a02017-08-08 09:54:36 +0800753 namedBlock = findNamedInterfaceBlock(interfaceBlock->name());
Jiajia Qinbc585152017-06-23 15:42:17 +0800754 }
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800755 ASSERT(namedBlock);
756 namedBlock->staticUse = true;
757 unsigned int fieldIndex = static_cast<unsigned int>(constantUnion->getIConst(0));
758 ASSERT(fieldIndex < namedBlock->fields.size());
759 namedBlock->fields[fieldIndex].staticUse = true;
Jiawei Shaod8105a02017-08-08 09:54:36 +0800760
761 if (traverseIndexExpression)
762 {
763 ASSERT(interfaceIndexingNode);
764 interfaceIndexingNode->getRight()->traverse(this);
765 }
Jamie Madillb547ddf2014-08-25 16:20:46 -0400766 return false;
767 }
768
769 return true;
770}
771
Olli Etuaho19515012017-06-26 18:00:17 +0300772} // anonymous namespace
773
774void CollectVariables(TIntermBlock *root,
775 std::vector<Attribute> *attributes,
776 std::vector<OutputVariable> *outputVariables,
777 std::vector<Uniform> *uniforms,
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800778 std::vector<Varying> *inputVaryings,
779 std::vector<Varying> *outputVaryings,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800780 std::vector<InterfaceBlock> *uniformBlocks,
781 std::vector<InterfaceBlock> *shaderStorageBlocks,
Jiawei Shaod8105a02017-08-08 09:54:36 +0800782 std::vector<InterfaceBlock> *inBlocks,
Olli Etuaho19515012017-06-26 18:00:17 +0300783 ShHashFunction64 hashFunction,
Olli Etuahoa5e693a2017-07-13 16:07:26 +0300784 TSymbolTable *symbolTable,
Olli Etuaho19515012017-06-26 18:00:17 +0300785 int shaderVersion,
786 const TExtensionBehavior &extensionBehavior)
787{
Jiawei-Shaodf7d7c92017-07-31 09:34:04 +0800788 CollectVariablesTraverser collect(attributes, outputVariables, uniforms, inputVaryings,
Jiawei Shaod8105a02017-08-08 09:54:36 +0800789 outputVaryings, uniformBlocks, shaderStorageBlocks, inBlocks,
Jiajia Qin9b11ea42017-07-11 16:50:08 +0800790 hashFunction, symbolTable, shaderVersion, extensionBehavior);
Olli Etuaho19515012017-06-26 18:00:17 +0300791 root->traverse(&collect);
792}
793
Olli Etuaho19515012017-06-26 18:00:17 +0300794} // namespace sh