1 //
2 // Copyright 2018 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 // SeparateStructFromUniformDeclarations: Separate struct declarations from uniform declarations.
7 //
8
9 #include "compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.h"
10 #include "compiler/translator/SymbolTable.h"
11 #include "compiler/translator/tree_util/IntermTraverse.h"
12 #include "compiler/translator/tree_util/ReplaceVariable.h"
13
14 namespace sh
15 {
16 namespace
17 {
18 // This traverser translates embedded uniform structs into a specifier and declaration.
19 // This makes the declarations easier to move into uniform blocks.
20 class Traverser : public TIntermTraverser
21 {
22 public:
Traverser(TSymbolTable * symbolTable)23 explicit Traverser(TSymbolTable *symbolTable)
24 : TIntermTraverser(true, false, false, symbolTable)
25 {}
26
visitDeclaration(Visit visit,TIntermDeclaration * decl)27 bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override
28 {
29 ASSERT(visit == PreVisit);
30
31 if (!mInGlobalScope)
32 {
33 return true;
34 }
35
36 const TIntermSequence &sequence = *(decl->getSequence());
37 ASSERT(sequence.size() == 1);
38 TIntermTyped *declarator = sequence.front()->getAsTyped();
39 const TType &type = declarator->getType();
40
41 if (type.isStructSpecifier() && type.getQualifier() == EvqUniform)
42 {
43 doReplacement(decl, declarator, type);
44 return false;
45 }
46
47 return true;
48 }
49
visitSymbol(TIntermSymbol * symbol)50 void visitSymbol(TIntermSymbol *symbol) override
51 {
52 const TVariable *variable = &symbol->variable();
53 if (mVariableMap.count(variable) > 0)
54 {
55 queueAccessChainReplacement(mVariableMap[variable]->deepCopy());
56 }
57 }
58
59 private:
doReplacement(TIntermDeclaration * decl,TIntermTyped * declarator,const TType & oldType)60 void doReplacement(TIntermDeclaration *decl, TIntermTyped *declarator, const TType &oldType)
61 {
62 const TStructure *structure = oldType.getStruct();
63 if (structure->symbolType() == SymbolType::Empty)
64 {
65 // Handle nameless structs: uniform struct { ... } variable;
66 structure = new TStructure(mSymbolTable, kEmptyImmutableString, &structure->fields(),
67 SymbolType::AngleInternal);
68 }
69 TType *namedType = new TType(structure, true);
70 namedType->setQualifier(EvqGlobal);
71
72 TVariable *structVariable =
73 new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
74 TIntermSymbol *structDeclarator = new TIntermSymbol(structVariable);
75 TIntermDeclaration *structDeclaration = new TIntermDeclaration;
76 structDeclaration->appendDeclarator(structDeclarator);
77
78 TIntermSequence newSequence;
79 newSequence.push_back(structDeclaration);
80
81 // Redeclare the uniform with the (potentially) new struct type
82 TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
83 ASSERT(asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty);
84
85 TIntermDeclaration *namedDecl = new TIntermDeclaration;
86 TType *uniformType = new TType(structure, false);
87 uniformType->setQualifier(EvqUniform);
88 uniformType->makeArrays(oldType.getArraySizes());
89
90 TVariable *newVar = new TVariable(mSymbolTable, asSymbol->getName(), uniformType,
91 asSymbol->variable().symbolType());
92 TIntermSymbol *newSymbol = new TIntermSymbol(newVar);
93 namedDecl->appendDeclarator(newSymbol);
94
95 newSequence.push_back(namedDecl);
96
97 mVariableMap[&asSymbol->variable()] = newSymbol;
98
99 mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl,
100 std::move(newSequence));
101 }
102
103 VariableReplacementMap mVariableMap;
104 };
105 } // anonymous namespace
106
SeparateStructFromUniformDeclarations(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)107 bool SeparateStructFromUniformDeclarations(TCompiler *compiler,
108 TIntermBlock *root,
109 TSymbolTable *symbolTable)
110 {
111 Traverser separateStructDecls(symbolTable);
112 root->traverse(&separateStructDecls);
113 return separateStructDecls.updateTree(compiler, root);
114 }
115 } // namespace sh
116