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:
RegenerateStructNamesTraverser(TSymbolTable * symbolTable)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 
visitSymbol(TIntermSymbol * symbol)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 
visitBlock(Visit,TIntermBlock * block)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 
RegenerateStructNames(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)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
120