blob: 6b015e2f4481cc7747339d930b020fc101538e7b [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,
Martin Radeve145def2017-06-22 12:49:12 +030090 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
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300101 TIntermTyped *initializedSymbol = nullptr;
Martin Radeve145def2017-06-22 12:49:12 +0300102 if (var.isBuiltIn())
103 {
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300104 initializedSymbol = ReferenceBuiltInVariable(name, symbolTable, shaderVersion);
105 if (initializedSymbol->getQualifier() == EvqFragData &&
106 !IsExtensionEnabled(extensionBehavior, "GL_EXT_draw_buffers"))
107 {
108 // If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be
109 // written to.
110 // TODO(oetuaho): This is a bit hacky and would be better to remove, if we came up
111 // with a good way to do it. Right now "gl_FragData" in symbol table is initialized
112 // to have the array size of MaxDrawBuffers, and the initialization happens before
113 // the shader sets the extensions it is using.
114 initializedSymbol =
115 new TIntermBinary(EOpIndexDirect, initializedSymbol, CreateIndexNode(0));
116 }
Zhenyao Mod7490962016-11-09 15:49:51 -0800117 }
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800118 else
119 {
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300120 initializedSymbol = ReferenceGlobalVariable(name, symbolTable);
Corentin Wallez509e4562016-08-25 14:55:44 -0400121 }
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300122 ASSERT(initializedSymbol != nullptr);
Martin Radeve145def2017-06-22 12:49:12 +0300123
Olli Etuaho9733cee2017-05-11 19:14:35 +0300124 TIntermSequence *initCode = CreateInitCode(initializedSymbol);
125 mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800126 }
127}
128
Olli Etuaho9733cee2017-05-11 19:14:35 +0300129class InitializeLocalsTraverser : public TIntermTraverser
130{
131 public:
132 InitializeLocalsTraverser(int shaderVersion)
133 : TIntermTraverser(true, false, false), mShaderVersion(shaderVersion)
134 {
135 }
136
137 protected:
138 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
139 {
140 for (TIntermNode *declarator : *node->getSequence())
141 {
142 if (!mInGlobalScope && !declarator->getAsBinaryNode())
143 {
144 TIntermSymbol *symbol = declarator->getAsSymbolNode();
145 ASSERT(symbol);
146 if (symbol->getSymbol() == "")
147 {
148 continue;
149 }
150
151 // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
152 // support array constructors or assigning arrays.
153 bool arrayConstructorUnavailable =
154 (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
155 mShaderVersion == 100;
156 // Nameless struct constructors can't be referred to, so they also need to be
157 // initialized one element at a time.
158 if (arrayConstructorUnavailable || IsNamelessStruct(symbol))
159 {
160 // SimplifyLoopConditions should have been run so the parent node of this node
161 // should not be a loop.
162 ASSERT(getParentNode()->getAsLoopNode() == nullptr);
163 // SeparateDeclarations should have already been run, so we don't need to worry
164 // about further declarators in this declaration depending on the effects of
165 // this declarator.
166 ASSERT(node->getSequence()->size() == 1);
167 insertStatementsInParentBlock(TIntermSequence(), *CreateInitCode(symbol));
168 }
169 else
170 {
Olli Etuaho3ec75682017-07-05 17:02:55 +0300171 TIntermBinary *init =
172 new TIntermBinary(EOpInitialize, symbol, CreateZeroNode(symbol->getType()));
Olli Etuaho9733cee2017-05-11 19:14:35 +0300173 queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
174 }
175 }
176 }
177 return false;
178 }
179
180 private:
181 int mShaderVersion;
182};
183
Zhenyao Mo72111912016-07-20 17:45:56 -0700184} // namespace anonymous
185
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300186TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol)
Olli Etuaho9733cee2017-05-11 19:14:35 +0300187{
188 TIntermSequence *initCode = new TIntermSequence();
189 if (initializedSymbol->isArray())
190 {
191 AddArrayZeroInitSequence(initializedSymbol, initCode);
192 }
193 else if (initializedSymbol->getType().isStructureContainingArrays() ||
194 IsNamelessStruct(initializedSymbol))
195 {
196 AddStructZeroInitSequence(initializedSymbol, initCode);
197 }
198 else
199 {
200 initCode->push_back(CreateZeroInitAssignment(initializedSymbol));
201 }
202 return initCode;
203}
204
205void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion)
206{
207 InitializeLocalsTraverser traverser(shaderVersion);
208 root->traverse(&traverser);
209 traverser.updateTree();
210}
211
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300212void InitializeVariables(TIntermBlock *root,
Zhenyao Mod7490962016-11-09 15:49:51 -0800213 const InitVariableList &vars,
Martin Radeve145def2017-06-22 12:49:12 +0300214 const TSymbolTable &symbolTable,
215 int shaderVersion,
Martin Radeve145def2017-06-22 12:49:12 +0300216 const TExtensionBehavior &extensionBehavior)
Zhenyao Mo72111912016-07-20 17:45:56 -0700217{
Martin Radevb50ccd32017-07-06 17:09:58 +0300218 TIntermBlock *body = FindMainBody(root);
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300219 InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, extensionBehavior);
Zhenyao Mo72111912016-07-20 17:45:56 -0700220}
Jamie Madill45bcc782016-11-07 13:58:48 -0500221
222} // namespace sh