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