• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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 SkRuntimeEffectPriv_DEFINED
9 #define SkRuntimeEffectPriv_DEFINED
10 
11 #include "include/effects/SkRuntimeEffect.h"
12 #include "include/private/SkColorData.h"
13 #include "src/core/SkVM.h"
14 
15 #include <functional>
16 
17 #ifdef SK_ENABLE_SKSL
18 
19 namespace SkSL {
20 class Context;
21 class Variable;
22 struct Program;
23 }
24 
25 class SkCapabilities;
26 struct SkColorSpaceXformSteps;
27 
28 class SkRuntimeEffectPriv {
29 public:
30     struct UniformsCallbackContext {
31         const SkColorSpace* fDstColorSpace;
32     };
33 
34     // Private (experimental) API for creating runtime shaders with late-bound uniforms.
35     // The callback must produce a uniform data blob of the correct size for the effect.
36     // It is invoked at "draw" time (essentially, when a draw call is made against the canvas
37     // using the resulting shader). There are no strong guarantees about timing.
38     // Serializing the resulting shader will immediately invoke the callback (and record the
39     // resulting uniforms).
40     using UniformsCallback = std::function<sk_sp<const SkData>(const UniformsCallbackContext&)>;
41     static sk_sp<SkShader> MakeDeferredShader(const SkRuntimeEffect* effect,
42                                               UniformsCallback uniformsCallback,
43                                               SkSpan<SkRuntimeEffect::ChildPtr> children,
44                                               const SkMatrix* localMatrix = nullptr);
45 
46     // Helper function when creating an effect for a GrSkSLFP that verifies an effect will
47     // implement the constant output for constant input optimization flag.
SupportsConstantOutputForConstantInput(const SkRuntimeEffect * effect)48     static bool SupportsConstantOutputForConstantInput(const SkRuntimeEffect* effect) {
49         return effect->getFilterColorProgram();
50     }
51 
Hash(const SkRuntimeEffect & effect)52     static uint32_t Hash(const SkRuntimeEffect& effect) {
53         return effect.hash();
54     }
55 
Program(const SkRuntimeEffect & effect)56     static const SkSL::Program& Program(const SkRuntimeEffect& effect) {
57         return *effect.fBaseProgram;
58     }
59 
ES3Options()60     static SkRuntimeEffect::Options ES3Options() {
61         SkRuntimeEffect::Options options;
62         options.maxVersionAllowed = SkSL::Version::k300;
63         return options;
64     }
65 
AllowPrivateAccess(SkRuntimeEffect::Options * options)66     static void AllowPrivateAccess(SkRuntimeEffect::Options* options) {
67         options->allowPrivateAccess = true;
68     }
69 
70     static SkRuntimeEffect::Uniform VarAsUniform(const SkSL::Variable&,
71                                                  const SkSL::Context&,
72                                                  size_t* offset);
73 
74     // If there are layout(color) uniforms then this performs color space transformation on the
75     // color values and returns a new SkData. Otherwise, the original data is returned.
76     static sk_sp<const SkData> TransformUniforms(SkSpan<const SkRuntimeEffect::Uniform> uniforms,
77                                                  sk_sp<const SkData> originalData,
78                                                  const SkColorSpaceXformSteps&);
79     static sk_sp<const SkData> TransformUniforms(SkSpan<const SkRuntimeEffect::Uniform> uniforms,
80                                                  sk_sp<const SkData> originalData,
81                                                  const SkColorSpace* dstCS);
82 
83     static bool CanDraw(const SkCapabilities*, const SkSL::Program*);
84     static bool CanDraw(const SkCapabilities*, const SkRuntimeEffect*);
85 };
86 
87 // These internal APIs for creating runtime effects vary from the public API in two ways:
88 //
89 //     1) they're used in contexts where it's not useful to receive an error message;
90 //     2) they're cached.
91 //
92 // Users of the public SkRuntimeEffect::Make*() can of course cache however they like themselves;
93 // keeping these APIs private means users will not be forced into our cache or cache policy.
94 
95 sk_sp<SkRuntimeEffect> SkMakeCachedRuntimeEffect(
96         SkRuntimeEffect::Result (*make)(SkString sksl, const SkRuntimeEffect::Options&),
97         SkString sksl);
98 
SkMakeCachedRuntimeEffect(SkRuntimeEffect::Result (* make)(SkString,const SkRuntimeEffect::Options &),const char * sksl)99 inline sk_sp<SkRuntimeEffect> SkMakeCachedRuntimeEffect(
100         SkRuntimeEffect::Result (*make)(SkString, const SkRuntimeEffect::Options&),
101         const char* sksl) {
102     return SkMakeCachedRuntimeEffect(make, SkString{sksl});
103 }
104 
105 // Internal API that assumes (and asserts) that the shader code is valid, but does no internal
106 // caching. Used when the caller will cache the result in a static variable. Ownership is passed to
107 // the caller; the effect will be leaked if it the pointer is not stored or explicitly deleted.
108 inline SkRuntimeEffect* SkMakeRuntimeEffect(
109         SkRuntimeEffect::Result (*make)(SkString, const SkRuntimeEffect::Options&),
110         const char* sksl,
111         SkRuntimeEffect::Options options = SkRuntimeEffect::Options{}) {
112 #if defined(SK_DEBUG)
113     // Our SKSL snippets we embed in Skia should not have comments or excess indentation.
114     // Removing them helps trim down code size and speeds up parsing
115     if (SkStrContains(sksl, "//") || SkStrContains(sksl, "    ")) {
116         SkDEBUGFAILF("Found SkSL snippet that can be minified: \n %s\n", sksl);
117     }
118 #endif
119     SkRuntimeEffectPriv::AllowPrivateAccess(&options);
120     auto result = make(SkString{sksl}, options);
121     if (!result.effect) {
122         SK_ABORT("%s", result.errorText.c_str());
123     }
124     return result.effect.release();
125 }
126 
127 /**
128  * Runtime effects are often long lived & cached. Individual color filters or FPs created from them
129  * and are often short-lived. However, color filters and FPs may need to operate on a single color
130  * (on the CPU). This may be done at the paint level (eg, filter the paint color), or as part of
131  * FP tree analysis.
132  *
133  * SkFilterColorProgram is an skvm program representing a (color filter) SkRuntimeEffect. It can
134  * process a single color, without knowing the details of a particular instance (uniform values or
135  * children).
136  */
137 class SkFilterColorProgram {
138 public:
139     static std::unique_ptr<SkFilterColorProgram> Make(const SkRuntimeEffect* effect);
140 
141     SkPMColor4f eval(const SkPMColor4f& inColor,
142                      const void* uniformData,
143                      std::function<SkPMColor4f(int, SkPMColor4f)> evalChild) const;
144 
isAlphaUnchanged()145     bool isAlphaUnchanged() const { return fAlphaUnchanged; }
146 
147 private:
148     struct SampleCall {
149         enum class Kind {
150             kInputColor,  // eg child.eval(inputColor)
151             kImmediate,   // eg child.eval(half4(1))
152             kPrevious,    // eg child1.eval(child2.eval(...))
153             kUniform,     // eg uniform half4 color; ... child.eval(color)
154         };
155 
156         int  fChild;
157         Kind fKind;
158         union {
159             SkPMColor4f fImm;       // for kImmediate
160             int         fPrevious;  // for kPrevious
161             int         fOffset;    // for kUniform
162         };
163     };
164 
165     SkFilterColorProgram(skvm::Program program,
166                          std::vector<SampleCall> sampleCalls,
167                          bool alphaUnchanged);
168 
169     skvm::Program           fProgram;
170     std::vector<SampleCall> fSampleCalls;
171     bool                    fAlphaUnchanged;
172 };
173 
174 #endif  // SK_ENABLE_SKSL
175 
176 #endif  // SkRuntimeEffectPriv_DEFINED
177