Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrSkSLFP.h
Go to the documentation of this file.
1/*
2 * Copyright 2018 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 GrSkSLFP_DEFINED
9#define GrSkSLFP_DEFINED
10
13#include "include/gpu/GrTypes.h"
17#include "src/base/SkVx.h" // IWYU pragma: keep
21
22#include <cstdint>
23#include <cstring>
24#include <memory>
25#include <string>
26#include <string_view>
27#include <utility>
28#include <vector>
29
30class SkColorSpace;
31class SkData;
32class SkM44;
33namespace skgpu { class KeyBuilder; }
34struct GrShaderCaps;
35struct SkISize;
36struct SkRect;
37struct SkV2;
38struct SkV4;
39
40template <typename T> struct GrFPUniformType;
41
42#ifdef SK_DEBUG
43// UNIFORM_TYPE allows C++ types to be mapped onto SkRuntimeEffect::Uniform::Type
44template <typename T> struct GrFPUniformType {
45 template <typename U> struct add_a_UNIFORM_TYPE_specialization_for {};
46 static constexpr add_a_UNIFORM_TYPE_specialization_for<T> value = {};
47};
48#define UNIFORM_TYPE(E, ...) \
49 template <> struct GrFPUniformType<__VA_ARGS__> { \
50 static constexpr SkRuntimeEffect::Uniform::Type value = SkRuntimeEffect::Uniform::Type::E; \
51 }; \
52 template <> struct GrFPUniformType<SkSpan<__VA_ARGS__>> { \
53 static constexpr SkRuntimeEffect::Uniform::Type value = SkRuntimeEffect::Uniform::Type::E; \
54 }
55
56UNIFORM_TYPE(kFloat, float);
57UNIFORM_TYPE(kFloat2, SkV2);
58UNIFORM_TYPE(kFloat4, SkPMColor4f);
59UNIFORM_TYPE(kFloat4, SkRect);
60UNIFORM_TYPE(kFloat4, SkV4);
61UNIFORM_TYPE(kFloat4, skvx::Vec<4, float>);
62UNIFORM_TYPE(kFloat4x4, SkM44);
63UNIFORM_TYPE(kInt, int);
64UNIFORM_TYPE(kInt2, SkISize);
65
66#undef UNIFORM_TYPE
67#endif
68
70public:
71 template <typename T> struct GrSpecializedUniform {
74 };
75 template <typename T>
76 static GrSpecializedUniform<T> Specialize(const T& value) {
77 return {true, value};
78 }
79 template <typename T>
80 static GrSpecializedUniform<T> SpecializeIf(bool condition, const T& value) {
81 return {condition, value};
82 }
83
84 template <typename T> struct GrOptionalUniform {
85 bool enabled;
87 };
88 template <typename T>
89 static GrOptionalUniform<T> When(bool condition, const T& value) {
90 return {condition, value};
91 }
92
94 std::unique_ptr<GrFragmentProcessor> child;
95 };
96 static GrIgnoreOptFlags IgnoreOptFlags(std::unique_ptr<GrFragmentProcessor> child) {
97 return {std::move(child)};
98 }
99
106
107 /**
108 * Both factories support a single 'input' FP, as well as a collection of other 'child' FPs.
109 * The 'child' FPs correspond to the children declared in the effect's SkSL. The inputFP is
110 * optional, and intended for instances that have color filter semantics. This is an implicit
111 * child - if present, it's evaluated to produce the input color fed to the SkSL. Otherwise,
112 * the SkSL receives this FP's input color directly.
113 */
114
115 /**
116 * Creates a new fragment processor from an SkRuntimeEffect and a data blob containing values
117 * for all of the 'uniform' variables in the SkSL source. The layout of the uniforms blob is
118 * dictated by the SkRuntimeEffect.
119 */
120 static std::unique_ptr<GrSkSLFP> MakeWithData(
122 const char* name,
123 sk_sp<SkColorSpace> dstColorSpace,
124 std::unique_ptr<GrFragmentProcessor> inputFP,
125 std::unique_ptr<GrFragmentProcessor> destColorFP,
126 const sk_sp<const SkData>& uniforms,
127 SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs);
128
129 /*
130 * Constructs a GrSkSLFP from a series of name-value pairs, corresponding to the children and
131 * uniform data members of the effect's SkSL.
132 * The variable length args... must contain all of the children and uniforms expected.
133 * Each individual argument must be preceded by a name that matches the SkSL name of the value
134 * being set. For children, the next argument must be a std::unique_ptr<GrFragmentProcessor>.
135 * For uniforms, the next argument must be data of the correct size and type.
136 *
137 * For example, given:
138 * uniform shader child;
139 * uniform float scale;
140 * uniform half2 pt;
141 * half4 main() { ... }
142 *
143 * A call to GrSkSLFP would be formatted like:
144 * std::unique_ptr<GrFragmentProcessor> child = ...;
145 * float scaleVal = ...;
146 * SkV2 ptVal = ...;
147 * auto fp = GrSkSLFP::Make(effect, "my_effect", nullptr, GrSkSLFP::OptFlags::...,
148 * "child", std::move(child),
149 * "scale", scaleVal,
150 * "pt", ptVal);
151 *
152 * The uniforms must appear in the correct order, as must the children. Technically, the two
153 * lists can be interleaved. In debug builds, the number, names, and sizes of all arguments are
154 * checked with assertions. In release builds, all checks are elided. In either case, the
155 * uniform data is directly copied into the footer allocated after the FP.
156 */
157 template <typename... Args>
158 static std::unique_ptr<GrSkSLFP> Make(const SkRuntimeEffect* effect,
159 const char* name,
160 std::unique_ptr<GrFragmentProcessor> inputFP,
161 OptFlags optFlags,
162 Args&&... args) {
163#ifdef SK_DEBUG
164 checkArgs(effect->fUniforms.begin(),
165 effect->fUniforms.end(),
166 effect->fChildren.begin(),
167 effect->fChildren.end(),
168 std::forward<Args>(args)...);
169#endif
170 // This factory is used internally (for "runtime FPs"). We don't pass/know the destination
171 // color space, so these effects can't use the color transform intrinsics. Callers of this
172 // factory should instead construct an GrColorSpaceXformEffect as part of the FP tree.
173 SkASSERT(!effect->usesColorTransform());
174
175 size_t uniformPayloadSize = UniformPayloadSize(effect);
176 std::unique_ptr<GrSkSLFP> fp(new (uniformPayloadSize) GrSkSLFP(sk_ref_sp(effect),
177 name, optFlags));
178 fp->appendArgs(fp->uniformData(), fp->specialized(), std::forward<Args>(args)...);
179 if (inputFP) {
180 fp->setInput(std::move(inputFP));
181 }
182 return fp;
183 }
184
185 const char* name() const override { return fName; }
186 std::unique_ptr<GrFragmentProcessor> clone() const override;
187
188private:
189 class Impl;
190
191 GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, OptFlags optFlags);
192 GrSkSLFP(const GrSkSLFP& other);
193
194 static OptimizationFlags DetermineOptimizationFlags(OptFlags of, SkRuntimeEffect* effect);
195
196 void addChild(std::unique_ptr<GrFragmentProcessor> child, bool mergeOptFlags);
197 void setInput(std::unique_ptr<GrFragmentProcessor> input);
198 void setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP);
199 void addColorTransformChildren(SkColorSpace* dstColorSpace);
200
201 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
202
203 void onAddToKey(const GrShaderCaps&, skgpu::KeyBuilder*) const override;
204
205 bool onIsEqual(const GrFragmentProcessor&) const override;
206
208
209 size_t uniformCount() const { return fEffect->uniforms().size(); }
210
211 // An instance of GrSkSLFP is always allocated with a payload immediately following the FP.
212 // First the values of all the uniforms, and then a set of flags (one per uniform).
213 static size_t UniformPayloadSize(const SkRuntimeEffect* effect) {
214 return effect->uniformSize() + effect->uniforms().size() * sizeof(Specialized);
215 }
216
217 const uint8_t* uniformData() const { return reinterpret_cast<const uint8_t*>(this + 1); }
218 uint8_t* uniformData() { return reinterpret_cast< uint8_t*>(this + 1); }
219
220 using Specialized = GrGLSLProgramDataManager::Specialized;
221
222 const Specialized* specialized() const {
223 return reinterpret_cast<const Specialized*>(this->uniformData() + fUniformSize);
224 }
225 Specialized* specialized() {
226 return reinterpret_cast<Specialized*>(this->uniformData() + fUniformSize);
227 }
228
229 // Helpers to attach variadic template args to a newly constructed FP:
230
231 void appendArgs(uint8_t* uniformDataPtr, Specialized* specializedPtr) {
232 // Base case -- no more args to append, so we're done
233 }
234 template <typename... Args>
235 void appendArgs(uint8_t* uniformDataPtr,
236 Specialized* specializedPtr,
237 const char* name,
238 std::unique_ptr<GrFragmentProcessor>&& child,
239 Args&&... remainder) {
240 // Child FP case -- register the child, then continue processing the remaining arguments.
241 // Children aren't "uniforms" here, so the data & flags pointers don't advance.
242 this->addChild(std::move(child), /*mergeOptFlags=*/true);
243 this->appendArgs(uniformDataPtr, specializedPtr, std::forward<Args>(remainder)...);
244 }
245 // As above, but we don't merge in the child's optimization flags
246 template <typename... Args>
247 void appendArgs(uint8_t* uniformDataPtr,
248 Specialized* specializedPtr,
249 const char* name,
250 GrIgnoreOptFlags&& child,
251 Args&&... remainder) {
252 // Child FP case -- register the child, then continue processing the remaining arguments.
253 // Children aren't "uniforms" here, so the data & flags pointers don't advance.
254 this->addChild(std::move(child.child), /*mergeOptFlags=*/false);
255 this->appendArgs(uniformDataPtr, specializedPtr, std::forward<Args>(remainder)...);
256 }
257 template <typename T, typename... Args>
258 void appendArgs(uint8_t* uniformDataPtr,
259 Specialized* specializedPtr,
260 const char* name,
261 const GrSpecializedUniform<T>& val,
262 Args&&... remainder) {
263 // Specialized uniform case -- This just handles the specialization logic. If we want to
264 // specialize on this particular value, set the flag. Then, continue processing the actual
265 // value (by just peeling off the wrapper). This lets our generic `const T&` case (below)
266 // handle copying the data into our uniform block, and advancing the per-value uniform
267 // data and flags pointers.
268 if (val.specialize) {
269 *specializedPtr = Specialized::kYes;
270 }
271 this->appendArgs(
272 uniformDataPtr, specializedPtr, name, val.value, std::forward<Args>(remainder)...);
273 }
274 template <typename T, typename... Args>
275 void appendArgs(uint8_t* uniformDataPtr,
276 Specialized* specializedPtr,
277 const char* name,
278 const GrOptionalUniform<T>& val,
279 Args&&... remainder) {
280 // Optional uniform case. Copy the data and advance pointers, but only if the uniform is
281 // enabled. Then proceed as normal.
282 if (val.enabled) {
283 memcpy(uniformDataPtr, &val.value, sizeof(val.value));
284 uniformDataPtr += sizeof(val.value);
285 specializedPtr++;
286 }
287
288 this->appendArgs(uniformDataPtr, specializedPtr, std::forward<Args>(remainder)...);
289 }
290 template <typename T, typename... Args>
291 void appendArgs(uint8_t* uniformDataPtr,
292 Specialized* specializedPtr,
293 const char* name,
294 SkSpan<T> val,
295 Args&&... remainder) {
296 // Uniform array case -- We copy the supplied values into our uniform data area,
297 // then advance our uniform data and flags pointers.
298 memcpy(uniformDataPtr, val.data(), val.size_bytes());
299 uniformDataPtr += val.size_bytes();
300 specializedPtr++;
301 this->appendArgs(uniformDataPtr, specializedPtr, std::forward<Args>(remainder)...);
302 }
303 template <typename T, typename... Args>
304 void appendArgs(uint8_t* uniformDataPtr,
305 Specialized* specializedPtr,
306 const char* name,
307 const T& val,
308 Args&&... remainder) {
309 // Raw uniform value case -- We copy the supplied value into our uniform data area,
310 // then advance our uniform data and flags pointers.
311 memcpy(uniformDataPtr, &val, sizeof(val));
312 uniformDataPtr += sizeof(val);
313 specializedPtr++;
314 this->appendArgs(uniformDataPtr, specializedPtr, std::forward<Args>(remainder)...);
315 }
316
317#ifdef SK_DEBUG
318 using child_iterator = std::vector<SkRuntimeEffect::Child>::const_iterator;
319 using uniform_iterator = std::vector<SkRuntimeEffect::Uniform>::const_iterator;
320
321 // Validates that all args passed to the template factory have the right names, sizes, and types
322 static void checkArgs(uniform_iterator uIter,
323 uniform_iterator uEnd,
324 child_iterator cIter,
325 child_iterator cEnd) {
326 SkASSERTF(uIter == uEnd,
327 "Expected more uniforms, starting with '%.*s'",
328 (int)uIter->name.size(), uIter->name.data());
329 SkASSERTF(cIter == cEnd, "Expected more children, starting with '%.*s'",
330 (int)cIter->name.size(), cIter->name.data());
331 }
332 static void checkOneChild(child_iterator cIter, child_iterator cEnd, const char* name) {
333 SkASSERTF(cIter != cEnd, "Too many children, wasn't expecting '%s'", name);
334 SkASSERTF(cIter->name == name,
335 "Expected child '%.*s', got '%s' instead",
336 (int)cIter->name.size(), cIter->name.data(), name);
337 }
338 template <typename... Args>
339 static void checkArgs(uniform_iterator uIter,
340 uniform_iterator uEnd,
341 child_iterator cIter,
342 child_iterator cEnd,
343 const char* name,
344 std::unique_ptr<GrFragmentProcessor>&& child,
345 Args&&... remainder) {
346 // NOTE: This function (necessarily) gets an rvalue reference to child, but deliberately
347 // does not use it. We leave it intact, and our caller (Make) will pass another rvalue
348 // reference to appendArgs, which will then move it to call addChild.
349 checkOneChild(cIter, cEnd, name);
350 checkArgs(uIter, uEnd, ++cIter, cEnd, std::forward<Args>(remainder)...);
351 }
352 template <typename... Args>
353 static void checkArgs(uniform_iterator uIter,
354 uniform_iterator uEnd,
355 child_iterator cIter,
356 child_iterator cEnd,
357 const char* name,
358 GrIgnoreOptFlags&& child,
359 Args&&... remainder) {
360 // NOTE: This function (necessarily) gets an rvalue reference to child, but deliberately
361 // does not use it. We leave it intact, and our caller (Make) will pass another rvalue
362 // reference to appendArgs, which will then move it to call addChild.
363 checkOneChild(cIter, cEnd, name);
364 checkArgs(uIter, uEnd, ++cIter, cEnd, std::forward<Args>(remainder)...);
365 }
366 template <typename T, typename... Args>
367 static void checkArgs(uniform_iterator uIter,
368 uniform_iterator uEnd,
369 child_iterator cIter,
370 child_iterator cEnd,
371 const char* name,
372 const GrSpecializedUniform<T>& val,
373 Args&&... remainder) {
374 static_assert(!std::is_array<T>::value); // No specializing arrays
375 checkArgs(uIter, uEnd, cIter, cEnd, name, val.value, std::forward<Args>(remainder)...);
376 }
377 template <typename T, typename... Args>
378 static void checkArgs(uniform_iterator uIter,
379 uniform_iterator uEnd,
380 child_iterator cIter,
381 child_iterator cEnd,
382 const char* name,
383 const GrOptionalUniform<T>& val,
384 Args&&... remainder) {
385 if (val.enabled) {
386 checkArgs(uIter, uEnd, cIter, cEnd, name, val.value, std::forward<Args>(remainder)...);
387 } else {
388 checkArgs(uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...);
389 }
390 }
391 template <typename T>
392 static void checkOneUniform(uniform_iterator uIter,
393 uniform_iterator uEnd,
394 const char* name,
395 const T* /*val*/,
396 size_t valSize) {
397 SkASSERTF(uIter != uEnd, "Too many uniforms, wasn't expecting '%s'", name);
398 SkASSERTF(uIter->name == name,
399 "Expected uniform '%.*s', got '%s' instead",
400 (int)uIter->name.size(), uIter->name.data(), name);
401 SkASSERTF(uIter->sizeInBytes() == valSize,
402 "Expected uniform '%s' to be %zu bytes, got %zu instead",
403 name, uIter->sizeInBytes(), valSize);
405 "Wrong type for uniform '%s'",
406 name);
407 }
408 template <typename T, typename... Args>
409 static void checkArgs(uniform_iterator uIter,
410 uniform_iterator uEnd,
411 child_iterator cIter,
412 child_iterator cEnd,
413 const char* name,
414 SkSpan<T> val,
415 Args&&... remainder) {
416 checkOneUniform(uIter, uEnd, name, val.data(), val.size_bytes());
417 checkArgs(++uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...);
418 }
419 template <typename T, typename... Args>
420 static void checkArgs(uniform_iterator uIter,
421 uniform_iterator uEnd,
422 child_iterator cIter,
423 child_iterator cEnd,
424 const char* name,
425 const T& val,
426 Args&&... remainder) {
427 checkOneUniform(uIter, uEnd, name, &val, sizeof(val));
428 checkArgs(++uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...);
429 }
430#endif
431
433 const char* fName;
434 uint32_t fUniformSize;
435 int fInputChildIndex = -1;
436 int fDestColorChildIndex = -1;
437 int fToLinearSrgbChildIndex = -1;
438 int fFromLinearSrgbChildIndex = -1;
439
441
443
444 friend class GrSkSLFPFactory;
445};
446
448
449#endif
const char * fName
#define GR_DECLARE_FRAGMENT_PROCESSOR_TEST
#define GR_MAKE_BITFIELD_CLASS_OPS(X)
Definition GrTypes.h:42
#define SkASSERT(cond)
Definition SkAssert.h:116
#define SkASSERTF(cond, fmt,...)
Definition SkAssert.h:117
#define INHERITED(method,...)
sk_sp< T > sk_ref_sp(T *obj)
Definition SkRefCnt.h:381
void onAddToKey(const GrShaderCaps &, skgpu::KeyBuilder *) const override
Definition GrSkSLFP.cpp:416
std::unique_ptr< GrFragmentProcessor > clone() const override
Definition GrSkSLFP.cpp:448
static GrSpecializedUniform< T > SpecializeIf(bool condition, const T &value)
Definition GrSkSLFP.h:80
bool onIsEqual(const GrFragmentProcessor &) const override
Definition GrSkSLFP.cpp:437
static std::unique_ptr< GrSkSLFP > MakeWithData(sk_sp< SkRuntimeEffect > effect, const char *name, sk_sp< SkColorSpace > dstColorSpace, std::unique_ptr< GrFragmentProcessor > inputFP, std::unique_ptr< GrFragmentProcessor > destColorFP, const sk_sp< const SkData > &uniforms, SkSpan< std::unique_ptr< GrFragmentProcessor > > childFPs)
Definition GrSkSLFP.cpp:289
static GrIgnoreOptFlags IgnoreOptFlags(std::unique_ptr< GrFragmentProcessor > child)
Definition GrSkSLFP.h:96
const char * name() const override
Definition GrSkSLFP.h:185
static std::unique_ptr< GrSkSLFP > Make(const SkRuntimeEffect *effect, const char *name, std::unique_ptr< GrFragmentProcessor > inputFP, OptFlags optFlags, Args &&... args)
Definition GrSkSLFP.h:158
friend class GrSkSLFPFactory
Definition GrSkSLFP.h:444
static GrSpecializedUniform< T > Specialize(const T &value)
Definition GrSkSLFP.h:76
static GrOptionalUniform< T > When(bool condition, const T &value)
Definition GrSkSLFP.h:89
std::unique_ptr< ProgramImpl > onMakeProgramImpl() const override
Definition GrSkSLFP.cpp:412
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f &) const override
Definition GrSkSLFP.cpp:453
Definition SkM44.h:150
size_t uniformSize() const
SkSpan< const Uniform > uniforms() const
constexpr T * data() const
Definition SkSpan_impl.h:94
constexpr size_t size_bytes() const
Definition SkSpan_impl.h:97
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
#define T
std::unique_ptr< GrFragmentProcessor > child
Definition GrSkSLFP.h:94
Definition SkM44.h:19
Definition SkM44.h:98