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