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 , fValueF(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 fValueF));
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 union {
85 int fValue; // for kBool_Kind and kInt_Kind
86 float fValueF; // for kFloat_Kind
87 };
88 };
89
90#if defined(SKSL_STANDALONE) || !SK_SUPPORT_GPU
91 const StandaloneShaderCaps* fCaps = &standaloneCaps;
92#else
93 const GrShaderCaps* fCaps = nullptr;
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 false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the w coordinate
99 // must be inversed.
100 bool fInverseW = false;
101 // If true the destination fragment color is read sk_FragColor. It must be declared inout.
102 bool fFragColorIsInOut = false;
103 // if true, Setting objects (e.g. sk_Caps.fbFetchSupport) should be replaced with their
104 // constant equivalents during compilation
105 bool fReplaceSettings = true;
106 // if true, all halfs are forced to be floats
107 bool fForceHighPrecision = false;
108 // if true, add -0.5 bias to LOD of all texture lookups
109 bool fSharpenTextures = false;
110 // if the program needs to create an RTHeight uniform, this is its offset in the uniform
111 // buffer
112 int fRTHeightOffset = -1;
113 // if the program needs to create an RTHeight uniform and is creating spriv, this is the
114 // binding and set number of the uniform buffer.
115 int fRTHeightBinding = -1;
116 int fRTHeightSet = -1;
117 // If true, remove any uncalled functions other than main(). Note that a function which
118 // starts out being used may end up being uncalled after optimization.
119 bool fRemoveDeadFunctions = true;
120 // Functions smaller than this (measured in IR nodes) will be inlined. Default is arbitrary.
121 // Set to 0 to disable inlining entirely.
122 int fInlineThreshold = 50;
123 };
124
125 struct Inputs {
126 // if true, this program requires the render target width uniform to be defined
127 bool fRTWidth;
128
129 // if true, this program requires the render target height uniform to be defined
130 bool fRTHeight;
131
132 // if true, this program must be recompiled if the flipY setting changes. If false, the
133 // program will compile to the same code regardless of the flipY setting.
134 bool fFlipY;
135
136 void reset() {
137 fRTWidth = false;
138 fRTHeight = false;
139 fFlipY = false;
140 }
141
142 bool isEmpty() {
143 return !fRTWidth && !fRTHeight && !fFlipY;
144 }
145 };
146
147 class iterator {
148 public:
149 ProgramElement& operator*() {
150 if (fIter1 != fEnd1) {
151 return **fIter1;
152 }
153 return **fIter2;
154 }
155
156 iterator& operator++() {
157 if (fIter1 != fEnd1) {
158 ++fIter1;
159 return *this;
160 }
161 ++fIter2;
162 return *this;
163 }
164
165 bool operator==(const iterator& other) const {
166 return fIter1 == other.fIter1 && fIter2 == other.fIter2;
167 }
168
169 bool operator!=(const iterator& other) const {
170 return !(*this == other);
171 }
172
173 private:
174 using inner = std::vector<std::unique_ptr<ProgramElement>>::iterator;
175
176 iterator(inner begin1, inner end1, inner begin2, inner end2)
177 : fIter1(begin1)
178 , fEnd1(end1)
179 , fIter2(begin2)
180 , fEnd2(end2) {}
181
182 inner fIter1;
183 inner fEnd1;
184 inner fIter2;
185 inner fEnd2;
186
187 friend struct Program;
188 };
189
190 class const_iterator {
191 public:
192 const ProgramElement& operator*() {
193 if (fIter1 != fEnd1) {
194 return **fIter1;
195 }
196 return **fIter2;
197 }
198
199 const_iterator& operator++() {
200 if (fIter1 != fEnd1) {
201 ++fIter1;
202 return *this;
203 }
204 ++fIter2;
205 return *this;
206 }
207
208 bool operator==(const const_iterator& other) const {
209 return fIter1 == other.fIter1 && fIter2 == other.fIter2;
210 }
211
212 bool operator!=(const const_iterator& other) const {
213 return !(*this == other);
214 }
215
216 private:
217 using inner = std::vector<std::unique_ptr<ProgramElement>>::const_iterator;
218
219 const_iterator(inner begin1, inner end1, inner begin2, inner end2)
220 : fIter1(begin1)
221 , fEnd1(end1)
222 , fIter2(begin2)
223 , fEnd2(end2) {}
224
225 inner fIter1;
226 inner fEnd1;
227 inner fIter2;
228 inner fEnd2;
229
230 friend struct Program;
231 };
232
233 enum Kind {
234 kFragment_Kind,
235 kVertex_Kind,
236 kGeometry_Kind,
237 kFragmentProcessor_Kind,
238 kPipelineStage_Kind,
239 kGeneric_Kind,
240 };
241
242 Program(Kind kind,
243 std::unique_ptr<String> source,
244 Settings settings,
245 std::shared_ptr<Context> context,
246 std::vector<std::unique_ptr<ProgramElement>>* inheritedElements,
247 std::vector<std::unique_ptr<ProgramElement>> elements,
248 std::shared_ptr<SymbolTable> symbols,
249 Inputs inputs)
250 : fKind(kind)
251 , fSource(std::move(source))
252 , fSettings(settings)
253 , fContext(context)
254 , fSymbols(symbols)
255 , fInputs(inputs)
256 , fInheritedElements(inheritedElements)
257 , fElements(std::move(elements)) {}
258
259 iterator begin() {
260 if (fInheritedElements) {
261 return iterator(fInheritedElements->begin(), fInheritedElements->end(),
262 fElements.begin(), fElements.end());
263 }
264 return iterator(fElements.begin(), fElements.end(), fElements.end(), fElements.end());
265 }
266
267 iterator end() {
268 if (fInheritedElements) {
269 return iterator(fInheritedElements->end(), fInheritedElements->end(),
270 fElements.end(), fElements.end());
271 }
272 return iterator(fElements.end(), fElements.end(), fElements.end(), fElements.end());
273 }
274
275 const_iterator begin() const {
276 if (fInheritedElements) {
277 return const_iterator(fInheritedElements->begin(), fInheritedElements->end(),
278 fElements.begin(), fElements.end());
279 }
280 return const_iterator(fElements.begin(), fElements.end(), fElements.end(), fElements.end());
281 }
282
283 const_iterator end() const {
284 if (fInheritedElements) {
285 return const_iterator(fInheritedElements->end(), fInheritedElements->end(),
286 fElements.end(), fElements.end());
287 }
288 return const_iterator(fElements.end(), fElements.end(), fElements.end(), fElements.end());
289 }
290
291 Kind fKind;
292 std::unique_ptr<String> fSource;
293 Settings fSettings;
294 std::shared_ptr<Context> fContext;
295 // it's important to keep fElements defined after (and thus destroyed before) fSymbols,
296 // because destroying elements can modify reference counts in symbols
297 std::shared_ptr<SymbolTable> fSymbols;
298 Inputs fInputs;
299 bool fIsOptimized = false;
300
301private:
302 std::vector<std::unique_ptr<ProgramElement>>* fInheritedElements;
303 std::vector<std::unique_ptr<ProgramElement>> fElements;
304
305 friend class Compiler;
306};
307
308} // namespace SkSL
309
310#endif
311