1 //
2 // Copyright 2019 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 // NameNamelessUniformBuffers: Gives nameless uniform buffer variables internal names.
7 //
8
9 #include "compiler/translator/tree_ops/NameNamelessUniformBuffers.h"
10
11 #include "compiler/translator/SymbolTable.h"
12 #include "compiler/translator/tree_util/IntermNode_util.h"
13 #include "compiler/translator/tree_util/IntermTraverse.h"
14
15 namespace sh
16 {
17 namespace
18 {
19 // Traverse uniform buffer declarations and give name to nameless declarations. Keeps track of
20 // the interface fields which will be used in the source without the interface block variable name
21 // and replaces them with name.field.
22 class NameUniformBufferVariablesTraverser : public TIntermTraverser
23 {
24 public:
NameUniformBufferVariablesTraverser(TSymbolTable * symbolTable)25 explicit NameUniformBufferVariablesTraverser(TSymbolTable *symbolTable)
26 : TIntermTraverser(true, false, false, symbolTable)
27 {}
28
visitDeclaration(Visit visit,TIntermDeclaration * decl)29 bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override
30 {
31 ASSERT(visit == PreVisit);
32
33 const TIntermSequence &sequence = *(decl->getSequence());
34
35 TIntermTyped *variableNode = sequence.front()->getAsTyped();
36 const TType &type = variableNode->getType();
37
38 // If it's an interface block, it may have to be converted if it contains any row-major
39 // fields.
40 if (!type.isInterfaceBlock())
41 {
42 return true;
43 }
44
45 // Multi declaration statements are already separated, so there can only be one variable
46 // here.
47 ASSERT(sequence.size() == 1);
48 const TVariable *variable = &variableNode->getAsSymbolNode()->variable();
49 if (variable->symbolType() != SymbolType::Empty)
50 {
51 return false;
52 }
53
54 TIntermDeclaration *newDeclaration = new TIntermDeclaration;
55 TVariable *newVariable = new TVariable(mSymbolTable, kEmptyImmutableString, &type,
56 SymbolType::AngleInternal, variable->extensions());
57 newDeclaration->appendDeclarator(new TIntermSymbol(newVariable));
58
59 queueReplacement(newDeclaration, OriginalNode::IS_DROPPED);
60
61 // It's safe to key the map with the interface block, as there couldn't have been multiple
62 // declarations with this interface block (as the variable is nameless), so for nameless
63 // uniform buffers, the interface block is unique.
64 mNamelessUniformBuffersMap[type.getInterfaceBlock()] = newVariable;
65
66 return false;
67 }
68
visitSymbol(TIntermSymbol * symbol)69 void visitSymbol(TIntermSymbol *symbol) override
70 {
71 const TType &type = symbol->getType();
72
73 // The symbols we are looking for have the interface block pointer set, but are not
74 // interface blocks. These are references to fields of nameless uniform buffers.
75 if (type.isInterfaceBlock() || type.getInterfaceBlock() == nullptr)
76 {
77 return;
78 }
79
80 const TInterfaceBlock *block = type.getInterfaceBlock();
81
82 // If block variable is not nameless, there's nothing to do.
83 if (mNamelessUniformBuffersMap.count(block) == 0)
84 {
85 return;
86 }
87
88 const ImmutableString symbolName = symbol->getName();
89
90 // Find which field it is
91 const TVector<TField *> fields = block->fields();
92 for (size_t fieldIndex = 0; fieldIndex < fields.size(); ++fieldIndex)
93 {
94 const TField *field = fields[fieldIndex];
95 if (field->name() != symbolName)
96 {
97 continue;
98 }
99
100 // Replace this node with a binary node that indexes the named uniform buffer.
101 TIntermSymbol *namedUniformBuffer =
102 new TIntermSymbol(mNamelessUniformBuffersMap[block]);
103 TIntermBinary *replacement =
104 new TIntermBinary(EOpIndexDirectInterfaceBlock, namedUniformBuffer,
105 CreateIndexNode(static_cast<uint32_t>(fieldIndex)));
106
107 queueReplacement(replacement, OriginalNode::IS_DROPPED);
108
109 return;
110 }
111
112 UNREACHABLE();
113 }
114
115 private:
116 // A map from nameless uniform buffers to their named replacements.
117 std::unordered_map<const TInterfaceBlock *, const TVariable *> mNamelessUniformBuffersMap;
118 };
119 } // anonymous namespace
120
NameNamelessUniformBuffers(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)121 bool NameNamelessUniformBuffers(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable)
122 {
123 NameUniformBufferVariablesTraverser nameUniformBufferVariables(symbolTable);
124 root->traverse(&nameUniformBufferVariables);
125 return nameUniformBufferVariables.updateTree(compiler, root);
126 }
127 } // namespace sh
128