SeparateStructFromUniformDeclarations.cpp (4226B)
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: 23 explicit Traverser(TSymbolTable *symbolTable) 24 : TIntermTraverser(true, false, false, symbolTable) 25 {} 26 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 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: 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 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