// // Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // #include "compiler/translator/InitializeVariables.h" #include "angle_gl.h" #include "common/debug.h" #include "compiler/translator/IntermNode.h" #include "compiler/translator/util.h" namespace { TIntermConstantUnion *constructConstUnionNode(const TType &type) { TType myType = type; myType.clearArrayness(); myType.setQualifier(EvqConst); size_t size = myType.getObjectSize(); TConstantUnion *u = new TConstantUnion[size]; for (size_t ii = 0; ii < size; ++ii) { switch (type.getBasicType()) { case EbtFloat: u[ii].setFConst(0.0f); break; case EbtInt: u[ii].setIConst(0); break; case EbtUInt: u[ii].setUConst(0u); break; default: UNREACHABLE(); return nullptr; } } TIntermConstantUnion *node = new TIntermConstantUnion(u, myType); return node; } TIntermConstantUnion *constructIndexNode(int index) { TConstantUnion *u = new TConstantUnion[1]; u[0].setIConst(index); TType type(EbtInt, EbpUndefined, EvqConst, 1); TIntermConstantUnion *node = new TIntermConstantUnion(u, type); return node; } class VariableInitializer : public TIntermTraverser { public: VariableInitializer(const InitVariableList &vars) : TIntermTraverser(true, false, false), mVariables(vars), mCodeInserted(false) { } protected: bool visitBinary(Visit, TIntermBinary *node) override { return false; } bool visitUnary(Visit, TIntermUnary *node) override { return false; } bool visitSelection(Visit, TIntermSelection *node) override { return false; } bool visitLoop(Visit, TIntermLoop *node) override { return false; } bool visitBranch(Visit, TIntermBranch *node) override { return false; } bool visitAggregate(Visit visit, TIntermAggregate *node) override; private: void insertInitCode(TIntermSequence *sequence); const InitVariableList &mVariables; bool mCodeInserted; }; // VariableInitializer implementation. bool VariableInitializer::visitAggregate(Visit visit, TIntermAggregate *node) { bool visitChildren = !mCodeInserted; switch (node->getOp()) { case EOpSequence: break; case EOpFunction: { // Function definition. ASSERT(visit == PreVisit); if (node->getName() == "main(") { TIntermSequence *sequence = node->getSequence(); ASSERT((sequence->size() == 1) || (sequence->size() == 2)); TIntermAggregate *body = NULL; if (sequence->size() == 1) { body = new TIntermAggregate(EOpSequence); sequence->push_back(body); } else { body = (*sequence)[1]->getAsAggregate(); } ASSERT(body); insertInitCode(body->getSequence()); mCodeInserted = true; } break; } default: visitChildren = false; break; } return visitChildren; } void VariableInitializer::insertInitCode(TIntermSequence *sequence) { for (size_t ii = 0; ii < mVariables.size(); ++ii) { const sh::ShaderVariable &var = mVariables[ii]; TString name = TString(var.name.c_str()); if (var.isArray()) { TType type = sh::ConvertShaderVariableTypeToTType(var.type); size_t pos = name.find_last_of('['); if (pos != TString::npos) name = name.substr(0, pos); for (int index = static_cast(var.arraySize) - 1; index >= 0; --index) { TIntermBinary *assign = new TIntermBinary(EOpAssign); sequence->insert(sequence->begin(), assign); TIntermBinary *indexDirect = new TIntermBinary(EOpIndexDirect); TIntermSymbol *symbol = new TIntermSymbol(0, name, type); indexDirect->setLeft(symbol); TIntermConstantUnion *indexNode = constructIndexNode(index); indexDirect->setRight(indexNode); assign->setLeft(indexDirect); TIntermConstantUnion *zeroConst = constructConstUnionNode(type); assign->setRight(zeroConst); } } else if (var.isStruct()) { TFieldList *fields = new TFieldList; TSourceLoc loc; for (auto field : var.fields) { fields->push_back(new TField(nullptr, new TString(field.name.c_str()), loc)); } TStructure *structure = new TStructure(new TString(var.structName.c_str()), fields); TType type; type.setStruct(structure); for (int fieldIndex = 0; fieldIndex < static_cast(var.fields.size()); ++fieldIndex) { TIntermBinary *assign = new TIntermBinary(EOpAssign); sequence->insert(sequence->begin(), assign); TIntermBinary *indexDirectStruct = new TIntermBinary(EOpIndexDirectStruct); TIntermSymbol *symbol = new TIntermSymbol(0, name, type); indexDirectStruct->setLeft(symbol); TIntermConstantUnion *indexNode = constructIndexNode(fieldIndex); indexDirectStruct->setRight(indexNode); assign->setLeft(indexDirectStruct); const sh::ShaderVariable &field = var.fields[fieldIndex]; TType fieldType = sh::ConvertShaderVariableTypeToTType(field.type); TIntermConstantUnion *zeroConst = constructConstUnionNode(fieldType); assign->setRight(zeroConst); } } else { TType type = sh::ConvertShaderVariableTypeToTType(var.type); TIntermBinary *assign = new TIntermBinary(EOpAssign); sequence->insert(sequence->begin(), assign); TIntermSymbol *symbol = new TIntermSymbol(0, name, type); assign->setLeft(symbol); TIntermConstantUnion *zeroConst = constructConstUnionNode(type); assign->setRight(zeroConst); } } } } // namespace anonymous void InitializeVariables(TIntermNode *root, const InitVariableList &vars) { VariableInitializer initializer(vars); root->traverse(&initializer); }