/src/skia/include/effects/SkRuntimeEffect.h
Line | Count | Source (jump to first uncovered line) |
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 SK_API 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 | 0 | bool isArray() const { return SkToBool(this->flags & kArray_Flag); } |
106 | 0 | 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; |
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 | | // 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 { |
151 | | sk_sp<SkRuntimeEffect> effect; |
152 | | SkString errorText; |
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&); |
166 | 0 | static Result MakeForColorFilter(SkString sksl) { |
167 | 0 | return MakeForColorFilter(std::move(sksl), Options{}); |
168 | 0 | } |
169 | | |
170 | | // Shader SkSL requires an entry point that looks like: |
171 | | // vec4 main(vec2 inCoords) { ... } |
172 | | static Result MakeForShader(SkString sksl, const Options&); |
173 | 3 | static Result MakeForShader(SkString sksl) { |
174 | 3 | return MakeForShader(std::move(sksl), Options{}); |
175 | 3 | } |
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&); |
180 | 1 | static Result MakeForBlender(SkString sksl) { |
181 | 1 | return MakeForBlender(std::move(sksl), Options{}); |
182 | 1 | } |
183 | | |
184 | | // Object that allows passing a SkShader, SkColorFilter or SkBlender as a child |
185 | | class SK_API ChildPtr { |
186 | | public: |
187 | 46.4k | ChildPtr() = default; |
188 | 52.1k | ChildPtr(sk_sp<SkShader> s) : fChild(std::move(s)) {} |
189 | 14.7k | ChildPtr(sk_sp<SkColorFilter> cf) : fChild(std::move(cf)) {} |
190 | 2.83k | 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 |
193 | | ChildPtr(sk_sp<SkFlattenable> f); |
194 | | |
195 | | std::optional<ChildType> type() const; |
196 | | |
197 | | SkShader* shader() const; |
198 | | SkColorFilter* colorFilter() const; |
199 | | SkBlender* blender() const; |
200 | 0 | SkFlattenable* flattenable() const { return fChild.get(); } |
201 | | |
202 | | using sk_is_trivially_relocatable = std::true_type; |
203 | | |
204 | | private: |
205 | | sk_sp<SkFlattenable> fChild; |
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 | | */ |
240 | | struct TracedShader { |
241 | | sk_sp<SkShader> shader; |
242 | | sk_sp<SkSL::DebugTrace> debugTrace; |
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 | 285k | SkSpan<const Uniform> uniforms() const { return SkSpan(fUniforms); } |
254 | 93.9k | 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 | 43.6k | bool allowShader() const { return (fFlags & kAllowShader_Flag); } |
264 | 104k | bool allowColorFilter() const { return (fFlags & kAllowColorFilter_Flag); } |
265 | 92.1k | bool allowBlender() const { return (fFlags & kAllowBlender_Flag); } |
266 | | |
267 | | static void RegisterFlattenables(); |
268 | | ~SkRuntimeEffect() override; |
269 | | |
270 | | private: |
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, |
285 | | const SkSL::FunctionDefinition& main, |
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 | 28.6k | uint32_t hash() const { return fHash; } |
302 | 88.6k | bool usesSampleCoords() const { return (fFlags & kUsesSampleCoords_Flag); } |
303 | 0 | bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); } |
304 | 11.6k | bool usesColorTransform() const { return (fFlags & kUsesColorTransform_Flag); } |
305 | 18.5k | bool alwaysOpaque() const { return (fFlags & kAlwaysOpaque_Flag); } |
306 | 6.60k | 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 | | |
315 | | friend class SkRuntimeEffectPriv; |
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. */ |
332 | | class SkRuntimeEffectBuilder { |
333 | | public: |
334 | | struct BuilderUniform { |
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> |
341 | | std::enable_if_t<std::is_trivially_copyable<T>::value, BuilderUniform&> operator=( |
342 | 121k | const T& val) { |
343 | 121k | if (!fVar) { |
344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); |
345 | 121k | } else if (sizeof(val) != fVar->sizeInBytes()) { |
346 | 0 | SkDEBUGFAIL("Incorrect value size"); |
347 | 121k | } else { |
348 | 121k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), |
349 | 121k | &val, sizeof(val)); |
350 | 121k | } |
351 | 121k | return *this; |
352 | 121k | } _ZN22SkRuntimeEffectBuilder14BuilderUniformaSI6SkRectEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Line | Count | Source | 342 | 6.76k | const T& val) { | 343 | 6.76k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 6.76k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 6.76k | } else { | 348 | 6.76k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 6.76k | &val, sizeof(val)); | 350 | 6.76k | } | 351 | 6.76k | return *this; | 352 | 6.76k | } |
Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSINSt3__15arrayI4SkV4Lm7EEEEENS2_9enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS7_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSINSt3__15arrayI4SkV4Lm14EEEEENS2_9enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS7_ _ZN22SkRuntimeEffectBuilder14BuilderUniformaSI4SkV2EENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Line | Count | Source | 342 | 20.5k | const T& val) { | 343 | 20.5k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 20.5k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 20.5k | } else { | 348 | 20.5k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 20.5k | &val, sizeof(val)); | 350 | 20.5k | } | 351 | 20.5k | return *this; | 352 | 20.5k | } |
_ZN22SkRuntimeEffectBuilder14BuilderUniformaSI4SkV4EENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Line | Count | Source | 342 | 23.1k | const T& val) { | 343 | 23.1k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 23.1k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 23.1k | } else { | 348 | 23.1k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 23.1k | &val, sizeof(val)); | 350 | 23.1k | } | 351 | 23.1k | return *this; | 352 | 23.1k | } |
_ZN22SkRuntimeEffectBuilder14BuilderUniformaSIfEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS4_ Line | Count | Source | 342 | 35.7k | const T& val) { | 343 | 35.7k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 35.7k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 35.7k | } else { | 348 | 35.7k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 35.7k | &val, sizeof(val)); | 350 | 35.7k | } | 351 | 35.7k | return *this; | 352 | 35.7k | } |
_ZN22SkRuntimeEffectBuilder14BuilderUniformaSI4SkV3EENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Line | Count | Source | 342 | 4.03k | const T& val) { | 343 | 4.03k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 4.03k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 4.03k | } else { | 348 | 4.03k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 4.03k | &val, sizeof(val)); | 350 | 4.03k | } | 351 | 4.03k | return *this; | 352 | 4.03k | } |
_ZN22SkRuntimeEffectBuilder14BuilderUniformaSI7SkISizeEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Line | Count | Source | 342 | 2.77k | const T& val) { | 343 | 2.77k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 2.77k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 2.77k | } else { | 348 | 2.77k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 2.77k | &val, sizeof(val)); | 350 | 2.77k | } | 351 | 2.77k | return *this; | 352 | 2.77k | } |
_ZN22SkRuntimeEffectBuilder14BuilderUniformaSIN4skif7IVectorEEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS6_ Line | Count | Source | 342 | 2.77k | const T& val) { | 343 | 2.77k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 2.77k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 2.77k | } else { | 348 | 2.77k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 2.77k | &val, sizeof(val)); | 350 | 2.77k | } | 351 | 2.77k | return *this; | 352 | 2.77k | } |
_ZN22SkRuntimeEffectBuilder14BuilderUniformaSIiEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS4_ Line | Count | Source | 342 | 5.95k | const T& val) { | 343 | 5.95k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 5.95k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 5.95k | } else { | 348 | 5.95k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 5.95k | &val, sizeof(val)); | 350 | 5.95k | } | 351 | 5.95k | return *this; | 352 | 5.95k | } |
Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSI6SkRectEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSINSt3__15arrayI4SkV4Lm7EEEEENS2_9enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS7_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSINSt3__15arrayI4SkV4Lm14EEEEENS2_9enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS7_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSI4SkV2EENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSI4SkV4EENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSIfEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS4_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSI4SkV3EENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSI7SkISizeEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSIN4skif7IVectorEEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS6_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSIiEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS4_ _ZN22SkRuntimeEffectBuilder14BuilderUniformaSINSt3__15arrayIfLm9EEEEENS2_9enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS6_ Line | Count | Source | 342 | 9.89k | const T& val) { | 343 | 9.89k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 9.89k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 9.89k | } else { | 348 | 9.89k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 9.89k | &val, sizeof(val)); | 350 | 9.89k | } | 351 | 9.89k | return *this; | 352 | 9.89k | } |
_ZN22SkRuntimeEffectBuilder14BuilderUniformaSI6SkSizeEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Line | Count | Source | 342 | 9.89k | const T& val) { | 343 | 9.89k | if (!fVar) { | 344 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 345 | 9.89k | } else if (sizeof(val) != fVar->sizeInBytes()) { | 346 | 0 | SkDEBUGFAIL("Incorrect value size"); | 347 | 9.89k | } else { | 348 | 9.89k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 349 | 9.89k | &val, sizeof(val)); | 350 | 9.89k | } | 351 | 9.89k | return *this; | 352 | 9.89k | } |
Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSI7SkPointEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSIA16_fEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ Unexecuted instantiation: _ZN22SkRuntimeEffectBuilder14BuilderUniformaSIA4_fEENSt3__19enable_ifIXsr3std21is_trivially_copyableIT_EE5valueERS0_E4typeERKS5_ |
353 | | |
354 | 0 | BuilderUniform& operator=(const SkMatrix& val) { |
355 | 0 | if (!fVar) { |
356 | 0 | SkDEBUGFAIL("Assigning to missing variable"); |
357 | 0 | } else if (fVar->sizeInBytes() != 9 * sizeof(float)) { |
358 | 0 | SkDEBUGFAIL("Incorrect value size"); |
359 | 0 | } else { |
360 | 0 | float* data = SkTAddOffset<float>(fOwner->writableUniformData(), |
361 | 0 | (ptrdiff_t)fVar->offset); |
362 | 0 | data[0] = val.get(0); data[1] = val.get(3); data[2] = val.get(6); |
363 | 0 | data[3] = val.get(1); data[4] = val.get(4); data[5] = val.get(7); |
364 | 0 | data[6] = val.get(2); data[7] = val.get(5); data[8] = val.get(8); |
365 | 0 | } |
366 | 0 | return *this; |
367 | 0 | } |
368 | | |
369 | | template <typename T> |
370 | 2.74k | bool set(const T val[], const int count) { |
371 | 2.74k | static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable"); |
372 | 2.74k | if (!fVar) { |
373 | 0 | SkDEBUGFAIL("Assigning to missing variable"); |
374 | 0 | return false; |
375 | 2.74k | } else if (sizeof(T) * count != fVar->sizeInBytes()) { |
376 | 0 | SkDEBUGFAIL("Incorrect value size"); |
377 | 0 | return false; |
378 | 2.74k | } else { |
379 | 2.74k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), |
380 | 2.74k | val, sizeof(T) * count); |
381 | 2.74k | } |
382 | 2.74k | return true; |
383 | 2.74k | } bool SkRuntimeEffectBuilder::BuilderUniform::set<float>(float const*, int) Line | Count | Source | 370 | 2.74k | bool set(const T val[], const int count) { | 371 | 2.74k | static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable"); | 372 | 2.74k | if (!fVar) { | 373 | 0 | SkDEBUGFAIL("Assigning to missing variable"); | 374 | 0 | return false; | 375 | 2.74k | } else if (sizeof(T) * count != fVar->sizeInBytes()) { | 376 | 0 | SkDEBUGFAIL("Incorrect value size"); | 377 | 0 | return false; | 378 | 2.74k | } else { | 379 | 2.74k | memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), | 380 | 2.74k | val, sizeof(T) * count); | 381 | 2.74k | } | 382 | 2.74k | return true; | 383 | 2.74k | } |
Unexecuted instantiation: bool SkRuntimeEffectBuilder::BuilderUniform::set<float>(float const*, int) |
384 | | |
385 | | SkRuntimeEffectBuilder* fOwner; |
386 | | const SkRuntimeEffect::Uniform* fVar; // nullptr if the variable was not found |
387 | | }; |
388 | | |
389 | | struct BuilderChild { |
390 | 46.4k | template <typename T> BuilderChild& operator=(sk_sp<T> val) { |
391 | 46.4k | if (!fChild) { |
392 | 0 | SkDEBUGFAIL("Assigning to missing child"); |
393 | 46.4k | } else { |
394 | 46.4k | fOwner->fChildren[(size_t)fChild->index] = std::move(val); |
395 | 46.4k | } |
396 | 46.4k | return *this; |
397 | 46.4k | } Unexecuted instantiation: SkRuntimeEffectBuilder::BuilderChild& SkRuntimeEffectBuilder::BuilderChild::operator=<SkBlender>(sk_sp<SkBlender>) SkRuntimeEffectBuilder::BuilderChild& SkRuntimeEffectBuilder::BuilderChild::operator=<SkShader>(sk_sp<SkShader>) Line | Count | Source | 390 | 46.4k | template <typename T> BuilderChild& operator=(sk_sp<T> val) { | 391 | 46.4k | if (!fChild) { | 392 | 0 | SkDEBUGFAIL("Assigning to missing child"); | 393 | 46.4k | } else { | 394 | 46.4k | fOwner->fChildren[(size_t)fChild->index] = std::move(val); | 395 | 46.4k | } | 396 | 46.4k | return *this; | 397 | 46.4k | } |
Unexecuted instantiation: SkRuntimeEffectBuilder::BuilderChild& SkRuntimeEffectBuilder::BuilderChild::operator=<SkColorFilter>(sk_sp<SkColorFilter>) Unexecuted instantiation: SkRuntimeEffectBuilder::BuilderChild& SkRuntimeEffectBuilder::BuilderChild::operator=<SkBlender>(sk_sp<SkBlender>) Unexecuted instantiation: SkRuntimeEffectBuilder::BuilderChild& SkRuntimeEffectBuilder::BuilderChild::operator=<SkColorFilter>(sk_sp<SkColorFilter>) |
398 | | |
399 | 0 | BuilderChild& operator=(std::nullptr_t) { |
400 | 0 | if (!fChild) { |
401 | 0 | SkDEBUGFAIL("Assigning to missing child"); |
402 | 0 | } else { |
403 | 0 | fOwner->fChildren[(size_t)fChild->index] = SkRuntimeEffect::ChildPtr{}; |
404 | 0 | } |
405 | 0 | return *this; |
406 | 0 | } Unexecuted instantiation: SkRuntimeEffectBuilder::BuilderChild::operator=(decltype(nullptr)) Unexecuted instantiation: SkRuntimeEffectBuilder::BuilderChild::operator=(decltype(nullptr)) |
407 | | |
408 | | SkRuntimeEffectBuilder* fOwner; |
409 | | const SkRuntimeEffect::Child* fChild; // nullptr if the child was not found |
410 | | }; |
411 | | |
412 | 40.8k | const SkRuntimeEffect* effect() const { return fEffect.get(); } |
413 | | |
414 | 124k | BuilderUniform uniform(std::string_view name) { return { this, fEffect->findUniform(name) }; } |
415 | 46.4k | 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 | 40.8k | sk_sp<const SkData> uniforms() const { return fUniforms; } |
420 | 40.8k | SkSpan<const SkRuntimeEffect::ChildPtr> children() const { return fChildren; } |
421 | | |
422 | | protected: |
423 | | SkRuntimeEffectBuilder() = delete; |
424 | | explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect) |
425 | | : fEffect(std::move(effect)) |
426 | | , fUniforms(SkData::MakeZeroInitialized(fEffect->uniformSize())) |
427 | 40.8k | , fChildren(fEffect->children().size()) {} |
428 | | explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> uniforms) |
429 | | : fEffect(std::move(effect)) |
430 | | , fUniforms(std::move(uniforms)) |
431 | 0 | , fChildren(fEffect->children().size()) {} |
432 | | |
433 | | SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default; |
434 | 0 | SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = default; |
435 | | |
436 | | SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = delete; |
437 | | SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete; |
438 | | |
439 | | private: |
440 | 124k | void* writableUniformData() { |
441 | 124k | if (!fUniforms->unique()) { |
442 | 0 | fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size()); |
443 | 0 | } |
444 | 124k | return fUniforms->writable_data(); |
445 | 124k | } |
446 | | |
447 | | sk_sp<SkRuntimeEffect> fEffect; |
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 | | */ |
472 | | class SK_API SkRuntimeShaderBuilder : public SkRuntimeEffectBuilder { |
473 | | public: |
474 | | explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>); |
475 | | // This is currently required by Android Framework but may go away if that dependency |
476 | | // can be removed. |
477 | 0 | SkRuntimeShaderBuilder(const SkRuntimeShaderBuilder&) = default; |
478 | | ~SkRuntimeShaderBuilder(); |
479 | | |
480 | | sk_sp<SkShader> makeShader(const SkMatrix* localMatrix = nullptr) const; |
481 | | |
482 | | private: |
483 | | explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> uniforms) |
484 | 0 | : SkRuntimeEffectBuilder(std::move(effect), std::move(uniforms)) {} |
485 | | |
486 | | friend class SkRuntimeImageFilter; |
487 | | }; |
488 | | |
489 | | /** |
490 | | * SkRuntimeColorFilterBuilder makes it easy to setup and assign uniforms to runtime color filters. |
491 | | */ |
492 | | class SK_API SkRuntimeColorFilterBuilder : public SkRuntimeEffectBuilder { |
493 | | public: |
494 | | explicit SkRuntimeColorFilterBuilder(sk_sp<SkRuntimeEffect>); |
495 | | ~SkRuntimeColorFilterBuilder(); |
496 | | |
497 | | SkRuntimeColorFilterBuilder(const SkRuntimeColorFilterBuilder&) = delete; |
498 | | SkRuntimeColorFilterBuilder& operator=(const SkRuntimeColorFilterBuilder&) = delete; |
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 | | */ |
506 | | class SK_API SkRuntimeBlendBuilder : public SkRuntimeEffectBuilder { |
507 | | public: |
508 | | explicit SkRuntimeBlendBuilder(sk_sp<SkRuntimeEffect>); |
509 | | ~SkRuntimeBlendBuilder(); |
510 | | |
511 | | SkRuntimeBlendBuilder(const SkRuntimeBlendBuilder&) = delete; |
512 | | SkRuntimeBlendBuilder& operator=(const SkRuntimeBlendBuilder&) = delete; |
513 | | |
514 | | sk_sp<SkBlender> makeBlender() const; |
515 | | }; |
516 | | |
517 | | #endif // SkRuntimeEffect_DEFINED |