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" |
14 | #include "include/core/SkFlattenable.h" |
15 | #include "include/core/SkMatrix.h" |
16 | #include "include/core/SkRefCnt.h" |
17 | #include "include/core/SkShader.h" |
18 | #include "include/core/SkSpan.h" |
19 | #include "include/core/SkString.h" |
20 | #include "include/core/SkTypes.h" |
21 | #include "include/private/SkSLSampleUsage.h" |
22 | #include "include/private/base/SkOnce.h" |
23 | #include "include/private/base/SkTemplates.h" |
24 | #include "include/private/base/SkTo.h" |
25 | #include "include/private/base/SkTypeTraits.h" |
26 | #include "include/sksl/SkSLDebugTrace.h" |
27 | #include "include/sksl/SkSLVersion.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 | |
39 | struct SkIPoint; |
40 | |
41 | namespace SkSL { |
42 | class DebugTracePriv; |
43 | class FunctionDefinition; |
44 | struct Program; |
45 | enum class ProgramKind : int8_t; |
46 | struct ProgramSettings; |
47 | } // namespace SkSL |
48 | |
49 | namespace SkSL::RP { |
50 | class 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 | */ |
59 | class SK_API SkRuntimeEffect : public SkRefCnt { |
60 | public: |
61 | // Reflected description of a uniform variable in the effect's SkSL |
62 | struct Uniform { |
63 | enum class Type { |
64 | kFloat, |
65 | kFloat2, |
66 | kFloat3, |
67 | kFloat4, |
68 | kFloat2x2, |
69 | kFloat3x3, |
70 | kFloat4x4, |
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; |
101 | Type type; |
102 | int count; |
103 | uint32_t flags; |
104 | |
105 | bool isArray() const { return SkToBool(x: this->flags & kArray_Flag); } |
106 | bool isColor() const { return SkToBool(x: 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; |
119 | ChildType type; |
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; |
132 | friend class SkRuntimeEffectPriv; |
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 | |
138 | // TODO(skia:11209) - Replace this with a promised SkCapabilities? |
139 | // This flag lifts the ES2 restrictions on Runtime Effects that are gated by the |
140 | // `strictES2Mode` check. Be aware that the software renderer and pipeline-stage effect are |
141 | // still largely ES3-unaware and can still fail or crash if post-ES2 features are used. |
142 | // This is only intended for use by tests and certain internally created effects. |
143 | SkSL::Version maxVersionAllowed = SkSL::Version::k100; |
144 | }; |
145 | |
146 | // If the effect is compiled successfully, `effect` will be non-null. |
147 | // Otherwise, `errorText` will contain the reason for failure. |
148 | struct Result { |
149 | sk_sp<SkRuntimeEffect> effect; |
150 | SkString errorText; |
151 | }; |
152 | |
153 | // MakeForColorFilter and MakeForShader verify that the SkSL code is valid for those stages of |
154 | // the Skia pipeline. In all of the signatures described below, color parameters and return |
155 | // values are flexible. They are listed as being 'vec4', but they can also be 'half4' or |
156 | // 'float4'. ('vec4' is an alias for 'float4'). |
157 | |
158 | // We can't use a default argument for `options` due to a bug in Clang. |
159 | // https://bugs.llvm.org/show_bug.cgi?id=36684 |
160 | |
161 | // Color filter SkSL requires an entry point that looks like: |
162 | // vec4 main(vec4 inColor) { ... } |
163 | static Result MakeForColorFilter(SkString sksl, const Options&); |
164 | static Result MakeForColorFilter(SkString sksl) { |
165 | return MakeForColorFilter(sksl: std::move(sksl), Options{}); |
166 | } |
167 | |
168 | // Shader SkSL requires an entry point that looks like: |
169 | // vec4 main(vec2 inCoords) { ... } |
170 | static Result MakeForShader(SkString sksl, const Options&); |
171 | static Result MakeForShader(SkString sksl) { |
172 | return MakeForShader(sksl: std::move(sksl), Options{}); |
173 | } |
174 | |
175 | // Blend SkSL requires an entry point that looks like: |
176 | // vec4 main(vec4 srcColor, vec4 dstColor) { ... } |
177 | static Result MakeForBlender(SkString sksl, const Options&); |
178 | static Result MakeForBlender(SkString sksl) { |
179 | return MakeForBlender(sksl: std::move(sksl), Options{}); |
180 | } |
181 | |
182 | // Object that allows passing a SkShader, SkColorFilter or SkBlender as a child |
183 | class ChildPtr { |
184 | public: |
185 | ChildPtr() = default; |
186 | ChildPtr(sk_sp<SkShader> s) : fChild(std::move(s)) {} |
187 | ChildPtr(sk_sp<SkColorFilter> cf) : fChild(std::move(cf)) {} |
188 | ChildPtr(sk_sp<SkBlender> b) : fChild(std::move(b)) {} |
189 | |
190 | // Asserts that the flattenable is either null, or one of the legal derived types |
191 | ChildPtr(sk_sp<SkFlattenable> f); |
192 | |
193 | std::optional<ChildType> type() const; |
194 | |
195 | SkShader* shader() const; |
196 | SkColorFilter* colorFilter() const; |
197 | SkBlender* blender() const; |
198 | SkFlattenable* flattenable() const { return fChild.get(); } |
199 | |
200 | using sk_is_trivially_relocatable = std::true_type; |
201 | |
202 | private: |
203 | sk_sp<SkFlattenable> fChild; |
204 | |
205 | static_assert(::sk_is_trivially_relocatable<decltype(fChild)>::value); |
206 | }; |
207 | |
208 | sk_sp<SkShader> makeShader(sk_sp<const SkData> uniforms, |
209 | sk_sp<SkShader> children[], |
210 | size_t childCount, |
211 | const SkMatrix* localMatrix = nullptr) const; |
212 | sk_sp<SkShader> makeShader(sk_sp<const SkData> uniforms, |
213 | SkSpan<const ChildPtr> children, |
214 | const SkMatrix* localMatrix = nullptr) const; |
215 | |
216 | sk_sp<SkColorFilter> makeColorFilter(sk_sp<const SkData> uniforms) const; |
217 | sk_sp<SkColorFilter> makeColorFilter(sk_sp<const SkData> uniforms, |
218 | sk_sp<SkColorFilter> children[], |
219 | size_t childCount) const; |
220 | sk_sp<SkColorFilter> makeColorFilter(sk_sp<const SkData> uniforms, |
221 | SkSpan<const ChildPtr> children) const; |
222 | |
223 | sk_sp<SkBlender> makeBlender(sk_sp<const SkData> uniforms, |
224 | SkSpan<const ChildPtr> children = {}) const; |
225 | |
226 | /** |
227 | * Creates a new Runtime Effect patterned after an already-existing one. The new shader behaves |
228 | * like the original, but also creates a debug trace of its execution at the requested |
229 | * coordinate. After painting with this shader, the associated DebugTrace object will contain a |
230 | * shader execution trace. Call `writeTrace` on the debug trace object to generate a full trace |
231 | * suitable for a debugger, or call `dump` to emit a human-readable trace. |
232 | * |
233 | * Debug traces are only supported on a raster (non-GPU) canvas. |
234 | |
235 | * Debug traces are currently only supported on shaders. Color filter and blender tracing is a |
236 | * work-in-progress. |
237 | */ |
238 | struct TracedShader { |
239 | sk_sp<SkShader> shader; |
240 | sk_sp<SkSL::DebugTrace> debugTrace; |
241 | }; |
242 | static TracedShader MakeTraced(sk_sp<SkShader> shader, const SkIPoint& traceCoord); |
243 | |
244 | // Returns the SkSL source of the runtime effect shader. |
245 | const std::string& source() const; |
246 | |
247 | // Combined size of all 'uniform' variables. When calling makeColorFilter or makeShader, |
248 | // provide an SkData of this size, containing values for all of those variables. |
249 | size_t uniformSize() const; |
250 | |
251 | SkSpan<const Uniform> uniforms() const { return SkSpan(fUniforms); } |
252 | SkSpan<const Child> children() const { return SkSpan(fChildren); } |
253 | |
254 | // Returns pointer to the named uniform variable's description, or nullptr if not found |
255 | const Uniform* findUniform(std::string_view name) const; |
256 | |
257 | // Returns pointer to the named child's description, or nullptr if not found |
258 | const Child* findChild(std::string_view name) const; |
259 | |
260 | // Allows the runtime effect type to be identified. |
261 | bool allowShader() const { return (fFlags & kAllowShader_Flag); } |
262 | bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); } |
263 | bool allowBlender() const { return (fFlags & kAllowBlender_Flag); } |
264 | |
265 | static void RegisterFlattenables(); |
266 | ~SkRuntimeEffect() override; |
267 | |
268 | private: |
269 | enum Flags { |
270 | kUsesSampleCoords_Flag = 0x001, |
271 | kAllowColorFilter_Flag = 0x002, |
272 | kAllowShader_Flag = 0x004, |
273 | kAllowBlender_Flag = 0x008, |
274 | kSamplesOutsideMain_Flag = 0x010, |
275 | kUsesColorTransform_Flag = 0x020, |
276 | kAlwaysOpaque_Flag = 0x040, |
277 | kAlphaUnchanged_Flag = 0x080, |
278 | kDisableOptimization_Flag = 0x100, |
279 | }; |
280 | |
281 | SkRuntimeEffect(std::unique_ptr<SkSL::Program> baseProgram, |
282 | const Options& options, |
283 | const SkSL::FunctionDefinition& main, |
284 | std::vector<Uniform>&& uniforms, |
285 | std::vector<Child>&& children, |
286 | std::vector<SkSL::SampleUsage>&& sampleUsages, |
287 | uint32_t flags); |
288 | |
289 | sk_sp<SkRuntimeEffect> makeUnoptimizedClone(); |
290 | |
291 | static Result MakeFromSource(SkString sksl, const Options& options, SkSL::ProgramKind kind); |
292 | |
293 | static Result MakeInternal(std::unique_ptr<SkSL::Program> program, |
294 | const Options& options, |
295 | SkSL::ProgramKind kind); |
296 | |
297 | static SkSL::ProgramSettings MakeSettings(const Options& options); |
298 | |
299 | uint32_t hash() const { return fHash; } |
300 | bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); } |
301 | bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); } |
302 | bool usesColorTransform() const { return (fFlags & kUsesColorTransform_Flag); } |
303 | bool alwaysOpaque() const { return (fFlags & kAlwaysOpaque_Flag); } |
304 | bool isAlphaUnchanged() const { return (fFlags & kAlphaUnchanged_Flag); } |
305 | |
306 | const SkSL::RP::Program* getRPProgram(SkSL::DebugTracePriv* debugTrace) const; |
307 | |
308 | #if defined(SK_GANESH) |
309 | friend class GrSkSLFP; // fBaseProgram, fSampleUsages |
310 | friend class GrGLSLSkSLFP; // |
311 | #endif |
312 | |
313 | friend class SkRuntimeShader; // fBaseProgram, fMain, fSampleUsages, getRPProgram() |
314 | friend class SkRuntimeBlender; // |
315 | friend class SkRuntimeColorFilter; // |
316 | |
317 | friend class SkRuntimeEffectPriv; |
318 | |
319 | uint32_t fHash; |
320 | |
321 | std::unique_ptr<SkSL::Program> fBaseProgram; |
322 | std::unique_ptr<SkSL::RP::Program> fRPProgram; |
323 | mutable SkOnce fCompileRPProgramOnce; |
324 | const SkSL::FunctionDefinition& fMain; |
325 | std::vector<Uniform> fUniforms; |
326 | std::vector<Child> fChildren; |
327 | std::vector<SkSL::SampleUsage> fSampleUsages; |
328 | |
329 | uint32_t fFlags; // Flags |
330 | }; |
331 | |
332 | /** Base class for SkRuntimeShaderBuilder, defined below. */ |
333 | class SkRuntimeEffectBuilder { |
334 | public: |
335 | struct BuilderUniform { |
336 | // Copy 'val' to this variable. No type conversion is performed - 'val' must be same |
337 | // size as expected by the effect. Information about the variable can be queried by |
338 | // looking at fVar. If the size is incorrect, no copy will be performed, and debug |
339 | // builds will abort. If this is the result of querying a missing variable, fVar will |
340 | // be nullptr, and assigning will also do nothing (and abort in debug builds). |
341 | template <typename T> |
342 | std::enable_if_t<std::is_trivially_copyable<T>::value, BuilderUniform&> operator=( |
343 | const T& val) { |
344 | if (!fVar) { |
345 | SkDEBUGFAIL("Assigning to missing variable"); |
346 | } else if (sizeof(val) != fVar->sizeInBytes()) { |
347 | SkDEBUGFAIL("Incorrect value size"); |
348 | } else { |
349 | memcpy(SkTAddOffset<void>(ptr: fOwner->writableUniformData(), byteOffset: fVar->offset), |
350 | &val, sizeof(val)); |
351 | } |
352 | return *this; |
353 | } |
354 | |
355 | BuilderUniform& operator=(const SkMatrix& val) { |
356 | if (!fVar) { |
357 | SkDEBUGFAIL("Assigning to missing variable"); |
358 | } else if (fVar->sizeInBytes() != 9 * sizeof(float)) { |
359 | SkDEBUGFAIL("Incorrect value size"); |
360 | } else { |
361 | float* data = SkTAddOffset<float>(ptr: fOwner->writableUniformData(), |
362 | byteOffset: (ptrdiff_t)fVar->offset); |
363 | data[0] = val.get(index: 0); data[1] = val.get(index: 3); data[2] = val.get(index: 6); |
364 | data[3] = val.get(index: 1); data[4] = val.get(index: 4); data[5] = val.get(index: 7); |
365 | data[6] = val.get(index: 2); data[7] = val.get(index: 5); data[8] = val.get(index: 8); |
366 | } |
367 | return *this; |
368 | } |
369 | |
370 | template <typename T> |
371 | bool set(const T val[], const int count) { |
372 | static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable"); |
373 | if (!fVar) { |
374 | SkDEBUGFAIL("Assigning to missing variable"); |
375 | return false; |
376 | } else if (sizeof(T) * count != fVar->sizeInBytes()) { |
377 | SkDEBUGFAIL("Incorrect value size"); |
378 | return false; |
379 | } else { |
380 | memcpy(SkTAddOffset<void>(ptr: fOwner->writableUniformData(), byteOffset: fVar->offset), |
381 | val, sizeof(T) * count); |
382 | } |
383 | return true; |
384 | } |
385 | |
386 | SkRuntimeEffectBuilder* fOwner; |
387 | const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found |
388 | }; |
389 | |
390 | struct BuilderChild { |
391 | template <typename T> BuilderChild& operator=(sk_sp<T> val) { |
392 | if (!fChild) { |
393 | SkDEBUGFAIL("Assigning to missing child"); |
394 | } else { |
395 | fOwner->fChildren[(size_t)fChild->index] = std::move(val); |
396 | } |
397 | return *this; |
398 | } |
399 | |
400 | BuilderChild& operator=(std::nullptr_t) { |
401 | if (!fChild) { |
402 | SkDEBUGFAIL("Assigning to missing child"); |
403 | } else { |
404 | fOwner->fChildren[(size_t)fChild->index] = SkRuntimeEffect::ChildPtr{}; |
405 | } |
406 | return *this; |
407 | } |
408 | |
409 | SkRuntimeEffectBuilder* fOwner; |
410 | const SkRuntimeEffect::Child* fChild; // nullptr if the child was not found |
411 | }; |
412 | |
413 | const SkRuntimeEffect* effect() const { return fEffect.get(); } |
414 | |
415 | BuilderUniform uniform(std::string_view name) { return { .fOwner: this, .fVar: fEffect->findUniform(name) }; } |
416 | BuilderChild child(std::string_view name) { return { .fOwner: this, .fChild: fEffect->findChild(name) }; } |
417 | |
418 | // Get access to the collated uniforms and children (in the order expected by APIs like |
419 | // makeShader on the effect): |
420 | sk_sp<const SkData> uniforms() const { return fUniforms; } |
421 | SkSpan<const SkRuntimeEffect::ChildPtr> children() const { return fChildren; } |
422 | |
423 | protected: |
424 | SkRuntimeEffectBuilder() = delete; |
425 | explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect) |
426 | : fEffect(std::move(effect)) |
427 | , fUniforms(SkData::MakeZeroInitialized(length: fEffect->uniformSize())) |
428 | , fChildren(fEffect->children().size()) {} |
429 | explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> uniforms) |
430 | : fEffect(std::move(effect)) |
431 | , fUniforms(std::move(uniforms)) |
432 | , fChildren(fEffect->children().size()) {} |
433 | |
434 | SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default; |
435 | SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = default; |
436 | |
437 | SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = delete; |
438 | SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete; |
439 | |
440 | private: |
441 | void* writableUniformData() { |
442 | if (!fUniforms->unique()) { |
443 | fUniforms = SkData::MakeWithCopy(data: fUniforms->data(), length: fUniforms->size()); |
444 | } |
445 | return fUniforms->writable_data(); |
446 | } |
447 | |
448 | sk_sp<SkRuntimeEffect> fEffect; |
449 | sk_sp<SkData> fUniforms; |
450 | std::vector<SkRuntimeEffect::ChildPtr> fChildren; |
451 | }; |
452 | |
453 | /** |
454 | * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects. |
455 | * |
456 | * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change! |
457 | * |
458 | * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and |
459 | * provides named access to the 'uniform' variables in that block, as well as named access |
460 | * to a list of child shader slots. Usage: |
461 | * |
462 | * sk_sp<SkRuntimeEffect> effect = ...; |
463 | * SkRuntimeShaderBuilder builder(effect); |
464 | * builder.uniform("some_uniform_float") = 3.14f; |
465 | * builder.uniform("some_uniform_matrix") = SkM44::Rotate(...); |
466 | * builder.child("some_child_effect") = mySkImage->makeShader(...); |
467 | * ... |
468 | * sk_sp<SkShader> shader = builder.makeShader(nullptr, false); |
469 | * |
470 | * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect, |
471 | * so can be used as-is or serve as inspiration for other interfaces or binding techniques. |
472 | */ |
473 | class SK_API SkRuntimeShaderBuilder : public SkRuntimeEffectBuilder { |
474 | public: |
475 | explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>); |
476 | // This is currently required by Android Framework but may go away if that dependency |
477 | // can be removed. |
478 | SkRuntimeShaderBuilder(const SkRuntimeShaderBuilder&) = default; |
479 | ~SkRuntimeShaderBuilder(); |
480 | |
481 | sk_sp<SkShader> makeShader(const SkMatrix* localMatrix = nullptr) const; |
482 | |
483 | private: |
484 | explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> uniforms) |
485 | : SkRuntimeEffectBuilder(std::move(effect), std::move(uniforms)) {} |
486 | |
487 | friend class SkRuntimeImageFilter; |
488 | }; |
489 | |
490 | /** |
491 | * SkRuntimeColorFilterBuilder makes it easy to setup and assign uniforms to runtime color filters. |
492 | */ |
493 | class SK_API SkRuntimeColorFilterBuilder : public SkRuntimeEffectBuilder { |
494 | public: |
495 | explicit SkRuntimeColorFilterBuilder(sk_sp<SkRuntimeEffect>); |
496 | ~SkRuntimeColorFilterBuilder(); |
497 | |
498 | SkRuntimeColorFilterBuilder(const SkRuntimeColorFilterBuilder&) = delete; |
499 | SkRuntimeColorFilterBuilder& operator=(const SkRuntimeColorFilterBuilder&) = delete; |
500 | |
501 | sk_sp<SkColorFilter> makeColorFilter() const; |
502 | }; |
503 | |
504 | /** |
505 | * SkRuntimeBlendBuilder is a utility to simplify creation and uniform setup of runtime blenders. |
506 | */ |
507 | class SK_API SkRuntimeBlendBuilder : public SkRuntimeEffectBuilder { |
508 | public: |
509 | explicit SkRuntimeBlendBuilder(sk_sp<SkRuntimeEffect>); |
510 | ~SkRuntimeBlendBuilder(); |
511 | |
512 | SkRuntimeBlendBuilder(const SkRuntimeBlendBuilder&) = delete; |
513 | SkRuntimeBlendBuilder& operator=(const SkRuntimeBlendBuilder&) = delete; |
514 | |
515 | sk_sp<SkBlender> makeBlender() const; |
516 | }; |
517 | |
518 | #endif // SkRuntimeEffect_DEFINED |
519 |
Definitions
- SkRuntimeEffect
- Uniform
- Type
- Flags
- isArray
- isColor
- ChildType
- Child
- Options
- Result
- MakeForColorFilter
- MakeForShader
- MakeForBlender
- ChildPtr
- ChildPtr
- ChildPtr
- ChildPtr
- ChildPtr
- flattenable
- TracedShader
- uniforms
- children
- allowShader
- allowColorFilter
- allowBlender
- Flags
- hash
- usesSampleCoords
- samplesOutsideMain
- usesColorTransform
- alwaysOpaque
- isAlphaUnchanged
- SkRuntimeEffectBuilder
- BuilderUniform
- operator=
- operator=
- set
- BuilderChild
- operator=
- operator=
- effect
- uniform
- child
- uniforms
- children
- SkRuntimeEffectBuilder
- SkRuntimeEffectBuilder
- SkRuntimeEffectBuilder
- SkRuntimeEffectBuilder
- SkRuntimeEffectBuilder
- operator=
- operator=
- writableUniformData
- SkRuntimeShaderBuilder
- SkRuntimeShaderBuilder
- SkRuntimeShaderBuilder
- SkRuntimeColorFilterBuilder
- SkRuntimeColorFilterBuilder
- operator=
- SkRuntimeBlendBuilder
- SkRuntimeBlendBuilder
Learn more about Flutter for embedded and desktop on industrialflutter.com