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 // NameEmbeddedUniformStructsMetal: Gives nameless uniform struct internal names.
7 //
8 
9 #include "compiler/translator/TranslatorMetalDirect/NameEmbeddedUniformStructsMetal.h"
10 
11 #include "compiler/translator/SymbolTable.h"
12 #include "compiler/translator/tree_util/IntermTraverse.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 
23   public:
24     std::unordered_map<int, TIntermSymbol *> replacements;
Traverser(TSymbolTable * symbolTable)25     explicit Traverser(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         if (!mInGlobalScope)
34         {
35             return false;
36         }
37 
38         const TIntermSequence &sequence = *(decl->getSequence());
39         ASSERT(sequence.size() == 1);
40         TIntermTyped *declarator = sequence.front()->getAsTyped();
41         const TType &type        = declarator->getType();
42 
43         if (type.isStructSpecifier() && type.getQualifier() == EvqUniform)
44         {
45             const TStructure *structure = type.getStruct();
46 
47             if (structure->symbolType() == SymbolType::Empty)
48             {
49                 doReplacement(decl, declarator, structure);
50             }
51         }
52 
53         return false;
54     }
visitSymbol(TIntermSymbol * decl)55     void visitSymbol(TIntermSymbol *decl) override
56     {
57         auto symbol = replacements.find(decl->uniqueId().get());
58         if (symbol != replacements.end())
59         {
60             queueReplacement(symbol->second->deepCopy(), OriginalNode::IS_DROPPED);
61         }
62     }
63 
64   private:
doReplacement(TIntermDeclaration * decl,TIntermTyped * declarator,const TStructure * oldStructure)65     void doReplacement(TIntermDeclaration *decl,
66                        TIntermTyped *declarator,
67                        const TStructure *oldStructure)
68     {
69         // struct <structName> { ... };
70         TStructure *structure = new TStructure(mSymbolTable, kEmptyImmutableString,
71                                                &oldStructure->fields(), SymbolType::AngleInternal);
72         TType *namedType      = new TType(structure, true);
73         namedType->setQualifier(EvqGlobal);
74 
75         TVariable *structVariable =
76             new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
77         TIntermSymbol *structDeclarator       = new TIntermSymbol(structVariable);
78         TIntermDeclaration *structDeclaration = new TIntermDeclaration;
79         structDeclaration->appendDeclarator(structDeclarator);
80 
81         TIntermSequence *newSequence = new TIntermSequence;
82         newSequence->push_back(structDeclaration);
83 
84         // uniform <structName> <structUniformName>;
85         TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
86         if (asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty)
87         {
88             TIntermDeclaration *namedDecl = new TIntermDeclaration;
89             TType *uniformType            = new TType(structure, false);
90             uniformType->setQualifier(EvqUniform);
91 
92             TVariable *newVar        = new TVariable(mSymbolTable, asSymbol->getName(), uniformType,
93                                               asSymbol->variable().symbolType());
94             TIntermSymbol *newSymbol = new TIntermSymbol(newVar);
95             replacements[asSymbol->uniqueId().get()] = newSymbol;
96             namedDecl->appendDeclarator(newSymbol);
97 
98             newSequence->push_back(namedDecl);
99         }
100 
101         mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl,
102                                         std::move(*newSequence));
103     }
104 };
105 }  // anonymous namespace
106 
NameEmbeddedStructUniformsMetal(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)107 bool NameEmbeddedStructUniformsMetal(TCompiler *compiler,
108                                      TIntermBlock *root,
109                                      TSymbolTable *symbolTable)
110 {
111     Traverser nameStructs(symbolTable);
112     root->traverse(&nameStructs);
113     return nameStructs.updateTree(compiler, root);
114 }
115 }  // namespace sh
116