summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.cpp')
-rw-r--r--gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.cpp115
1 files changed, 115 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.cpp b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.cpp
new file mode 100644
index 0000000000..fb3f4ba1c1
--- /dev/null
+++ b/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.cpp
@@ -0,0 +1,115 @@
+//
+// Copyright 2018 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.
+//
+// SeparateStructFromUniformDeclarations: Separate struct declarations from uniform declarations.
+//
+
+#include "compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.h"
+#include "compiler/translator/SymbolTable.h"
+#include "compiler/translator/tree_util/IntermTraverse.h"
+#include "compiler/translator/tree_util/ReplaceVariable.h"
+
+namespace sh
+{
+namespace
+{
+// This traverser translates embedded uniform structs into a specifier and declaration.
+// This makes the declarations easier to move into uniform blocks.
+class Traverser : public TIntermTraverser
+{
+ public:
+ explicit Traverser(TSymbolTable *symbolTable)
+ : TIntermTraverser(true, false, false, symbolTable)
+ {}
+
+ bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override
+ {
+ ASSERT(visit == PreVisit);
+
+ if (!mInGlobalScope)
+ {
+ return true;
+ }
+
+ const TIntermSequence &sequence = *(decl->getSequence());
+ ASSERT(sequence.size() == 1);
+ TIntermTyped *declarator = sequence.front()->getAsTyped();
+ const TType &type = declarator->getType();
+
+ if (type.isStructSpecifier() && type.getQualifier() == EvqUniform)
+ {
+ doReplacement(decl, declarator, type);
+ return false;
+ }
+
+ return true;
+ }
+
+ void visitSymbol(TIntermSymbol *symbol) override
+ {
+ const TVariable *variable = &symbol->variable();
+ if (mVariableMap.count(variable) > 0)
+ {
+ queueAccessChainReplacement(mVariableMap[variable]->deepCopy());
+ }
+ }
+
+ private:
+ void doReplacement(TIntermDeclaration *decl, TIntermTyped *declarator, const TType &oldType)
+ {
+ const TStructure *structure = oldType.getStruct();
+ if (structure->symbolType() == SymbolType::Empty)
+ {
+ // Handle nameless structs: uniform struct { ... } variable;
+ structure = new TStructure(mSymbolTable, kEmptyImmutableString, &structure->fields(),
+ SymbolType::AngleInternal);
+ }
+ TType *namedType = new TType(structure, true);
+ namedType->setQualifier(EvqGlobal);
+
+ TVariable *structVariable =
+ new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
+ TIntermSymbol *structDeclarator = new TIntermSymbol(structVariable);
+ TIntermDeclaration *structDeclaration = new TIntermDeclaration;
+ structDeclaration->appendDeclarator(structDeclarator);
+
+ TIntermSequence newSequence;
+ newSequence.push_back(structDeclaration);
+
+ // Redeclare the uniform with the (potentially) new struct type
+ TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
+ ASSERT(asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty);
+
+ TIntermDeclaration *namedDecl = new TIntermDeclaration;
+ TType *uniformType = new TType(structure, false);
+ uniformType->setQualifier(EvqUniform);
+ uniformType->makeArrays(oldType.getArraySizes());
+
+ TVariable *newVar = new TVariable(mSymbolTable, asSymbol->getName(), uniformType,
+ asSymbol->variable().symbolType());
+ TIntermSymbol *newSymbol = new TIntermSymbol(newVar);
+ namedDecl->appendDeclarator(newSymbol);
+
+ newSequence.push_back(namedDecl);
+
+ mVariableMap[&asSymbol->variable()] = newSymbol;
+
+ mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl,
+ std::move(newSequence));
+ }
+
+ VariableReplacementMap mVariableMap;
+};
+} // anonymous namespace
+
+bool SeparateStructFromUniformDeclarations(TCompiler *compiler,
+ TIntermBlock *root,
+ TSymbolTable *symbolTable)
+{
+ Traverser separateStructDecls(symbolTable);
+ root->traverse(&separateStructDecls);
+ return separateStructDecls.updateTree(compiler, root);
+}
+} // namespace sh