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