• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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"
12 #include "include/core/SkColorFilter.h"
13 #include "include/core/SkData.h"
14 #include "include/core/SkImageInfo.h"
15 #include "include/core/SkMatrix.h"
16 #include "include/core/SkShader.h"
17 #include "include/core/SkSpan.h"
18 #include "include/core/SkString.h"
19 #include "include/private/SkOnce.h"
20 #include "include/private/SkSLSampleUsage.h"
21 #include "include/private/SkTOptional.h"
22 
23 #include <string>
24 #include <vector>
25 
26 #ifdef SK_ENABLE_SKSL
27 
28 class GrRecordingContext;
29 class SkFilterColorProgram;
30 class SkImage;
31 
32 namespace SkSL {
33 class FunctionDefinition;
34 struct Program;
35 enum class ProgramKind : int8_t;
36 }  // namespace SkSL
37 
38 namespace skvm {
39 class Program;
40 }  // namespace skvm
41 
42 /*
43  * SkRuntimeEffect supports creating custom SkShader and SkColorFilter objects using Skia's SkSL
44  * shading language.
45  *
46  * NOTE: This API is experimental and subject to change.
47  */
48 class SK_API SkRuntimeEffect : public SkRefCnt {
49 public:
50     // Reflected description of a uniform variable in the effect's SkSL
51     struct Uniform {
52         enum class Type {
53             kFloat,
54             kFloat2,
55             kFloat3,
56             kFloat4,
57             kFloat2x2,
58             kFloat3x3,
59             kFloat4x4,
60             kInt,
61             kInt2,
62             kInt3,
63             kInt4,
64         };
65 
66         enum Flags {
67             kArray_Flag         = 0x1,
68             kSRGBUnpremul_Flag  = 0x2,
69         };
70 
71         SkString  name;
72         size_t    offset;
73         Type      type;
74         int       count;
75         uint32_t  flags;
76 
isArrayUniform77         bool isArray() const { return SkToBool(this->flags & kArray_Flag); }
78         size_t sizeInBytes() const;
79     };
80 
81     // Reflected description of a uniform child (shader or colorFilter) in the effect's SkSL
82     enum class ChildType {
83         kShader,
84         kColorFilter,
85         kBlender,
86     };
87 
88     struct Child {
89         SkString  name;
90         ChildType type;
91         int       index;
92     };
93 
94     class Options {
95     public:
96         // For testing purposes, completely disable the inliner. (Normally, Runtime Effects don't
97         // run the inliner directly, but they still get an inlining pass once they are painted.)
98         bool forceNoInline = false;
99 
100         // Advanced Filter: It indicates whether AF is enabled
101         // The value will pass to ProgramSettings::fUseAF.
102         bool useAF = false;
103 
104     private:
105         friend class SkRuntimeEffect;
106         friend class SkRuntimeEffectPriv;
107 
108         // This flag lifts the ES2 restrictions on Runtime Effects that are gated by the
109         // `strictES2Mode` check. Be aware that the software renderer and pipeline-stage effect are
110         // still largely ES3-unaware and can still fail or crash if post-ES2 features are used.
111         // This is only intended for use by tests and certain internally created effects.
112         bool enforceES2Restrictions = true;
113 
114         // Similarly: Public SkSL does not allow access to sk_FragCoord. The semantics of that
115         // variable are confusing, and expose clients to implementation details of saveLayer and
116         // image filters.
117         bool allowFragCoord = false;
118     };
119 
120     // If the effect is compiled successfully, `effect` will be non-null.
121     // Otherwise, `errorText` will contain the reason for failure.
122     struct Result {
123         sk_sp<SkRuntimeEffect> effect;
124         SkString errorText;
125     };
126 
127     // MakeForColorFilter and MakeForShader verify that the SkSL code is valid for those stages of
128     // the Skia pipeline. In all of the signatures described below, color parameters and return
129     // values are flexible. They are listed as being 'vec4', but they can also be 'half4' or
130     // 'float4'. ('vec4' is an alias for 'float4').
131 
132     // We can't use a default argument for `options` due to a bug in Clang.
133     // https://bugs.llvm.org/show_bug.cgi?id=36684
134 
135     // Color filter SkSL requires an entry point that looks like:
136     //     vec4 main(vec4 inColor) { ... }
137     static Result MakeForColorFilter(SkString sksl, const Options&);
MakeForColorFilter(SkString sksl)138     static Result MakeForColorFilter(SkString sksl) {
139         return MakeForColorFilter(std::move(sksl), Options{});
140     }
141 
142     // Shader SkSL requires an entry point that looks like:
143     //     vec4 main(vec2 inCoords) { ... }
144     //   -or-
145     //     vec4 main(vec2 inCoords, vec4 inColor) { ... }
146     //
147     // Most shaders don't use the input color, so that parameter is optional.
148     static Result MakeForShader(SkString sksl, const Options&);
MakeForShader(SkString sksl)149     static Result MakeForShader(SkString sksl) {
150         return MakeForShader(std::move(sksl), Options{});
151     }
152 
153     // Blend SkSL requires an entry point that looks like:
154     //     vec4 main(vec4 srcColor, vec4 dstColor) { ... }
155     static Result MakeForBlender(SkString sksl, const Options&);
MakeForBlender(SkString sksl)156     static Result MakeForBlender(SkString sksl) {
157         return MakeForBlender(std::move(sksl), Options{});
158     }
159 
160     // DSL entry points
161     static Result MakeForColorFilter(std::unique_ptr<SkSL::Program> program, const Options&);
162     static Result MakeForColorFilter(std::unique_ptr<SkSL::Program> program);
163 
164     static Result MakeForShader(std::unique_ptr<SkSL::Program> program, const Options&);
165     static Result MakeForShader(std::unique_ptr<SkSL::Program> program);
166 
167     static Result MakeForBlender(std::unique_ptr<SkSL::Program> program, const Options&);
168     static Result MakeForBlender(std::unique_ptr<SkSL::Program> program);
169 
170     // Object that allows passing a SkShader, SkColorFilter or SkBlender as a child
171     class ChildPtr {
172     public:
173         ChildPtr() = default;
ChildPtr(sk_sp<SkShader> s)174         ChildPtr(sk_sp<SkShader> s) : fChild(std::move(s)) {}
ChildPtr(sk_sp<SkColorFilter> cf)175         ChildPtr(sk_sp<SkColorFilter> cf) : fChild(std::move(cf)) {}
ChildPtr(sk_sp<SkBlender> b)176         ChildPtr(sk_sp<SkBlender> b) : fChild(std::move(b)) {}
177 
178         skstd::optional<ChildType> type() const;
179 
180         SkShader* shader() const;
181         SkColorFilter* colorFilter() const;
182         SkBlender* blender() const;
flattenable()183         SkFlattenable* flattenable() const { return fChild.get(); }
184 
185     private:
186         sk_sp<SkFlattenable> fChild;
187     };
188 
189     sk_sp<SkShader> makeShader(sk_sp<SkData> uniforms,
190                                sk_sp<SkShader> children[],
191                                size_t childCount,
192                                const SkMatrix* localMatrix,
193                                bool isOpaque) const;
194     sk_sp<SkShader> makeShader(sk_sp<SkData> uniforms,
195                                SkSpan<ChildPtr> children,
196                                const SkMatrix* localMatrix,
197                                bool isOpaque) const;
198 
199     sk_sp<SkImage> makeImage(GrRecordingContext*,
200                              sk_sp<SkData> uniforms,
201                              SkSpan<ChildPtr> children,
202                              const SkMatrix* localMatrix,
203                              SkImageInfo resultInfo,
204                              bool mipmapped) const;
205 
206     sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms) const;
207     sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms,
208                                          sk_sp<SkColorFilter> children[],
209                                          size_t childCount) const;
210     sk_sp<SkColorFilter> makeColorFilter(sk_sp<SkData> uniforms,
211                                          SkSpan<ChildPtr> children) const;
212 
213     sk_sp<SkBlender> makeBlender(sk_sp<SkData> uniforms, SkSpan<ChildPtr> children = {}) const;
214 
215     const std::string& source() const;
216 
217     // Combined size of all 'uniform' variables. When calling makeColorFilter or makeShader,
218     // provide an SkData of this size, containing values for all of those variables.
219     size_t uniformSize() const;
220 
uniforms()221     SkSpan<const Uniform> uniforms() const { return SkMakeSpan(fUniforms); }
children()222     SkSpan<const Child> children() const { return SkMakeSpan(fChildren); }
223 
224     // Returns pointer to the named uniform variable's description, or nullptr if not found
225     const Uniform* findUniform(const char* name) const;
226 
227     // Returns pointer to the named child's description, or nullptr if not found
228     const Child* findChild(const char* name) const;
229 
230     // Advanced Filter: get AF state
231     bool getAF() const;
232 
233     static void RegisterFlattenables();
234     ~SkRuntimeEffect() override;
235 
236 private:
237     enum Flags {
238         kUsesSampleCoords_Flag   = 0x1,
239         kAllowColorFilter_Flag   = 0x2,
240         kAllowShader_Flag        = 0x4,
241         kAllowBlender_Flag       = 0x8,
242         kSamplesOutsideMain_Flag = 0x10,
243     };
244 
245     SkRuntimeEffect(std::unique_ptr<SkSL::Program> baseProgram,
246                     const Options& options,
247                     const SkSL::FunctionDefinition& main,
248                     std::vector<Uniform>&& uniforms,
249                     std::vector<Child>&& children,
250                     std::vector<SkSL::SampleUsage>&& sampleUsages,
251                     uint32_t flags);
252 
253     static Result MakeFromSource(SkString sksl, const Options& options, SkSL::ProgramKind kind);
254 
255     static Result MakeFromDSL(std::unique_ptr<SkSL::Program> program,
256                               const Options& options,
257                               SkSL::ProgramKind kind);
258 
259     static Result MakeInternal(std::unique_ptr<SkSL::Program> program,
260                                const Options& options,
261                                SkSL::ProgramKind kind);
262 
hash()263     uint32_t hash() const { return fHash; }
usesSampleCoords()264     bool usesSampleCoords()   const { return (fFlags & kUsesSampleCoords_Flag); }
allowShader()265     bool allowShader()        const { return (fFlags & kAllowShader_Flag);      }
allowColorFilter()266     bool allowColorFilter()   const { return (fFlags & kAllowColorFilter_Flag); }
allowBlender()267     bool allowBlender()       const { return (fFlags & kAllowBlender_Flag);     }
samplesOutsideMain()268     bool samplesOutsideMain() const { return (fFlags & kSamplesOutsideMain_Flag); }
269 
270     const SkFilterColorProgram* getFilterColorProgram();
271 
272 #if SK_SUPPORT_GPU
273     friend class GrSkSLFP;             // fBaseProgram, fSampleUsages
274     friend class GrGLSLSkSLFP;         //
275 #endif
276 
277     friend class SkRTShader;            // fBaseProgram, fMain
278     friend class SkRuntimeBlender;      //
279     friend class SkRuntimeColorFilter;  //
280 
281     friend class SkFilterColorProgram;
282     friend class SkRuntimeEffectPriv;
283 
284     uint32_t fHash;
285 
286     std::unique_ptr<SkSL::Program> fBaseProgram;
287     const SkSL::FunctionDefinition& fMain;
288     std::vector<Uniform> fUniforms;
289     std::vector<Child> fChildren;
290     std::vector<SkSL::SampleUsage> fSampleUsages;
291 
292     std::unique_ptr<SkFilterColorProgram> fFilterColorProgram;
293 
294     uint32_t fFlags;  // Flags
295 };
296 
297 /** Base class for SkRuntimeShaderBuilder, defined below. */
298 class SkRuntimeEffectBuilder {
299 public:
300     struct BuilderUniform {
301         // Copy 'val' to this variable. No type conversion is performed - 'val' must be same
302         // size as expected by the effect. Information about the variable can be queried by
303         // looking at fVar. If the size is incorrect, no copy will be performed, and debug
304         // builds will abort. If this is the result of querying a missing variable, fVar will
305         // be nullptr, and assigning will also do nothing (and abort in debug builds).
306         template <typename T>
307         std::enable_if_t<std::is_trivially_copyable<T>::value, BuilderUniform&> operator=(
308                 const T& val) {
309             if (!fVar) {
310                 SkDEBUGFAIL("Assigning to missing variable");
311             } else if (sizeof(val) != fVar->sizeInBytes()) {
312                 SkDEBUGFAIL("Incorrect value size");
313             } else {
314                 memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset),
315                        &val, sizeof(val));
316             }
317             return *this;
318         }
319 
320         BuilderUniform& operator=(const SkMatrix& val) {
321             if (!fVar) {
322                 SkDEBUGFAIL("Assigning to missing variable");
323             } else if (fVar->sizeInBytes() != 9 * sizeof(float)) {
324                 SkDEBUGFAIL("Incorrect value size");
325             } else {
326                 float* data = SkTAddOffset<float>(fOwner->writableUniformData(),
327                                                   (ptrdiff_t)fVar->offset);
328                 data[0] = val.get(0); data[1] = val.get(3); data[2] = val.get(6);
329                 data[3] = val.get(1); data[4] = val.get(4); data[5] = val.get(7);
330                 data[6] = val.get(2); data[7] = val.get(5); data[8] = val.get(8);
331             }
332             return *this;
333         }
334 
335         template <typename T>
setBuilderUniform336         bool set(const T val[], const int count) {
337             static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable");
338             if (!fVar) {
339                 SkDEBUGFAIL("Assigning to missing variable");
340                 return false;
341             } else if (sizeof(T) * count != fVar->sizeInBytes()) {
342                 SkDEBUGFAIL("Incorrect value size");
343                 return false;
344             } else {
345                 memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset),
346                        val, sizeof(T) * count);
347             }
348             return true;
349         }
350 
351         SkRuntimeEffectBuilder*         fOwner;
352         const SkRuntimeEffect::Uniform* fVar;    // nullptr if the variable was not found
353     };
354 
355     struct BuilderChild {
356         template <typename T> BuilderChild& operator=(sk_sp<T> val) {
357             if (!fChild) {
358                 SkDEBUGFAIL("Assigning to missing child");
359             } else {
360                 fOwner->fChildren[(size_t)fChild->index] = std::move(val);
361             }
362             return *this;
363         }
364 
365         BuilderChild& operator=(std::nullptr_t) {
366             if (!fChild) {
367                 SkDEBUGFAIL("Assigning to missing child");
368             } else {
369                 fOwner->fChildren[(size_t)fChild->index] = SkRuntimeEffect::ChildPtr{};
370             }
371             return *this;
372         }
373 
374         SkRuntimeEffectBuilder*       fOwner;
375         const SkRuntimeEffect::Child* fChild;  // nullptr if the child was not found
376     };
377 
effect()378     const SkRuntimeEffect* effect() const { return fEffect.get(); }
379 
uniform(const char * name)380     BuilderUniform uniform(const char* name) { return { this, fEffect->findUniform(name) }; }
child(const char * name)381     BuilderChild child(const char* name) {
382         const SkRuntimeEffect::Child* child = fEffect->findChild(name);
383         return { this, child };
384     }
385 
386 protected:
387     SkRuntimeEffectBuilder() = delete;
SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect)388     explicit SkRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect)
389             : fEffect(std::move(effect))
390             , fUniforms(SkData::MakeUninitialized(fEffect->uniformSize()))
391             , fChildren(fEffect->children().size()) {}
392 
393     SkRuntimeEffectBuilder(SkRuntimeEffectBuilder&&) = default;
394     SkRuntimeEffectBuilder(const SkRuntimeEffectBuilder&) = default;
395 
396     SkRuntimeEffectBuilder& operator=(SkRuntimeEffectBuilder&&) = delete;
397     SkRuntimeEffectBuilder& operator=(const SkRuntimeEffectBuilder&) = delete;
398 
uniforms()399     sk_sp<SkData> uniforms() { return fUniforms; }
children()400     SkRuntimeEffect::ChildPtr* children() { return fChildren.data(); }
numChildren()401     size_t numChildren() { return fChildren.size(); }
402 
403 private:
writableUniformData()404     void* writableUniformData() {
405         if (!fUniforms->unique()) {
406             fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size());
407         }
408         return fUniforms->writable_data();
409     }
410 
411     sk_sp<SkRuntimeEffect>                 fEffect;
412     sk_sp<SkData>                          fUniforms;
413     std::vector<SkRuntimeEffect::ChildPtr> fChildren;
414 };
415 
416 /**
417  * SkRuntimeShaderBuilder is a utility to simplify creating SkShader objects from SkRuntimeEffects.
418  *
419  * NOTE: Like SkRuntimeEffect, this API is experimental and subject to change!
420  *
421  * Given an SkRuntimeEffect, the SkRuntimeShaderBuilder manages creating an input data block and
422  * provides named access to the 'uniform' variables in that block, as well as named access
423  * to a list of child shader slots. Usage:
424  *
425  *   sk_sp<SkRuntimeEffect> effect = ...;
426  *   SkRuntimeShaderBuilder builder(effect);
427  *   builder.uniform("some_uniform_float")  = 3.14f;
428  *   builder.uniform("some_uniform_matrix") = SkM44::Rotate(...);
429  *   builder.child("some_child_effect")     = mySkImage->makeShader(...);
430  *   ...
431  *   sk_sp<SkShader> shader = builder.makeShader(nullptr, false);
432  *
433  * Note that SkRuntimeShaderBuilder is built entirely on the public API of SkRuntimeEffect,
434  * so can be used as-is or serve as inspiration for other interfaces or binding techniques.
435  */
436 class SK_API SkRuntimeShaderBuilder : public SkRuntimeEffectBuilder {
437 public:
438     explicit SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect>);
439     // This is currently required by Android Framework but may go away if that dependency
440     // can be removed.
441     SkRuntimeShaderBuilder(const SkRuntimeShaderBuilder&) = default;
442     ~SkRuntimeShaderBuilder();
443 
444     sk_sp<SkShader> makeShader(const SkMatrix* localMatrix, bool isOpaque);
445     sk_sp<SkImage> makeImage(GrRecordingContext*,
446                              const SkMatrix* localMatrix,
447                              SkImageInfo resultInfo,
448                              bool mipmapped);
449 
450 private:
451     using INHERITED = SkRuntimeEffectBuilder;
452 };
453 
454 /**
455  * SkRuntimeBlendBuilder is a utility to simplify creation and uniform setup of runtime blenders.
456  */
457 class SK_API SkRuntimeBlendBuilder : public SkRuntimeEffectBuilder {
458 public:
459     explicit SkRuntimeBlendBuilder(sk_sp<SkRuntimeEffect>);
460     ~SkRuntimeBlendBuilder();
461 
462     SkRuntimeBlendBuilder(const SkRuntimeBlendBuilder&) = delete;
463     SkRuntimeBlendBuilder& operator=(const SkRuntimeBlendBuilder&) = delete;
464 
465     sk_sp<SkBlender> makeBlender();
466 
467 private:
468     using INHERITED = SkRuntimeEffectBuilder;
469 };
470 
471 #endif  // SK_ENABLE_SKSL
472 
473 #endif  // SkRuntimeEffect_DEFINED
474