• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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