• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 namespace SkSL {
32 
33 class Context;
34 class Pool;
35 
36 /**
37  * Side-car class holding mutable information about a Program's IR
38  */
39 class ProgramUsage {
40 public:
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  */
65 struct 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 
ProgramProgram76     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 
~ProgramProgram97     ~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 
iteratorProgram143             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 
beginProgram152         iterator begin() const {
153             return iterator(fProgram.fOwnedElements.begin(), fProgram.fOwnedElements.end(),
154                             fProgram.fSharedElements.begin(), fProgram.fSharedElements.end());
155         }
156 
endProgram157         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 
ElementsCollectionProgram165         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).
elementsProgram172     ElementsCollection elements() const { return ElementsCollection(*this); }
173 
descriptionProgram174     String description() const {
175         String result;
176         for (const ProgramElement* e : this->elements()) {
177             result += e->description();
178         }
179         return result;
180     }
181 
usageProgram182     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 
198 private:
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