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