blob: 0cd3d7cc4b7a0e635bb50956e549028e949e1d48 [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"
Zhenyao Mo72111912016-07-20 17:45:56 -070012#include "compiler/translator/IntermNode.h"
Zhenyao Mod7490962016-11-09 15:49:51 -080013#include "compiler/translator/SymbolTable.h"
Zhenyao Mo72111912016-07-20 17:45:56 -070014#include "compiler/translator/util.h"
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080015
Jamie Madill45bcc782016-11-07 13:58:48 -050016namespace sh
17{
18
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080019namespace
20{
21
Olli Etuaho9733cee2017-05-11 19:14:35 +030022bool IsNamelessStruct(const TIntermTyped *node)
23{
24 return (node->getBasicType() == EbtStruct && node->getType().getStruct()->name() == "");
25}
26
27void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
28 TIntermSequence *initSequenceOut);
29
30TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode)
31{
32 TIntermTyped *zero = TIntermTyped::CreateZero(initializedNode->getType());
33 return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero);
34}
35
36void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
37 TIntermSequence *initSequenceOut)
38{
39 ASSERT(initializedNode->getBasicType() == EbtStruct);
40 TStructure *structType = initializedNode->getType().getStruct();
41 for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
42 {
43 TIntermBinary *element = new TIntermBinary(
44 EOpIndexDirectStruct, initializedNode->deepCopy(), TIntermTyped::CreateIndexNode(i));
45 if (element->isArray())
46 {
47 AddArrayZeroInitSequence(element, initSequenceOut);
48 }
49 else if (element->getType().isStructureContainingArrays())
50 {
51 AddStructZeroInitSequence(element, initSequenceOut);
52 }
53 else
54 {
55 // Structs can't be defined inside structs, so the type of a struct field can't be a
56 // nameless struct.
57 ASSERT(!IsNamelessStruct(element));
58 initSequenceOut->push_back(CreateZeroInitAssignment(element));
59 }
60 }
61}
62
63void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, TIntermSequence *initSequenceOut)
64{
65 ASSERT(initializedNode->isArray());
66 // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
67 // doesn't have array assignment.
68 // Note that it is important to have the array init in the right order to workaround
69 // http://crbug.com/709317
70 for (unsigned int i = 0; i < initializedNode->getArraySize(); ++i)
71 {
72 TIntermBinary *element = new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(),
73 TIntermTyped::CreateIndexNode(i));
74 if (element->getType().isStructureContainingArrays())
75 {
76 AddStructZeroInitSequence(element, initSequenceOut);
77 }
78 else
79 {
80 initSequenceOut->push_back(CreateZeroInitAssignment(element));
81 }
82 }
83}
84
85void InsertInitCode(TIntermSequence *mainBody,
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030086 const InitVariableList &variables,
Martin Radeve145def2017-06-22 12:49:12 +030087 const TSymbolTable &symbolTable,
88 int shaderVersion,
89 ShShaderSpec shaderSpec,
90 const TExtensionBehavior &extensionBehavior)
Zhenyao Mo72111912016-07-20 17:45:56 -070091{
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030092 for (const auto &var : variables)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080093 {
Zhenyao Mo72111912016-07-20 17:45:56 -070094 TString name = TString(var.name.c_str());
Martin Radeve145def2017-06-22 12:49:12 +030095 size_t pos = name.find_last_of('[');
96 if (pos != TString::npos)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080097 {
Martin Radeve145def2017-06-22 12:49:12 +030098 name = name.substr(0, pos);
Zhenyao Mof9312682016-07-22 12:51:31 -070099 }
Zhenyao Mod7490962016-11-09 15:49:51 -0800100
Martin Radeve145def2017-06-22 12:49:12 +0300101 const TVariable *symbolInfo = nullptr;
102 if (var.isBuiltIn())
103 {
104 symbolInfo =
105 reinterpret_cast<const TVariable *>(symbolTable.findBuiltIn(name, shaderVersion));
Zhenyao Mod7490962016-11-09 15:49:51 -0800106 }
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800107 else
108 {
Martin Radeve145def2017-06-22 12:49:12 +0300109 symbolInfo = reinterpret_cast<const TVariable *>(symbolTable.findGlobal(name));
Corentin Wallez509e4562016-08-25 14:55:44 -0400110 }
Martin Radeve145def2017-06-22 12:49:12 +0300111 ASSERT(symbolInfo != nullptr);
112
113 TType type = symbolInfo->getType();
114 if (type.getQualifier() == EvqFragData &&
115 (shaderSpec == SH_WEBGL2_SPEC ||
116 !IsExtensionEnabled(extensionBehavior, "GL_EXT_draw_buffers")))
117 {
118 // Adjust the number of attachment indices which can be initialized according to the
119 // WebGL2 spec and extension behavior:
120 // - WebGL2 spec, Editor's draft May 31, 5.13 GLSL ES
121 // 1.00 Fragment Shader Output: "A fragment shader written in The OpenGL ES Shading
122 // Language, Version 1.00, that statically assigns a value to gl_FragData[n] where n
123 // does not equal constant value 0 must fail to compile in the WebGL 2.0 API.".
124 // This excerpt limits the initialization of gl_FragData to only the 0th index.
125 // - If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be
126 // written to.
127 type.setArraySize(1u);
128 }
129
130 TIntermSymbol *initializedSymbol = new TIntermSymbol(0, name, type);
Olli Etuaho9733cee2017-05-11 19:14:35 +0300131 TIntermSequence *initCode = CreateInitCode(initializedSymbol);
132 mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800133 }
134}
135
Olli Etuaho9733cee2017-05-11 19:14:35 +0300136class InitializeLocalsTraverser : public TIntermTraverser
137{
138 public:
139 InitializeLocalsTraverser(int shaderVersion)
140 : TIntermTraverser(true, false, false), mShaderVersion(shaderVersion)
141 {
142 }
143
144 protected:
145 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
146 {
147 for (TIntermNode *declarator : *node->getSequence())
148 {
149 if (!mInGlobalScope && !declarator->getAsBinaryNode())
150 {
151 TIntermSymbol *symbol = declarator->getAsSymbolNode();
152 ASSERT(symbol);
153 if (symbol->getSymbol() == "")
154 {
155 continue;
156 }
157
158 // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
159 // support array constructors or assigning arrays.
160 bool arrayConstructorUnavailable =
161 (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
162 mShaderVersion == 100;
163 // Nameless struct constructors can't be referred to, so they also need to be
164 // initialized one element at a time.
165 if (arrayConstructorUnavailable || IsNamelessStruct(symbol))
166 {
167 // SimplifyLoopConditions should have been run so the parent node of this node
168 // should not be a loop.
169 ASSERT(getParentNode()->getAsLoopNode() == nullptr);
170 // SeparateDeclarations should have already been run, so we don't need to worry
171 // about further declarators in this declaration depending on the effects of
172 // this declarator.
173 ASSERT(node->getSequence()->size() == 1);
174 insertStatementsInParentBlock(TIntermSequence(), *CreateInitCode(symbol));
175 }
176 else
177 {
178 TIntermBinary *init = new TIntermBinary(
179 EOpInitialize, symbol, TIntermTyped::CreateZero(symbol->getType()));
180 queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
181 }
182 }
183 }
184 return false;
185 }
186
187 private:
188 int mShaderVersion;
189};
190
Zhenyao Mo72111912016-07-20 17:45:56 -0700191} // namespace anonymous
192
Olli Etuaho9733cee2017-05-11 19:14:35 +0300193TIntermSequence *CreateInitCode(const TIntermSymbol *initializedSymbol)
194{
195 TIntermSequence *initCode = new TIntermSequence();
196 if (initializedSymbol->isArray())
197 {
198 AddArrayZeroInitSequence(initializedSymbol, initCode);
199 }
200 else if (initializedSymbol->getType().isStructureContainingArrays() ||
201 IsNamelessStruct(initializedSymbol))
202 {
203 AddStructZeroInitSequence(initializedSymbol, initCode);
204 }
205 else
206 {
207 initCode->push_back(CreateZeroInitAssignment(initializedSymbol));
208 }
209 return initCode;
210}
211
212void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion)
213{
214 InitializeLocalsTraverser traverser(shaderVersion);
215 root->traverse(&traverser);
216 traverser.updateTree();
217}
218
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300219void InitializeVariables(TIntermBlock *root,
Zhenyao Mod7490962016-11-09 15:49:51 -0800220 const InitVariableList &vars,
Martin Radeve145def2017-06-22 12:49:12 +0300221 const TSymbolTable &symbolTable,
222 int shaderVersion,
223 ShShaderSpec shaderSpec,
224 const TExtensionBehavior &extensionBehavior)
Zhenyao Mo72111912016-07-20 17:45:56 -0700225{
Martin Radeve145def2017-06-22 12:49:12 +0300226
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300227 TIntermFunctionDefinition *main = FindMain(root);
228 ASSERT(main != nullptr);
229 TIntermBlock *body = main->getBody();
Martin Radeve145def2017-06-22 12:49:12 +0300230 InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, shaderSpec,
231 extensionBehavior);
Zhenyao Mo72111912016-07-20 17:45:56 -0700232}
Jamie Madill45bcc782016-11-07 13:58:48 -0500233
234} // namespace sh