summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.cpp
blob: fb3f4ba1c1b7727a25f2adb17cc91f60f575d26c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//
// Copyright 2018 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// SeparateStructFromUniformDeclarations: Separate struct declarations from uniform declarations.
//

#include "compiler/translator/tree_ops/SeparateStructFromUniformDeclarations.h"
#include "compiler/translator/SymbolTable.h"
#include "compiler/translator/tree_util/IntermTraverse.h"
#include "compiler/translator/tree_util/ReplaceVariable.h"

namespace sh
{
namespace
{
// This traverser translates embedded uniform structs into a specifier and declaration.
// This makes the declarations easier to move into uniform blocks.
class Traverser : public TIntermTraverser
{
  public:
    explicit Traverser(TSymbolTable *symbolTable)
        : TIntermTraverser(true, false, false, symbolTable)
    {}

    bool visitDeclaration(Visit visit, TIntermDeclaration *decl) override
    {
        ASSERT(visit == PreVisit);

        if (!mInGlobalScope)
        {
            return true;
        }

        const TIntermSequence &sequence = *(decl->getSequence());
        ASSERT(sequence.size() == 1);
        TIntermTyped *declarator = sequence.front()->getAsTyped();
        const TType &type        = declarator->getType();

        if (type.isStructSpecifier() && type.getQualifier() == EvqUniform)
        {
            doReplacement(decl, declarator, type);
            return false;
        }

        return true;
    }

    void visitSymbol(TIntermSymbol *symbol) override
    {
        const TVariable *variable = &symbol->variable();
        if (mVariableMap.count(variable) > 0)
        {
            queueAccessChainReplacement(mVariableMap[variable]->deepCopy());
        }
    }

  private:
    void doReplacement(TIntermDeclaration *decl, TIntermTyped *declarator, const TType &oldType)
    {
        const TStructure *structure = oldType.getStruct();
        if (structure->symbolType() == SymbolType::Empty)
        {
            // Handle nameless structs: uniform struct { ... } variable;
            structure = new TStructure(mSymbolTable, kEmptyImmutableString, &structure->fields(),
                                       SymbolType::AngleInternal);
        }
        TType *namedType = new TType(structure, true);
        namedType->setQualifier(EvqGlobal);

        TVariable *structVariable =
            new TVariable(mSymbolTable, kEmptyImmutableString, namedType, SymbolType::Empty);
        TIntermSymbol *structDeclarator       = new TIntermSymbol(structVariable);
        TIntermDeclaration *structDeclaration = new TIntermDeclaration;
        structDeclaration->appendDeclarator(structDeclarator);

        TIntermSequence newSequence;
        newSequence.push_back(structDeclaration);

        // Redeclare the uniform with the (potentially) new struct type
        TIntermSymbol *asSymbol = declarator->getAsSymbolNode();
        ASSERT(asSymbol && asSymbol->variable().symbolType() != SymbolType::Empty);

        TIntermDeclaration *namedDecl = new TIntermDeclaration;
        TType *uniformType            = new TType(structure, false);
        uniformType->setQualifier(EvqUniform);
        uniformType->makeArrays(oldType.getArraySizes());

        TVariable *newVar        = new TVariable(mSymbolTable, asSymbol->getName(), uniformType,
                                          asSymbol->variable().symbolType());
        TIntermSymbol *newSymbol = new TIntermSymbol(newVar);
        namedDecl->appendDeclarator(newSymbol);

        newSequence.push_back(namedDecl);

        mVariableMap[&asSymbol->variable()] = newSymbol;

        mMultiReplacements.emplace_back(getParentNode()->getAsBlock(), decl,
                                        std::move(newSequence));
    }

    VariableReplacementMap mVariableMap;
};
}  // anonymous namespace

bool SeparateStructFromUniformDeclarations(TCompiler *compiler,
                                           TIntermBlock *root,
                                           TSymbolTable *symbolTable)
{
    Traverser separateStructDecls(symbolTable);
    root->traverse(&separateStructDecls);
    return separateStructDecls.updateTree(compiler, root);
}
}  // namespace sh