blob: 22c1cab7fdf153a8f083256a8e2a6659b0542fd6 [file] [log] [blame]
Zhenyao Mo4a667fe2014-02-11 12:35:01 -08001//
2// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include "compiler/translator/InitializeVariables.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +03008
Zhenyao Mo72111912016-07-20 17:45:56 -07009#include "angle_gl.h"
Olli Etuahod57e0db2015-04-24 15:05:08 +030010#include "common/debug.h"
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030011#include "compiler/translator/FindMain.h"
Olli Etuaho3ec75682017-07-05 17:02:55 +030012#include "compiler/translator/IntermNode_util.h"
Olli Etuahocccf2b02017-07-05 14:50:54 +030013#include "compiler/translator/IntermTraverse.h"
Zhenyao Mod7490962016-11-09 15:49:51 -080014#include "compiler/translator/SymbolTable.h"
Zhenyao Mo72111912016-07-20 17:45:56 -070015#include "compiler/translator/util.h"
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080016
Jamie Madill45bcc782016-11-07 13:58:48 -050017namespace sh
18{
19
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080020namespace
21{
22
Olli Etuaho9733cee2017-05-11 19:14:35 +030023bool IsNamelessStruct(const TIntermTyped *node)
24{
25 return (node->getBasicType() == EbtStruct && node->getType().getStruct()->name() == "");
26}
27
28void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
29 TIntermSequence *initSequenceOut);
30
31TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode)
32{
Olli Etuaho3ec75682017-07-05 17:02:55 +030033 TIntermTyped *zero = CreateZeroNode(initializedNode->getType());
Olli Etuaho9733cee2017-05-11 19:14:35 +030034 return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero);
35}
36
37void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
38 TIntermSequence *initSequenceOut)
39{
40 ASSERT(initializedNode->getBasicType() == EbtStruct);
41 TStructure *structType = initializedNode->getType().getStruct();
42 for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
43 {
Olli Etuaho3ec75682017-07-05 17:02:55 +030044 TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct,
45 initializedNode->deepCopy(), CreateIndexNode(i));
Olli Etuaho9733cee2017-05-11 19:14:35 +030046 if (element->isArray())
47 {
48 AddArrayZeroInitSequence(element, initSequenceOut);
49 }
50 else if (element->getType().isStructureContainingArrays())
51 {
52 AddStructZeroInitSequence(element, initSequenceOut);
53 }
54 else
55 {
56 // Structs can't be defined inside structs, so the type of a struct field can't be a
57 // nameless struct.
58 ASSERT(!IsNamelessStruct(element));
59 initSequenceOut->push_back(CreateZeroInitAssignment(element));
60 }
61 }
62}
63
64void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, TIntermSequence *initSequenceOut)
65{
66 ASSERT(initializedNode->isArray());
67 // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
68 // doesn't have array assignment.
69 // Note that it is important to have the array init in the right order to workaround
70 // http://crbug.com/709317
71 for (unsigned int i = 0; i < initializedNode->getArraySize(); ++i)
72 {
Olli Etuaho3ec75682017-07-05 17:02:55 +030073 TIntermBinary *element =
74 new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i));
Olli Etuaho9733cee2017-05-11 19:14:35 +030075 if (element->getType().isStructureContainingArrays())
76 {
77 AddStructZeroInitSequence(element, initSequenceOut);
78 }
79 else
80 {
81 initSequenceOut->push_back(CreateZeroInitAssignment(element));
82 }
83 }
84}
85
86void InsertInitCode(TIntermSequence *mainBody,
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030087 const InitVariableList &variables,
Martin Radeve145def2017-06-22 12:49:12 +030088 const TSymbolTable &symbolTable,
89 int shaderVersion,
90 ShShaderSpec shaderSpec,
91 const TExtensionBehavior &extensionBehavior)
Zhenyao Mo72111912016-07-20 17:45:56 -070092{
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030093 for (const auto &var : variables)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080094 {
Zhenyao Mo72111912016-07-20 17:45:56 -070095 TString name = TString(var.name.c_str());
Martin Radeve145def2017-06-22 12:49:12 +030096 size_t pos = name.find_last_of('[');
97 if (pos != TString::npos)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080098 {
Martin Radeve145def2017-06-22 12:49:12 +030099 name = name.substr(0, pos);
Zhenyao Mof9312682016-07-22 12:51:31 -0700100 }
Zhenyao Mod7490962016-11-09 15:49:51 -0800101
Martin Radeve145def2017-06-22 12:49:12 +0300102 const TVariable *symbolInfo = nullptr;
103 if (var.isBuiltIn())
104 {
105 symbolInfo =
106 reinterpret_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion));
Zhenyao Mod7490962016-11-09 15:49:51 -0800107 }
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800108 else
109 {
Martin Radeve145def2017-06-22 12:49:12 +0300110 symbolInfo = reinterpret_cast<const TVariable *>(symbolTable.findGlobal(name));
Corentin Wallez509e4562016-08-25 14:55:44 -0400111 }
Martin Radeve145def2017-06-22 12:49:12 +0300112 ASSERT(symbolInfo != nullptr);
113
114 TType type = symbolInfo->getType();
115 if (type.getQualifier() == EvqFragData &&
116 (shaderSpec == SH_WEBGL2_SPEC ||
117 !IsExtensionEnabled(extensionBehavior, "GL_EXT_draw_buffers")))
118 {
119 // Adjust the number of attachment indices which can be initialized according to the
120 // WebGL2 spec and extension behavior:
121 // - WebGL2 spec, Editor's draft May 31, 5.13 GLSL ES
122 // 1.00 Fragment Shader Output: "A fragment shader written in The OpenGL ES Shading
123 // Language, Version 1.00, that statically assigns a value to gl_FragData[n] where n
124 // does not equal constant value 0 must fail to compile in the WebGL 2.0 API.".
125 // This excerpt limits the initialization of gl_FragData to only the 0th index.
126 // - If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be
127 // written to.
128 type.setArraySize(1u);
129 }
130
131 TIntermSymbol *initializedSymbol = new TIntermSymbol(0, name, type);
Olli Etuaho9733cee2017-05-11 19:14:35 +0300132 TIntermSequence *initCode = CreateInitCode(initializedSymbol);
133 mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800134 }
135}
136
Olli Etuaho9733cee2017-05-11 19:14:35 +0300137class InitializeLocalsTraverser : public TIntermTraverser
138{
139 public:
140 InitializeLocalsTraverser(int shaderVersion)
141 : TIntermTraverser(true, false, false), mShaderVersion(shaderVersion)
142 {
143 }
144
145 protected:
146 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
147 {
148 for (TIntermNode *declarator : *node->getSequence())
149 {
150 if (!mInGlobalScope && !declarator->getAsBinaryNode())
151 {
152 TIntermSymbol *symbol = declarator->getAsSymbolNode();
153 ASSERT(symbol);
154 if (symbol->getSymbol() == "")
155 {
156 continue;
157 }
158
159 // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
160 // support array constructors or assigning arrays.
161 bool arrayConstructorUnavailable =
162 (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
163 mShaderVersion == 100;
164 // Nameless struct constructors can't be referred to, so they also need to be
165 // initialized one element at a time.
166 if (arrayConstructorUnavailable || IsNamelessStruct(symbol))
167 {
168 // SimplifyLoopConditions should have been run so the parent node of this node
169 // should not be a loop.
170 ASSERT(getParentNode()->getAsLoopNode() == nullptr);
171 // SeparateDeclarations should have already been run, so we don't need to worry
172 // about further declarators in this declaration depending on the effects of
173 // this declarator.
174 ASSERT(node->getSequence()->size() == 1);
175 insertStatementsInParentBlock(TIntermSequence(), *CreateInitCode(symbol));
176 }
177 else
178 {
Olli Etuaho3ec75682017-07-05 17:02:55 +0300179 TIntermBinary *init =
180 new TIntermBinary(EOpInitialize, symbol, CreateZeroNode(symbol->getType()));
Olli Etuaho9733cee2017-05-11 19:14:35 +0300181 queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
182 }
183 }
184 }
185 return false;
186 }
187
188 private:
189 int mShaderVersion;
190};
191
Zhenyao Mo72111912016-07-20 17:45:56 -0700192} // namespace anonymous
193
Olli Etuaho9733cee2017-05-11 19:14:35 +0300194TIntermSequence *CreateInitCode(const TIntermSymbol *initializedSymbol)
195{
196 TIntermSequence *initCode = new TIntermSequence();
197 if (initializedSymbol->isArray())
198 {
199 AddArrayZeroInitSequence(initializedSymbol, initCode);
200 }
201 else if (initializedSymbol->getType().isStructureContainingArrays() ||
202 IsNamelessStruct(initializedSymbol))
203 {
204 AddStructZeroInitSequence(initializedSymbol, initCode);
205 }
206 else
207 {
208 initCode->push_back(CreateZeroInitAssignment(initializedSymbol));
209 }
210 return initCode;
211}
212
213void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion)
214{
215 InitializeLocalsTraverser traverser(shaderVersion);
216 root->traverse(&traverser);
217 traverser.updateTree();
218}
219
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300220void InitializeVariables(TIntermBlock *root,
Zhenyao Mod7490962016-11-09 15:49:51 -0800221 const InitVariableList &vars,
Martin Radeve145def2017-06-22 12:49:12 +0300222 const TSymbolTable &symbolTable,
223 int shaderVersion,
224 ShShaderSpec shaderSpec,
225 const TExtensionBehavior &extensionBehavior)
Zhenyao Mo72111912016-07-20 17:45:56 -0700226{
Martin Radeve145def2017-06-22 12:49:12 +0300227
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300228 TIntermFunctionDefinition *main = FindMain(root);
229 ASSERT(main != nullptr);
230 TIntermBlock *body = main->getBody();
Martin Radeve145def2017-06-22 12:49:12 +0300231 InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, shaderSpec,
232 extensionBehavior);
Zhenyao Mo72111912016-07-20 17:45:56 -0700233}
Jamie Madill45bcc782016-11-07 13:58:48 -0500234
235} // namespace sh