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