NameNamelessUniformBuffers.cpp (4717B)
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: 25 explicit NameUniformBufferVariablesTraverser(TSymbolTable *symbolTable) 26 : TIntermTraverser(true, false, false, symbolTable) 27 {} 28 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 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 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