Flutter Engine
The Flutter Engine
SkRuntimeEffect.h
Go to the documentation of this file.
1/*
2 * Copyright 2019 Google LLC
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 SkRuntimeEffect_DEFINED
9#define SkRuntimeEffect_DEFINED
10
11#include "include/core/SkBlender.h" // IWYU pragma: keep
12#include "include/core/SkColorFilter.h" // IWYU pragma: keep
13#include "include/core/SkData.h"
18#include "include/core/SkSpan.h"
28
29#include <cstddef>
30#include <cstdint>
31#include <cstring>
32#include <memory>
33#include <optional>
34#include <string>
35#include <string_view>
36#include <utility>
37#include <vector>
38
39struct SkIPoint;
40
41namespace SkSL {
42class DebugTracePriv;
43class FunctionDefinition;
44struct Program;
45enum class ProgramKind : int8_t;
46struct ProgramSettings;
47} // namespace SkSL
48
49namespace SkSL::RP {
50class Program;
51}
52
53/*
54 * SkRuntimeEffect supports creating custom SkShader and SkColorFilter objects using Skia's SkSL
55 * shading language.
56 *
57 * NOTE: This API is experimental and subject to change.
58 */
60public:
61 // Reflected description of a uniform variable in the effect's SkSL
62 struct SK_API Uniform {
63 enum class Type {
64 kFloat,
65 kFloat2,
66 kFloat3,
67 kFloat4,
71 kInt,
72 kInt2,
73 kInt3,
74 kInt4,
75 };
76
77 enum Flags {
78 // Uniform is declared as an array. 'count' contains array length.
79 kArray_Flag = 0x1,
80
81 // Uniform is declared with layout(color). Colors should be supplied as unpremultiplied,
82 // extended-range (unclamped) sRGB (ie SkColor4f). The uniform will be automatically
83 // transformed to unpremultiplied extended-range working-space colors.
84 kColor_Flag = 0x2,
85
86 // When used with SkMeshSpecification, indicates that the uniform is present in the
87 // vertex shader. Not used with SkRuntimeEffect.
88 kVertex_Flag = 0x4,
89
90 // When used with SkMeshSpecification, indicates that the uniform is present in the
91 // fragment shader. Not used with SkRuntimeEffect.
92 kFragment_Flag = 0x8,
93
94 // This flag indicates that the SkSL uniform uses a medium-precision type
95 // (i.e., `half` instead of `float`).
96 kHalfPrecision_Flag = 0x10,
97 };
98
99 std::string_view name;
100 size_t offset;
102 int count;
103 uint32_t flags;
104
105 bool isArray() const { return SkToBool(this->flags & kArray_Flag); }
106 bool isColor() const { return SkToBool(this->flags & kColor_Flag); }
107 size_t sizeInBytes() const;
108 };
109
110 // Reflected description of a uniform child (shader or colorFilter) in the effect's SkSL
111 enum class ChildType {
112 kShader,
113 kColorFilter,
114 kBlender,
115 };
116
117 struct Child {
118 std::string_view name;
120 int index;
121 };
122
123 class Options {
124 public:
125 // For testing purposes, disables optimization and inlining. (Normally, Runtime Effects
126 // don't run the inliner directly, but they still get an inlining pass once they are
127 // painted.)
128 bool forceUnoptimized = false;
129
130 private:
131 friend class SkRuntimeEffect;
133
134 // This flag allows Runtime Effects to access Skia implementation details like sk_FragCoord
135 // and functions with private identifiers (e.g. $rgb_to_hsl).
136 bool allowPrivateAccess = false;
137 // When not 0, this field allows Skia to assign a stable key to a known runtime effect
138 uint32_t fStableKey = 0;
139
140 // TODO(skia:11209) - Replace this with a promised SkCapabilities?
141 // This flag lifts the ES2 restrictions on Runtime Effects that are gated by the
142 // `strictES2Mode` check. Be aware that the software renderer and pipeline-stage effect are
143 // still largely ES3-unaware and can still fail or crash if post-ES2 features are used.
144 // This is only intended for use by tests and certain internally created effects.
145 SkSL::Version maxVersionAllowed = SkSL::Version::k100;
146 };
147
148 // If the effect is compiled successfully, `effect` will be non-null.
149 // Otherwise, `errorText` will contain the reason for failure.
150 struct Result {
153 };
154
155 // MakeForColorFilter and MakeForShader verify that the SkSL code is valid for those stages of
156 // the Skia pipeline. In all of the signatures described below, color parameters and return
157 // values are flexible. They are listed as being 'vec4', but they can also be 'half4' or
158 // 'float4'. ('vec4' is an alias for 'float4').
159
160 // We can't use a default argument for `options` due to a bug in Clang.
161 // https://bugs.llvm.org/show_bug.cgi?id=36684
162
163 // Color filter SkSL requires an entry point that looks like:
164 // vec4 main(vec4 inColor) { ... }
165 static Result MakeForColorFilter(SkString sksl, const Options&);
167 return MakeForColorFilter(std::move(sksl), Options{});
168 }
169
170 // Shader SkSL requires an entry point that looks like:
171 // vec4 main(vec2 inCoords) { ... }
172 static Result MakeForShader(SkString sksl, const Options&);
174 return MakeForShader(std::move(sksl), Options{});
175 }
176
177 // Blend SkSL requires an entry point that looks like:
178 // vec4 main(vec4 srcColor, vec4 dstColor) { ... }
179 static Result MakeForBlender(SkString sksl, const Options&);
181 return MakeForBlender(std::move(sksl), Options{});
182 }
183
184 // Object that allows passing a SkShader, SkColorFilter or SkBlender as a child
186 public:
187 ChildPtr() = default;
188 ChildPtr(sk_sp<SkShader> s) : fChild(std::move(s)) {}
189 ChildPtr(sk_sp<SkColorFilter> cf) : fChild(std::move(cf)) {}
190 ChildPtr(sk_sp<SkBlender> b) : fChild(std::move(b)) {}
191
192 // Asserts that the flattenable is either null, or one of the legal derived types
194
195 std::optional<ChildType> type() const;
196
197 SkShader* shader() const;
198 SkColorFilter* colorFilter() const;
199 SkBlender* blender() const;
200 SkFlattenable* flattenable() const { return fChild.get(); }
201
202 using sk_is_trivially_relocatable = std::true_type;
203
204 private:
206
207 static_assert(::sk_is_trivially_relocatable<decltype(fChild)>::value);
208 };
209
210 sk_sp<SkShader> makeShader(sk_sp<const SkData> uniforms,
211 sk_sp<SkShader> children[],
212 size_t childCount,
213 const SkMatrix* localMatrix = nullptr) const;
214 sk_sp<SkShader> makeShader(sk_sp<const SkData> uniforms,
215 SkSpan<const ChildPtr> children,
216 const SkMatrix* localMatrix = nullptr) const;
217
218 sk_sp<SkColorFilter> makeColorFilter(sk_sp<const SkData> uniforms) const;
219 sk_sp<SkColorFilter> makeColorFilter(sk_sp<const SkData> uniforms,
220 sk_sp<SkColorFilter> children[],
221 size_t childCount) const;
222 sk_sp<SkColorFilter> makeColorFilter(sk_sp<const SkData> uniforms,
223 SkSpan<const ChildPtr> children) const;
224
225 sk_sp<SkBlender> makeBlender(sk_sp<const SkData> uniforms,
226 SkSpan<const ChildPtr> children = {}) const;
227
228 /**
229 * Creates a new Runtime Effect patterned after an already-existing one. The new shader behaves
230 * like the original, but also creates a debug trace of its execution at the requested
231 * coordinate. After painting with this shader, the associated DebugTrace object will contain a
232 * shader execution trace. Call `writeTrace` on the debug trace object to generate a full trace
233 * suitable for a debugger, or call `dump` to emit a human-readable trace.
234 *
235 * Debug traces are only supported on a raster (non-GPU) canvas.
236
237 * Debug traces are currently only supported on shaders. Color filter and blender tracing is a
238 * work-in-progress.
239 */
243 };
244 static TracedShader MakeTraced(sk_sp<SkShader> shader, const SkIPoint& traceCoord);
245
246 // Returns the SkSL source of the runtime effect shader.
247 const std::string& source() const;
248
249 // Combined size of all 'uniform' variables. When calling makeColorFilter or makeShader,
250 // provide an SkData of this size, containing values for all of those variables.
251 size_t uniformSize() const;
252
253 SkSpan<const Uniform> uniforms() const { return SkSpan(fUniforms); }
254 SkSpan<const Child> children() const { return SkSpan(fChildren); }
255
256 // Returns pointer to the named uniform variable's description, or nullptr if not found
257 const Uniform* findUniform(std::string_view name) const;
258
259 // Returns pointer to the named child's description, or nullptr if not found
260 const Child* findChild(std::string_view name) const;
261
262 // Allows the runtime effect type to be identified.
263 bool allowShader() const { return (fFlags & kAllowShader_Flag); }
264 bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); }
265 bool allowBlender() const { return (fFlags & kAllowBlender_Flag); }
266
267 static void RegisterFlattenables();
269
270private:
271 enum Flags {
272 kUsesSampleCoords_Flag = 0x001,
273 kAllowColorFilter_Flag = 0x002,
274 kAllowShader_Flag = 0x004,
275 kAllowBlender_Flag = 0x008,
276 kSamplesOutsideMain_Flag = 0x010,
277 kUsesColorTransform_Flag = 0x020,
278 kAlwaysOpaque_Flag = 0x040,
279 kAlphaUnchanged_Flag = 0x080,
280 kDisableOptimization_Flag = 0x100,
281 };
282
283 SkRuntimeEffect(std::unique_ptr<SkSL::Program> baseProgram,
284 const Options& options,
286 std::vector<Uniform>&& uniforms,
287 std::vector<Child>&& children,
288 std::vector<SkSL::SampleUsage>&& sampleUsages,
289 uint32_t flags);
290
291 sk_sp<SkRuntimeEffect> makeUnoptimizedClone();
292
293 static Result MakeFromSource(SkString sksl, const Options& options, SkSL::ProgramKind kind);
294
295 static Result MakeInternal(std::unique_ptr<SkSL::Program> program,
296 const Options& options,
297 SkSL::ProgramKind kind);
298
299 static SkSL::ProgramSettings MakeSettings(const Options& options);
300
301 uint32_t hash() const { return fHash; }
302 bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); }
303 bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); }
304 bool usesColorTransform() const { return (fFlags & kUsesColorTransform_Flag); }
305 bool alwaysOpaque() const { return (fFlags & kAlwaysOpaque_Flag); }
306 bool isAlphaUnchanged() const { return (fFlags & kAlphaUnchanged_Flag); }
307
308 const SkSL::RP::Program* getRPProgram(SkSL::DebugTracePriv* debugTrace) const;
309
310 friend class GrSkSLFP; // usesColorTransform
311 friend class SkRuntimeShader; // fBaseProgram, fMain, fSampleUsages, getRPProgram()
312 friend class SkRuntimeBlender; //
313 friend class SkRuntimeColorFilter; //
314
316
317 uint32_t fHash;
318 uint32_t fStableKey;
319
320 std::unique_ptr<SkSL::Program> fBaseProgram;
321 std::unique_ptr<SkSL::RP::Program> fRPProgram;
322 mutable SkOnce fCompileRPProgramOnce;
323 const SkSL::FunctionDefinition& fMain;
324 std::vector<Uniform> fUniforms;
325 std::vector<Child> fChildren;
326 std::vector<SkSL::SampleUsage> fSampleUsages;
327
328 uint32_t fFlags; // Flags
329};
330
331/** Base class for SkRuntimeShaderBuilder, defined below. */
333public:
335 // Copy 'val' to this variable. No type conversion is performed - 'val' must be same
336 // size as expected by the effect. Information about the variable can be queried by
337 // looking at fVar. If the size is incorrect, no copy will be performed, and debug
338 // builds will abort. If this is the result of querying a missing variable, fVar will
339 // be nullptr, and assigning will also do nothing (and abort in debug builds).
340 template <typename T>
342 const T& val) {
343 if (!fVar) {
344 SkDEBUGFAIL("Assigning to missing variable");
345 } else if (sizeof(val) != fVar->sizeInBytes()) {
346 SkDEBUGFAIL("Incorrect value size");
347 } else {
348 memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset),
349 &val, sizeof(val));
350 }
351 return *this;
352 }
353
355 if (!fVar) {
356 SkDEBUGFAIL("Assigning to missing variable");
357 } else if (fVar->sizeInBytes() != 9 * sizeof(float)) {
358 SkDEBUGFAIL("Incorrect value size");
359 } else {
360 float* data = SkTAddOffset<float>(fOwner->writableUniformData(),
361 (ptrdiff_t)fVar->offset);
362 data[0] = val.get(0); data[1] = val.get(3); data[2] = val.get(6);
363 data[3] = val.get(1); data[4] = val.get(4); data[5] = val.get(7);
364 data[6] = val.get(2); data[7] = val.get(5); data[8] = val.get(8);
365 }
366 return *this;
367 }
368
369 template <typename T>
370 bool set(const T val[], const int count) {
371 static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable");
372 if (!fVar) {
373 SkDEBUGFAIL("Assigning to missing variable");
374 return false;
375 } else if (sizeof(T) * count != fVar->sizeInBytes()) {
376 SkDEBUGFAIL("Incorrect value size");
377 return false;
378 } else {
379 memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset),
380 val, sizeof(T) * count);
381 }
382 return true;
383 }
384
386 const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found
387 };
388
390 template <typename T> BuilderChild& operator=(sk_sp<T> val) {
391 if (!fChild) {
392 SkDEBUGFAIL("Assigning to missing child");
393 } else {
394 fOwner->fChildren[(size_t)fChild->index] = std::move(val);
395 }
396 return *this;
397 }
398
399 BuilderChild& operator=(std::nullptr_t) {
400 if (!fChild) {
401 SkDEBUGFAIL("Assigning to missing child");
402 } else {
403 fOwner->fChildren[(size_t)fChild->index] = SkRuntimeEffect::ChildPtr{};
404 }
405 return *this;
406 }
407
409 const SkRuntimeEffect::Child* fChild; // nullptr if the child was not found
410 };
411
412 const SkRuntimeEffect* effect() const { return fEffect.get(); }
413
414 BuilderUniform uniform(std::string_view name) { return { this, fEffect->findUniform(name) }; }
415 BuilderChild child(std::string_view name) { return { this, fEffect->findChild(name) }; }
416
417 // Get access to the collated uniforms and children (in the order expected by APIs like
418 // makeShader on the effect):
419 sk_sp<const SkData> uniforms() const { return fUniforms; }
421
422protected:
425 : fEffect(std::move(effect))
426 , fUniforms(SkData::MakeZeroInitialized(fEffect->uniformSize()))
427 , fChildren(fEffect->children().size()) {}
429 : fEffect(std::move(effect))
430 , fUniforms(std::move(uniforms))
431 , fChildren(fEffect->children().size()) {}
432
435
438
439private:
440 void* writableUniformData() {
441 if (!fUniforms->unique()) {
442 fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size());
443 }
444 return fUniforms->writable_data();
445 }
446
448 sk_sp<SkData> fUniforms;
449 std::vector<SkRuntimeEffect::ChildPtr> fChildren;
450};
451
452/**
453 * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects.
454 *
455 * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change!
456 *
457 * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and
458 * provides named access to the 'uniform' variables in that block, as well as named access
459 * to a list of child shader slots. Usage:
460 *
461 * sk_sp<SkRuntimeEffect> effect = ...;
462 * SkRuntimeShaderBuilder builder(effect);
463 * builder.uniform("some_uniform_float") = 3.14f;
464 * builder.uniform("some_uniform_matrix") = SkM44::Rotate(...);
465 * builder.child("some_child_effect") = mySkImage->makeShader(...);
466 * ...
467 * sk_sp<SkShader> shader = builder.makeShader(nullptr, false);
468 *
469 * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect,
470 * so can be used as-is or serve as inspiration for other interfaces or binding techniques.
471 */
473public:
475 // This is currently required by Android Framework but may go away if that dependency
476 // can be removed.
479
480 sk_sp<SkShader> makeShader(const SkMatrix* localMatrix = nullptr) const;
481
482private:
484 : SkRuntimeEffectBuilder(std::move(effect), std::move(uniforms)) {}
485
487};
488
489/**
490 * SkRuntimeColorFilterBuilder makes it easy to setup and assign uniforms to runtime color filters.
491 */
493public:
496
499
500 sk_sp<SkColorFilter> makeColorFilter() const;
501};
502
503/**
504 * SkRuntimeBlendBuilder is a utility to simplify creation and uniform setup of runtime blenders.
505 */
507public:
510
513
514 sk_sp<SkBlender> makeBlender() const;
515};
516
517#endif // SkRuntimeEffect_DEFINED
const char * options
int count
Definition: FontMgrTest.cpp:50
uint16_t fFlags
Definition: ShapeLayer.cpp:106
#define SK_API
Definition: SkAPI.h:35
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
static uint32_t hash(const SkShaderBase::GradientInfo &v)
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
static constexpr bool SkToBool(const T &x)
Definition: SkTo.h:35
GLenum type
Definition: SkData.h:25
static sk_sp< SkData > MakeWithCopy(const void *data, size_t length)
Definition: SkData.cpp:111
SkScalar get(int index) const
Definition: SkMatrix.h:392
Definition: SkOnce.h:22
SkRuntimeBlendBuilder(const SkRuntimeBlendBuilder &)=delete
SkRuntimeBlendBuilder & operator=(const SkRuntimeBlendBuilder &)=delete
SkRuntimeColorFilterBuilder(const SkRuntimeColorFilterBuilder &)=delete
SkRuntimeColorFilterBuilder & operator=(const SkRuntimeColorFilterBuilder &)=delete
SkRuntimeEffectBuilder & operator=(SkRuntimeEffectBuilder &&)=delete
BuilderUniform uniform(std::string_view name)
SkRuntimeEffectBuilder(sk_sp< SkRuntimeEffect > effect)
BuilderChild child(std::string_view name)
sk_sp< const SkData > uniforms() const
SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder &)=default
SkRuntimeEffectBuilder(sk_sp< SkRuntimeEffect > effect, sk_sp< SkData > uniforms)
const SkRuntimeEffect * effect() const
SkSpan< const SkRuntimeEffect::ChildPtr > children() const
SkRuntimeEffectBuilder & operator=(const SkRuntimeEffectBuilder &)=delete
SkRuntimeEffectBuilder()=delete
SkRuntimeEffectBuilder(SkRuntimeEffectBuilder &&)=default
ChildPtr(sk_sp< SkBlender > b)
SkFlattenable * flattenable() const
ChildPtr(sk_sp< SkShader > s)
std::true_type sk_is_trivially_relocatable
ChildPtr(sk_sp< SkColorFilter > cf)
const Child * findChild(std::string_view name) const
SkSpan< const Child > children() const
bool allowColorFilter() const
~SkRuntimeEffect() override
bool allowBlender() const
static Result MakeForShader(SkString sksl)
static Result MakeForColorFilter(SkString sksl)
SkSpan< const Uniform > uniforms() const
bool allowShader() const
static Result MakeForBlender(SkString sksl)
const Uniform * findUniform(std::string_view name) const
SkRuntimeShaderBuilder(const SkRuntimeShaderBuilder &)=default
T * get() const
Definition: SkRefCnt.h:303
SkBitmap source
Definition: examples.cpp:28
static bool b
struct MyStruct s
FlutterSemanticsFlag flags
uint8_t value
DEF_SWITCHES_START aot vmservice shared library name
Definition: switches.h:32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: main.py:1
Definition: ref_ptr.h:256
#define T
Definition: precompiler.cc:65
BuilderChild & operator=(sk_sp< T > val)
const SkRuntimeEffect::Child * fChild
BuilderChild & operator=(std::nullptr_t)
std::enable_if_t< std::is_trivially_copyable< T >::value, BuilderUniform & > operator=(const T &val)
BuilderUniform & operator=(const SkMatrix &val)
const SkRuntimeEffect::Uniform * fVar
bool set(const T val[], const int count)
std::string_view name
sk_sp< SkRuntimeEffect > effect
sk_sp< SkSL::DebugTrace > debugTrace
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63