xref: /third_party/skia/src/sksl/ir/SkSLProgram.h (revision cb93a386)
1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SKSL_PROGRAM
9#define SKSL_PROGRAM
10
11#include <vector>
12#include <memory>
13
14#include "include/private/SkSLDefines.h"
15#include "include/private/SkSLModifiers.h"
16#include "include/private/SkSLProgramElement.h"
17#include "include/private/SkTHash.h"
18#include "src/sksl/SkSLAnalysis.h"
19#include "src/sksl/SkSLProgramSettings.h"
20#include "src/sksl/ir/SkSLExpression.h"
21#include "src/sksl/ir/SkSLLiteral.h"
22#include "src/sksl/ir/SkSLSymbolTable.h"
23
24#ifdef SK_VULKAN
25#include "src/gpu/vk/GrVkCaps.h"
26#endif
27
28// name of the uniform used to handle features that are sensitive to whether Y is flipped.
29#define SKSL_RTFLIP_NAME "u_skRTFlip"
30
31namespace SkSL {
32
33class Context;
34class Pool;
35
36/**
37 * Side-car class holding mutable information about a Program's IR
38 */
39class ProgramUsage {
40public:
41    struct VariableCounts {
42        int fDeclared = 0;
43        int fRead = 0;
44        int fWrite = 0;
45    };
46    VariableCounts get(const Variable&) const;
47    bool isDead(const Variable&) const;
48
49    int get(const FunctionDeclaration&) const;
50
51    void add(const Expression* expr);
52    void add(const Statement* stmt);
53    void add(const ProgramElement& element);
54    void remove(const Expression* expr);
55    void remove(const Statement* stmt);
56    void remove(const ProgramElement& element);
57
58    SkTHashMap<const Variable*, VariableCounts> fVariableCounts;
59    SkTHashMap<const FunctionDeclaration*, int> fCallCounts;
60};
61
62/**
63 * Represents a fully-digested program, ready for code generation.
64 */
65struct Program {
66    using Settings = ProgramSettings;
67
68    struct Inputs {
69        bool fUseFlipRTUniform = false;
70        bool operator==(const Inputs& that) const {
71            return fUseFlipRTUniform == that.fUseFlipRTUniform;
72        }
73        bool operator!=(const Inputs& that) const { return !(*this == that); }
74    };
75
76    Program(std::unique_ptr<String> source,
77            std::unique_ptr<ProgramConfig> config,
78            std::shared_ptr<Context> context,
79            std::vector<std::unique_ptr<ProgramElement>> elements,
80            std::vector<const ProgramElement*> sharedElements,
81            std::unique_ptr<ModifiersPool> modifiers,
82            std::shared_ptr<SymbolTable> symbols,
83            std::unique_ptr<Pool> pool,
84            Inputs inputs)
85    : fSource(std::move(source))
86    , fConfig(std::move(config))
87    , fContext(context)
88    , fSymbols(symbols)
89    , fPool(std::move(pool))
90    , fOwnedElements(std::move(elements))
91    , fSharedElements(std::move(sharedElements))
92    , fInputs(inputs)
93    , fModifiers(std::move(modifiers)) {
94        fUsage = Analysis::GetUsage(*this);
95    }
96
97    ~Program() {
98        // Some or all of the program elements are in the pool. To free them safely, we must attach
99        // the pool before destroying any program elements. (Otherwise, we may accidentally call
100        // delete on a pooled node.)
101        AutoAttachPoolToThread attach(fPool.get());
102
103        fOwnedElements.clear();
104        fContext.reset();
105        fSymbols.reset();
106        fModifiers.reset();
107    }
108
109    class ElementsCollection {
110    public:
111        class iterator {
112        public:
113            const ProgramElement* operator*() {
114                if (fShared != fSharedEnd) {
115                    return *fShared;
116                } else {
117                    return fOwned->get();
118                }
119            }
120
121            iterator& operator++() {
122                if (fShared != fSharedEnd) {
123                    ++fShared;
124                } else {
125                    ++fOwned;
126                }
127                return *this;
128            }
129
130            bool operator==(const iterator& other) const {
131                return fOwned == other.fOwned && fShared == other.fShared;
132            }
133
134            bool operator!=(const iterator& other) const {
135                return !(*this == other);
136            }
137
138        private:
139            using Owned  = std::vector<std::unique_ptr<ProgramElement>>::const_iterator;
140            using Shared = std::vector<const ProgramElement*>::const_iterator;
141            friend class ElementsCollection;
142
143            iterator(Owned owned, Owned ownedEnd, Shared shared, Shared sharedEnd)
144                    : fOwned(owned), fOwnedEnd(ownedEnd), fShared(shared), fSharedEnd(sharedEnd) {}
145
146            Owned  fOwned;
147            Owned  fOwnedEnd;
148            Shared fShared;
149            Shared fSharedEnd;
150        };
151
152        iterator begin() const {
153            return iterator(fProgram.fOwnedElements.begin(), fProgram.fOwnedElements.end(),
154                            fProgram.fSharedElements.begin(), fProgram.fSharedElements.end());
155        }
156
157        iterator end() const {
158            return iterator(fProgram.fOwnedElements.end(), fProgram.fOwnedElements.end(),
159                            fProgram.fSharedElements.end(), fProgram.fSharedElements.end());
160        }
161
162    private:
163        friend struct Program;
164
165        ElementsCollection(const Program& program) : fProgram(program) {}
166        const Program& fProgram;
167    };
168
169    // Can be used to iterate over *all* elements in this Program, both owned and shared (builtin).
170    // The iterator's value type is 'const ProgramElement*', so it's clear that you *must not*
171    // modify anything (as you might be mutating shared data).
172    ElementsCollection elements() const { return ElementsCollection(*this); }
173
174    String description() const {
175        String result;
176        for (const ProgramElement* e : this->elements()) {
177            result += e->description();
178        }
179        return result;
180    }
181
182    const ProgramUsage* usage() const { return fUsage.get(); }
183
184    std::unique_ptr<String> fSource;
185    std::unique_ptr<ProgramConfig> fConfig;
186    std::shared_ptr<Context> fContext;
187    // it's important to keep fOwnedElements defined after (and thus destroyed before) fSymbols,
188    // because destroying elements can modify reference counts in symbols
189    std::shared_ptr<SymbolTable> fSymbols;
190    std::unique_ptr<Pool> fPool;
191    // Contains *only* elements owned exclusively by this program.
192    std::vector<std::unique_ptr<ProgramElement>> fOwnedElements;
193    // Contains *only* elements owned by a built-in module that are included in this program.
194    // Use elements() to iterate over the combined set of owned + shared elements.
195    std::vector<const ProgramElement*> fSharedElements;
196    Inputs fInputs;
197
198private:
199    std::unique_ptr<ModifiersPool> fModifiers;
200    std::unique_ptr<ProgramUsage> fUsage;
201
202    friend class Compiler;
203    friend class Inliner;             // fUsage
204    friend class SPIRVCodeGenerator;  // fModifiers
205};
206
207}  // namespace SkSL
208
209#endif
210