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 "SkSLBoolLiteral.h"
15 #include "SkSLExpression.h"
16 #include "SkSLIntLiteral.h"
17 #include "SkSLModifiers.h"
18 #include "SkSLProgramElement.h"
19 #include "SkSLSymbolTable.h"
20 
21 // name of the render target width uniform
22 #define SKSL_RTWIDTH_NAME "u_skRTWidth"
23 
24 // name of the render target height uniform
25 #define SKSL_RTHEIGHT_NAME "u_skRTHeight"
26 
27 namespace SkSL {
28 
29 class Context;
30 
31 /**
32  * Represents a fully-digested program, ready for code generation.
33  */
34 struct Program {
35     struct Settings {
36         struct Value {
ValueProgram::Settings::Value37             Value(bool b)
38             : fKind(kBool_Kind)
39             , fValue(b) {}
40 
ValueProgram::Settings::Value41             Value(int i)
42             : fKind(kInt_Kind)
43             , fValue(i) {}
44 
ValueProgram::Settings::Value45             Value(unsigned int i)
46             : fKind(kInt_Kind)
47             , fValue(i) {}
48 
literalProgram::Settings::Value49             std::unique_ptr<Expression> literal(const Context& context, int offset) const {
50                 switch (fKind) {
51                     case Program::Settings::Value::kBool_Kind:
52                         return std::unique_ptr<Expression>(new BoolLiteral(context,
53                                                                            offset,
54                                                                            fValue));
55                     case Program::Settings::Value::kInt_Kind:
56                         return std::unique_ptr<Expression>(new IntLiteral(context,
57                                                                           offset,
58                                                                           fValue));
59                     default:
60                         SkASSERT(false);
61                         return nullptr;
62                 }
63             }
64 
65             enum {
66                 kBool_Kind,
67                 kInt_Kind,
68             } fKind;
69 
70             int fValue;
71         };
72 
73 #ifdef SKSL_STANDALONE
74         const StandaloneShaderCaps* fCaps = &standaloneCaps;
75 #else
76         const GrShaderCaps* fCaps = nullptr;
77 #endif
78         // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the y coordinate
79         // must be flipped.
80         bool fFlipY = false;
81         // If true the destination fragment color is read sk_FragColor. It must be declared inout.
82         bool fFragColorIsInOut = false;
83         // if true, Setting objects (e.g. sk_Caps.fbFetchSupport) should be replaced with their
84         // constant equivalents during compilation
85         bool fReplaceSettings = true;
86         // if true, all halfs are forced to be floats
87         bool fForceHighPrecision = false;
88         // if true, add -0.5 bias to LOD of all texture lookups
89         bool fSharpenTextures = false;
90         std::unordered_map<String, Value> fArgs;
91     };
92 
93     struct Inputs {
94         // if true, this program requires the render target width uniform to be defined
95         bool fRTWidth;
96 
97         // if true, this program requires the render target height uniform to be defined
98         bool fRTHeight;
99 
100         // if true, this program must be recompiled if the flipY setting changes. If false, the
101         // program will compile to the same code regardless of the flipY setting.
102         bool fFlipY;
103 
resetProgram::Inputs104         void reset() {
105             fRTWidth = false;
106             fRTHeight = false;
107             fFlipY = false;
108         }
109 
isEmptyProgram::Inputs110         bool isEmpty() {
111             return !fRTWidth && !fRTHeight && !fFlipY;
112         }
113     };
114 
115     class iterator {
116     public:
117         ProgramElement& operator*() {
118             if (fIter1 != fEnd1) {
119                 return **fIter1;
120             }
121             return **fIter2;
122         }
123 
124         iterator& operator++() {
125             if (fIter1 != fEnd1) {
126                 ++fIter1;
127                 return *this;
128             }
129             ++fIter2;
130             return *this;
131         }
132 
133         bool operator==(const iterator& other) const {
134             return fIter1 == other.fIter1 && fIter2 == other.fIter2;
135         }
136 
137         bool operator!=(const iterator& other) const {
138             return !(*this == other);
139         }
140 
141     private:
142         using inner = std::vector<std::unique_ptr<ProgramElement>>::iterator;
143 
iteratorProgram144         iterator(inner begin1, inner end1, inner begin2, inner end2)
145         : fIter1(begin1)
146         , fEnd1(end1)
147         , fIter2(begin2)
148         , fEnd2(end2) {}
149 
150         inner fIter1;
151         inner fEnd1;
152         inner fIter2;
153         inner fEnd2;
154 
155         friend struct Program;
156     };
157 
158     class const_iterator {
159     public:
160         const ProgramElement& operator*() {
161             if (fIter1 != fEnd1) {
162                 return **fIter1;
163             }
164             return **fIter2;
165         }
166 
167         const_iterator& operator++() {
168             if (fIter1 != fEnd1) {
169                 ++fIter1;
170                 return *this;
171             }
172             ++fIter2;
173             return *this;
174         }
175 
176         bool operator==(const const_iterator& other) const {
177             return fIter1 == other.fIter1 && fIter2 == other.fIter2;
178         }
179 
180         bool operator!=(const const_iterator& other) const {
181             return !(*this == other);
182         }
183 
184     private:
185         using inner = std::vector<std::unique_ptr<ProgramElement>>::const_iterator;
186 
const_iteratorProgram187         const_iterator(inner begin1, inner end1, inner begin2, inner end2)
188         : fIter1(begin1)
189         , fEnd1(end1)
190         , fIter2(begin2)
191         , fEnd2(end2) {}
192 
193         inner fIter1;
194         inner fEnd1;
195         inner fIter2;
196         inner fEnd2;
197 
198         friend struct Program;
199     };
200 
201     enum Kind {
202         kFragment_Kind,
203         kVertex_Kind,
204         kGeometry_Kind,
205         kFragmentProcessor_Kind,
206         kPipelineStage_Kind
207     };
208 
ProgramProgram209     Program(Kind kind,
210             std::unique_ptr<String> source,
211             Settings settings,
212             std::shared_ptr<Context> context,
213             std::vector<std::unique_ptr<ProgramElement>>* inheritedElements,
214             std::vector<std::unique_ptr<ProgramElement>> elements,
215             std::shared_ptr<SymbolTable> symbols,
216             Inputs inputs)
217     : fKind(kind)
218     , fSource(std::move(source))
219     , fSettings(settings)
220     , fContext(context)
221     , fSymbols(symbols)
222     , fInputs(inputs)
223     , fInheritedElements(inheritedElements)
224     , fElements(std::move(elements)) {}
225 
beginProgram226     iterator begin() {
227         if (fInheritedElements) {
228             return iterator(fInheritedElements->begin(), fInheritedElements->end(),
229                             fElements.begin(), fElements.end());
230         }
231         return iterator(fElements.begin(), fElements.end(), fElements.end(), fElements.end());
232     }
233 
endProgram234     iterator end() {
235         if (fInheritedElements) {
236             return iterator(fInheritedElements->end(), fInheritedElements->end(),
237                             fElements.end(), fElements.end());
238         }
239         return iterator(fElements.end(), fElements.end(), fElements.end(), fElements.end());
240     }
241 
beginProgram242     const_iterator begin() const {
243         if (fInheritedElements) {
244             return const_iterator(fInheritedElements->begin(), fInheritedElements->end(),
245                                   fElements.begin(), fElements.end());
246         }
247         return const_iterator(fElements.begin(), fElements.end(), fElements.end(), fElements.end());
248     }
249 
endProgram250     const_iterator end() const {
251         if (fInheritedElements) {
252             return const_iterator(fInheritedElements->end(), fInheritedElements->end(),
253                                   fElements.end(), fElements.end());
254         }
255         return const_iterator(fElements.end(), fElements.end(), fElements.end(), fElements.end());
256     }
257 
258     Kind fKind;
259     std::unique_ptr<String> fSource;
260     Settings fSettings;
261     std::shared_ptr<Context> fContext;
262     // it's important to keep fElements defined after (and thus destroyed before) fSymbols,
263     // because destroying elements can modify reference counts in symbols
264     std::shared_ptr<SymbolTable> fSymbols;
265     Inputs fInputs;
266     bool fIsOptimized = false;
267 
268 private:
269     std::vector<std::unique_ptr<ProgramElement>>* fInheritedElements;
270     std::vector<std::unique_ptr<ProgramElement>> fElements;
271 
272     friend class Compiler;
273 };
274 
275 } // namespace
276 
277 #endif
278