blob: 51f2cc2c16daefb0a832a0e459ff390d1f299b38 [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 +030023void AddArrayZeroInitSequence(const TIntermTyped *initializedNode,
24 TIntermSequence *initSequenceOut);
25
26TIntermBinary *CreateZeroInitAssignment(const TIntermTyped *initializedNode)
27{
Olli Etuaho3ec75682017-07-05 17:02:55 +030028 TIntermTyped *zero = CreateZeroNode(initializedNode->getType());
Olli Etuaho9733cee2017-05-11 19:14:35 +030029 return new TIntermBinary(EOpAssign, initializedNode->deepCopy(), zero);
30}
31
32void AddStructZeroInitSequence(const TIntermTyped *initializedNode,
33 TIntermSequence *initSequenceOut)
34{
35 ASSERT(initializedNode->getBasicType() == EbtStruct);
Olli Etuahobd3cd502017-11-03 15:48:52 +020036 const TStructure *structType = initializedNode->getType().getStruct();
Olli Etuaho9733cee2017-05-11 19:14:35 +030037 for (int i = 0; i < static_cast<int>(structType->fields().size()); ++i)
38 {
Olli Etuaho3ec75682017-07-05 17:02:55 +030039 TIntermBinary *element = new TIntermBinary(EOpIndexDirectStruct,
40 initializedNode->deepCopy(), CreateIndexNode(i));
Olli Etuaho9733cee2017-05-11 19:14:35 +030041 if (element->isArray())
42 {
43 AddArrayZeroInitSequence(element, initSequenceOut);
44 }
45 else if (element->getType().isStructureContainingArrays())
46 {
47 AddStructZeroInitSequence(element, initSequenceOut);
48 }
49 else
50 {
51 // Structs can't be defined inside structs, so the type of a struct field can't be a
52 // nameless struct.
Olli Etuaho858ff482017-11-15 13:41:46 +020053 ASSERT(!element->getType().isNamelessStruct());
Olli Etuaho9733cee2017-05-11 19:14:35 +030054 initSequenceOut->push_back(CreateZeroInitAssignment(element));
55 }
56 }
57}
58
59void AddArrayZeroInitSequence(const TIntermTyped *initializedNode, TIntermSequence *initSequenceOut)
60{
61 ASSERT(initializedNode->isArray());
62 // Assign the array elements one by one to keep the AST compatible with ESSL 1.00 which
63 // doesn't have array assignment.
64 // Note that it is important to have the array init in the right order to workaround
65 // http://crbug.com/709317
Olli Etuaho96f6adf2017-08-16 11:18:54 +030066 for (unsigned int i = 0; i < initializedNode->getOutermostArraySize(); ++i)
Olli Etuaho9733cee2017-05-11 19:14:35 +030067 {
Olli Etuaho3ec75682017-07-05 17:02:55 +030068 TIntermBinary *element =
69 new TIntermBinary(EOpIndexDirect, initializedNode->deepCopy(), CreateIndexNode(i));
Olli Etuaho96f6adf2017-08-16 11:18:54 +030070 if (element->isArray())
71 {
72 AddArrayZeroInitSequence(element, initSequenceOut);
73 }
74 else if (element->getType().isStructureContainingArrays())
Olli Etuaho9733cee2017-05-11 19:14:35 +030075 {
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,
Martin Radeve145def2017-06-22 12:49:12 +030089 const TExtensionBehavior &extensionBehavior)
Zhenyao Mo72111912016-07-20 17:45:56 -070090{
Olli Etuaho9cbc07c2017-05-10 18:22:01 +030091 for (const auto &var : variables)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080092 {
Zhenyao Mo72111912016-07-20 17:45:56 -070093 TString name = TString(var.name.c_str());
Martin Radeve145def2017-06-22 12:49:12 +030094 size_t pos = name.find_last_of('[');
95 if (pos != TString::npos)
Zhenyao Mo4a667fe2014-02-11 12:35:01 -080096 {
Martin Radeve145def2017-06-22 12:49:12 +030097 name = name.substr(0, pos);
Zhenyao Mof9312682016-07-22 12:51:31 -070098 }
Zhenyao Mod7490962016-11-09 15:49:51 -080099
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300100 TIntermTyped *initializedSymbol = nullptr;
Martin Radeve145def2017-06-22 12:49:12 +0300101 if (var.isBuiltIn())
102 {
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300103 initializedSymbol = ReferenceBuiltInVariable(name, symbolTable, shaderVersion);
104 if (initializedSymbol->getQualifier() == EvqFragData &&
Olli Etuaho2a1e8f92017-07-14 11:49:36 +0300105 !IsExtensionEnabled(extensionBehavior, TExtension::EXT_draw_buffers))
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300106 {
107 // If GL_EXT_draw_buffers is disabled, only the 0th index of gl_FragData can be
108 // written to.
109 // TODO(oetuaho): This is a bit hacky and would be better to remove, if we came up
110 // with a good way to do it. Right now "gl_FragData" in symbol table is initialized
111 // to have the array size of MaxDrawBuffers, and the initialization happens before
112 // the shader sets the extensions it is using.
113 initializedSymbol =
114 new TIntermBinary(EOpIndexDirect, initializedSymbol, CreateIndexNode(0));
115 }
Zhenyao Mod7490962016-11-09 15:49:51 -0800116 }
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800117 else
118 {
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300119 initializedSymbol = ReferenceGlobalVariable(name, symbolTable);
Corentin Wallez509e4562016-08-25 14:55:44 -0400120 }
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300121 ASSERT(initializedSymbol != nullptr);
Martin Radeve145def2017-06-22 12:49:12 +0300122
Olli Etuaho9733cee2017-05-11 19:14:35 +0300123 TIntermSequence *initCode = CreateInitCode(initializedSymbol);
124 mainBody->insert(mainBody->begin(), initCode->begin(), initCode->end());
Zhenyao Mo4a667fe2014-02-11 12:35:01 -0800125 }
126}
127
Olli Etuaho9733cee2017-05-11 19:14:35 +0300128class InitializeLocalsTraverser : public TIntermTraverser
129{
130 public:
131 InitializeLocalsTraverser(int shaderVersion)
132 : TIntermTraverser(true, false, false), mShaderVersion(shaderVersion)
133 {
134 }
135
136 protected:
137 bool visitDeclaration(Visit visit, TIntermDeclaration *node) override
138 {
139 for (TIntermNode *declarator : *node->getSequence())
140 {
141 if (!mInGlobalScope && !declarator->getAsBinaryNode())
142 {
143 TIntermSymbol *symbol = declarator->getAsSymbolNode();
144 ASSERT(symbol);
145 if (symbol->getSymbol() == "")
146 {
147 continue;
148 }
149
150 // Arrays may need to be initialized one element at a time, since ESSL 1.00 does not
151 // support array constructors or assigning arrays.
152 bool arrayConstructorUnavailable =
153 (symbol->isArray() || symbol->getType().isStructureContainingArrays()) &&
154 mShaderVersion == 100;
155 // Nameless struct constructors can't be referred to, so they also need to be
156 // initialized one element at a time.
Olli Etuaho858ff482017-11-15 13:41:46 +0200157 if (arrayConstructorUnavailable || symbol->getType().isNamelessStruct())
Olli Etuaho9733cee2017-05-11 19:14:35 +0300158 {
159 // SimplifyLoopConditions should have been run so the parent node of this node
160 // should not be a loop.
161 ASSERT(getParentNode()->getAsLoopNode() == nullptr);
162 // SeparateDeclarations should have already been run, so we don't need to worry
163 // about further declarators in this declaration depending on the effects of
164 // this declarator.
165 ASSERT(node->getSequence()->size() == 1);
166 insertStatementsInParentBlock(TIntermSequence(), *CreateInitCode(symbol));
167 }
168 else
169 {
Olli Etuaho3ec75682017-07-05 17:02:55 +0300170 TIntermBinary *init =
171 new TIntermBinary(EOpInitialize, symbol, CreateZeroNode(symbol->getType()));
Olli Etuaho9733cee2017-05-11 19:14:35 +0300172 queueReplacementWithParent(node, symbol, init, OriginalNode::BECOMES_CHILD);
173 }
174 }
175 }
176 return false;
177 }
178
179 private:
180 int mShaderVersion;
181};
182
Zhenyao Mo72111912016-07-20 17:45:56 -0700183} // namespace anonymous
184
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300185TIntermSequence *CreateInitCode(const TIntermTyped *initializedSymbol)
Olli Etuaho9733cee2017-05-11 19:14:35 +0300186{
187 TIntermSequence *initCode = new TIntermSequence();
188 if (initializedSymbol->isArray())
189 {
190 AddArrayZeroInitSequence(initializedSymbol, initCode);
191 }
192 else if (initializedSymbol->getType().isStructureContainingArrays() ||
Olli Etuaho858ff482017-11-15 13:41:46 +0200193 initializedSymbol->getType().isNamelessStruct())
Olli Etuaho9733cee2017-05-11 19:14:35 +0300194 {
195 AddStructZeroInitSequence(initializedSymbol, initCode);
196 }
197 else
198 {
199 initCode->push_back(CreateZeroInitAssignment(initializedSymbol));
200 }
201 return initCode;
202}
203
204void InitializeUninitializedLocals(TIntermBlock *root, int shaderVersion)
205{
206 InitializeLocalsTraverser traverser(shaderVersion);
207 root->traverse(&traverser);
208 traverser.updateTree();
209}
210
Olli Etuaho9cbc07c2017-05-10 18:22:01 +0300211void InitializeVariables(TIntermBlock *root,
Zhenyao Mod7490962016-11-09 15:49:51 -0800212 const InitVariableList &vars,
Martin Radeve145def2017-06-22 12:49:12 +0300213 const TSymbolTable &symbolTable,
214 int shaderVersion,
Martin Radeve145def2017-06-22 12:49:12 +0300215 const TExtensionBehavior &extensionBehavior)
Zhenyao Mo72111912016-07-20 17:45:56 -0700216{
Martin Radevb50ccd32017-07-06 17:09:58 +0300217 TIntermBlock *body = FindMainBody(root);
Olli Etuahodaaff1c2017-07-05 18:03:26 +0300218 InsertInitCode(body->getSequence(), vars, symbolTable, shaderVersion, extensionBehavior);
Zhenyao Mo72111912016-07-20 17:45:56 -0700219}
Jamie Madill45bcc782016-11-07 13:58:48 -0500220
221} // namespace sh