RegenerateStructNames.cpp (3805B)
1 // 2 // Copyright 2002 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 7 #include "compiler/translator/tree_ops/gl/RegenerateStructNames.h" 8 9 #include "common/debug.h" 10 #include "compiler/translator/Compiler.h" 11 #include "compiler/translator/ImmutableStringBuilder.h" 12 #include "compiler/translator/SymbolTable.h" 13 #include "compiler/translator/tree_util/IntermTraverse.h" 14 15 #include <set> 16 17 namespace sh 18 { 19 20 namespace 21 { 22 constexpr const ImmutableString kPrefix("_webgl_struct_"); 23 } // anonymous namespace 24 25 class RegenerateStructNamesTraverser : public TIntermTraverser 26 { 27 public: 28 RegenerateStructNamesTraverser(TSymbolTable *symbolTable) 29 : TIntermTraverser(true, false, false, symbolTable), mScopeDepth(0) 30 {} 31 32 protected: 33 void visitSymbol(TIntermSymbol *) override; 34 bool visitBlock(Visit, TIntermBlock *block) override; 35 36 private: 37 // Indicating the depth of the current scope. 38 // The global scope is 1. 39 int mScopeDepth; 40 41 // If a struct is declared globally, push its ID in this set. 42 std::set<int> mDeclaredGlobalStructs; 43 }; 44 45 void RegenerateStructNamesTraverser::visitSymbol(TIntermSymbol *symbol) 46 { 47 ASSERT(symbol); 48 const TType &type = symbol->getType(); 49 const TStructure *userType = type.getStruct(); 50 if (!userType) 51 return; 52 53 if (userType->symbolType() == SymbolType::BuiltIn || 54 userType->symbolType() == SymbolType::Empty) 55 { 56 // Built-in struct or nameless struct, do not touch it. 57 return; 58 } 59 60 int uniqueId = userType->uniqueId().get(); 61 62 ASSERT(mScopeDepth > 0); 63 if (mScopeDepth == 1) 64 { 65 // If a struct is defined at global scope, we don't map its name. 66 // This is because at global level, the struct might be used to 67 // declare a uniform, so the same name needs to stay the same for 68 // vertex/fragment shaders. However, our mapping uses internal ID, 69 // which will be different for the same struct in vertex/fragment 70 // shaders. 71 // This is OK because names for any structs defined in other scopes 72 // will begin with "_webgl", which is reserved. So there will be 73 // no conflicts among unmapped struct names from global scope and 74 // mapped struct names from other scopes. 75 // However, we need to keep track of these global structs, so if a 76 // variable is used in a local scope, we don't try to modify the 77 // struct name through that variable. 78 mDeclaredGlobalStructs.insert(uniqueId); 79 return; 80 } 81 if (mDeclaredGlobalStructs.count(uniqueId) > 0) 82 return; 83 // Map {name} to _webgl_struct_{uniqueId}_{name}. 84 if (userType->name().beginsWith(kPrefix)) 85 { 86 // The name has already been regenerated. 87 return; 88 } 89 ImmutableStringBuilder tmp(kPrefix.length() + sizeof(uniqueId) * 2u + 1u + 90 userType->name().length()); 91 tmp << kPrefix; 92 tmp.appendHex(uniqueId); 93 tmp << '_' << userType->name(); 94 95 // TODO(oetuaho): Add another mechanism to change symbol names so that the const_cast is not 96 // needed. 97 const_cast<TStructure *>(userType)->setName(tmp); 98 } 99 100 bool RegenerateStructNamesTraverser::visitBlock(Visit, TIntermBlock *block) 101 { 102 ++mScopeDepth; 103 TIntermSequence &sequence = *(block->getSequence()); 104 for (TIntermNode *node : sequence) 105 { 106 node->traverse(this); 107 } 108 --mScopeDepth; 109 return false; 110 } 111 112 bool RegenerateStructNames(TCompiler *compiler, TIntermBlock *root, TSymbolTable *symbolTable) 113 { 114 RegenerateStructNamesTraverser traverser(symbolTable); 115 root->traverse(&traverser); 116 return compiler->validateAST(root); 117 } 118 119 } // namespace sh