blob: bab1b6a391456140dbb4dcc2ec3c9ad17b91559c [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
Olli Etuaho96f6adf2017-08-16 11:18:54 +030071 for (unsigned int i = 0; i < initializedNode->getOutermostArraySize(); ++i)
Olli Etuaho9733cee2017-05-11 19:14:35 +030072 {
Olli Etuaho3ec75682017-07-05 17:02:55 +030073 TIntermBinary *element =
74 new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i));
Olli Etuaho96f6adf2017-08-16 11:18:54 +030075 if (element->isArray())
76 {
77 AddArrayZeroInitSequence(element, initSequenceOut);
78 }
79 else if (element->getType().isStructureContainingArrays())
Olli Etuaho9733cee2017-05-11 19:14:35 +030080 {
81 AddStructZeroInitSequence(element, initSequenceOut);
82 }
83 else
84 {
85 initSequenceOut->push_back(CreateZeroInitAssignment(element));
86 }
87 }
88}
89
90void InsertInitCode(TIntermSequence *mainBody,
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030091 const InitVariableList &variables,
Martin Radeve145def2017-06-22 12:49:12 +030092 const TSymbolTable &symbolTable,
93 int shaderVersion,
Martin Radeve145def2017-06-22 12:49:12 +030094 const TExtensionBehavior &extensionBehavior)
Zhenyao Mo72111912016-07-20 17:45:56 -070095{
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030096 for (const auto &var : variables)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080097 {
Zhenyao Mo72111912016-07-20 17:45:56 -070098 TString name = TString(var.name.c_str());
Martin Radeve145def2017-06-22 12:49:12 +030099 size_t pos = name.find_last_of('[');
100 if (pos != TString::npos)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800101 {
Martin Radeve145def2017-06-22 12:49:12 +0300102 name = name.substr(0, pos);
Zhenyao Mof9312682016-07-22 12:51:31 -0700103 }
Zhenyao Mod7490962016-11-09 15:49:51 -0800104
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300105 TIntermTyped *initializedSymbol = nullptr;
Martin Radeve145def2017-06-22 12:49:12 +0300106 if (var.isBuiltIn())
107 {
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300108 initializedSymbol = ReferenceBuiltInVariable(name, symbolTable, shaderVersion);
109 if (initializedSymbol->getQualifier() == EvqFragData &&
110 !IsExtensionEnabled(extensionBehavior, "GL_EXT_draw_buffers"))
111 {
112 // If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be
113 // written to.
114 // TODO(oetuaho): This is a bit hacky and would be better to remove, if we came up
115 // with a good way to do it. Right now "gl_FragData" in symbol table is initialized
116 // to have the array size of MaxDrawBuffers, and the initialization happens before
117 // the shader sets the extensions it is using.
118 initializedSymbol =
119 new TIntermBinary(EOpIndexDirect, initializedSymbol, CreateIndexNode(0));
120 }
Zhenyao Mod7490962016-11-09 15:49:51 -0800121 }
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800122 else
123 {
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300124 initializedSymbol = ReferenceGlobalVariable(name, symbolTable);
Corentin Wallez509e4562016-08-25 14:55:44 -0400125 }
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300126 ASSERT(initializedSymbol != nullptr);
Martin Radeve145def2017-06-22 12:49:12 +0300127
Olli Etuaho9733cee2017-05-11 19:14:35 +0300128 TIntermSequence *initCode = CreateInitCode(initializedSymbol);
129 mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800130 }
131}
132
Olli Etuaho9733cee2017-05-11 19:14:35 +0300133class InitializeLocalsTraverser : public TIntermTraverser
134{
135 public:
136 InitializeLocalsTraverser(int shaderVersion)
137 : TIntermTraverser(true, false, false), mShaderVersion(shaderVersion)
138 {
139 }
140
141 protected:
142 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
143 {
144 for (TIntermNode *declarator : *node->getSequence())
145 {
146 if (!mInGlobalScope && !declarator->getAsBinaryNode())
147 {
148 TIntermSymbol *symbol = declarator->getAsSymbolNode();
149 ASSERT(symbol);
150 if (symbol->getSymbol() == "")
151 {
152 continue;
153 }
154
155 // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
156 // support array constructors or assigning arrays.
157 bool arrayConstructorUnavailable =
158 (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
159 mShaderVersion == 100;
160 // Nameless struct constructors can't be referred to, so they also need to be
161 // initialized one element at a time.
162 if (arrayConstructorUnavailable || IsNamelessStruct(symbol))
163 {
164 // SimplifyLoopConditions should have been run so the parent node of this node
165 // should not be a loop.
166 ASSERT(getParentNode()->getAsLoopNode() == nullptr);
167 // SeparateDeclarations should have already been run, so we don't need to worry
168 // about further declarators in this declaration depending on the effects of
169 // this declarator.
170 ASSERT(node->getSequence()->size() == 1);
171 insertStatementsInParentBlock(TIntermSequence(), *CreateInitCode(symbol));
172 }
173 else
174 {
Olli Etuaho3ec75682017-07-05 17:02:55 +0300175 TIntermBinary *init =
176 new TIntermBinary(EOpInitialize, symbol, CreateZeroNode(symbol->getType()));
Olli Etuaho9733cee2017-05-11 19:14:35 +0300177 queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
178 }
179 }
180 }
181 return false;
182 }
183
184 private:
185 int mShaderVersion;
186};
187
Zhenyao Mo72111912016-07-20 17:45:56 -0700188} // namespace anonymous
189
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300190TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol)
Olli Etuaho9733cee2017-05-11 19:14:35 +0300191{
192 TIntermSequence *initCode = new TIntermSequence();
193 if (initializedSymbol->isArray())
194 {
195 AddArrayZeroInitSequence(initializedSymbol, initCode);
196 }
197 else if (initializedSymbol->getType().isStructureContainingArrays() ||
198 IsNamelessStruct(initializedSymbol))
199 {
200 AddStructZeroInitSequence(initializedSymbol, initCode);
201 }
202 else
203 {
204 initCode->push_back(CreateZeroInitAssignment(initializedSymbol));
205 }
206 return initCode;
207}
208
209void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion)
210{
211 InitializeLocalsTraverser traverser(shaderVersion);
212 root->traverse(&traverser);
213 traverser.updateTree();
214}
215
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300216void InitializeVariables(TIntermBlock *root,
Zhenyao Mod7490962016-11-09 15:49:51 -0800217 const InitVariableList &vars,
Martin Radeve145def2017-06-22 12:49:12 +0300218 const TSymbolTable &symbolTable,
219 int shaderVersion,
Martin Radeve145def2017-06-22 12:49:12 +0300220 const TExtensionBehavior &extensionBehavior)
Zhenyao Mo72111912016-07-20 17:45:56 -0700221{
Martin Radevb50ccd32017-07-06 17:09:58 +0300222 TIntermBlock *body = FindMainBody(root);
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300223 InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, extensionBehavior);
Zhenyao Mo72111912016-07-20 17:45:56 -0700224}
Jamie Madill45bcc782016-11-07 13:58:48 -0500225
226} // namespace sh