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/tree_ops/msl/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.getStruct()->symbolType() == SymbolType::Empty)
44 {
45 doReplacement(decl, declarator, type);
46 }
47
48 return false;
49 }
visitSymbol(TIntermSymbol * decl)50 void visitSymbol(TIntermSymbol *decl) override
51 {
52 auto symbol = replacements.find(decl->uniqueId().get());
53 if (symbol != replacements.end())
54 {
55 queueReplacement(symbol->second->deepCopy(), OriginalNode::IS_DROPPED);
56 }
57 }
58
59 private:
doReplacement(TIntermDeclaration * decl,TIntermTyped * declarator,const TType & oldType)60 void doReplacement(TIntermDeclaration *decl, TIntermTyped *declarator, const TType &oldType)
61 {
62 const TStructure *oldStructure = oldType.getStruct();
63 // struct <structName> { ... };
64 TStructure *structure = new TStructure(mSymbolTable, kEmptyImmutableString,
65 &oldStructure->fields(), SymbolType::AngleInternal);
66 TType *namedType = new TType(structure, true);
67 namedType->setQualifier(EvqGlobal);
68
69 TVariable *structVariable =
70 new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
71 TIntermSymbol *structDeclarator = new TIntermSymbol(structVariable);
72 TIntermDeclaration *structDeclaration = new TIntermDeclaration;
73 structDeclaration->appendDeclarator(structDeclarator);
74
75 TIntermSequence *newSequence = new TIntermSequence;
76 newSequence->push_back(structDeclaration);
77
78 // uniform <structName> <structUniformName>;
79 TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
80 if (asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty)
81 {
82 TIntermDeclaration *namedDecl = new TIntermDeclaration;
83 TType *uniformType = new TType(structure, false);
84 uniformType->setQualifier(EvqUniform);
85 uniformType->makeArrays(oldType.getArraySizes());
86
87 TVariable *newVar = new TVariable(mSymbolTable, asSymbol->getName(), uniformType,
88 asSymbol->variable().symbolType());
89 TIntermSymbol *newSymbol = new TIntermSymbol(newVar);
90 replacements[asSymbol->uniqueId().get()] = newSymbol;
91 namedDecl->appendDeclarator(newSymbol);
92
93 newSequence->push_back(namedDecl);
94 }
95
96 mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl,
97 std::move(*newSequence));
98 }
99 };
100 } // anonymous namespace
101
NameEmbeddedStructUniformsMetal(TCompiler * compiler,TIntermBlock * root,TSymbolTable * symbolTable)102 bool NameEmbeddedStructUniformsMetal(TCompiler *compiler,
103 TIntermBlock *root,
104 TSymbolTable *symbolTable)
105 {
106 Traverser nameStructs(symbolTable);
107 root->traverse(&nameStructs);
108 return nameStructs.updateTree(compiler, root);
109 }
110 } // namespace sh
111