• 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/core/SkColor.h"
12 #include "include/core/SkRefCnt.h"
13 #include "include/core/SkString.h"
14 #include "include/effects/SkRuntimeEffect.h"
15 #include "include/private/SkSLSampleUsage.h"
16 #include "include/private/base/SkAssert.h"
17 #include "include/private/base/SkDebug.h"
18 #include "include/private/base/SkSpan_impl.h"
19 #include "include/private/base/SkTArray.h"
20 #include "src/core/SkEffectPriv.h"
21 #include "src/core/SkKnownRuntimeEffects.h"
22 #include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
23 
24 #include <cstddef>
25 #include <cstdint>
26 #include <functional>
27 #include <memory>
28 
29 #include "include/sksl/SkSLVersion.h"
30 
31 class SkArenaAlloc;
32 class SkCapabilities;
33 class SkColorSpace;
34 class SkData;
35 class SkMatrix;
36 class SkReadBuffer;
37 class SkShader;
38 class SkWriteBuffer;
39 struct SkColorSpaceXformSteps;
40 
41 namespace SkShaders {
42 class MatrixRec;
43 }
44 
45 namespace SkSL {
46 class Context;
47 class Variable;
48 struct Program;
49 }
50 
51 class SkRuntimeEffectPriv {
52 public:
53     struct UniformsCallbackContext {
54         const SkColorSpace* fDstColorSpace;
55     };
56 
57     // Private (experimental) API for creating runtime shaders with late-bound uniforms.
58     // The callback must produce a uniform data blob of the correct size for the effect.
59     // It is invoked at "draw" time (essentially, when a draw call is made against the canvas
60     // using the resulting shader). There are no strong guarantees about timing.
61     // Serializing the resulting shader will immediately invoke the callback (and record the
62     // resulting uniforms).
63     using UniformsCallback = std::function<sk_sp<const SkData>(const UniformsCallbackContext&)>;
64     static sk_sp<SkShader> MakeDeferredShader(const SkRuntimeEffect* effect,
65                                               UniformsCallback uniformsCallback,
66                                               SkSpan<const SkRuntimeEffect::ChildPtr> children,
67                                               const SkMatrix* localMatrix = nullptr);
68 
69     // Helper function when creating an effect for a GrSkSLFP that verifies an effect will
70     // implement the GrFragmentProcessor "constant output for constant input" optimization flag.
SupportsConstantOutputForConstantInput(const SkRuntimeEffect * effect)71     static bool SupportsConstantOutputForConstantInput(const SkRuntimeEffect* effect) {
72         // This optimization is only implemented for color filters without any children.
73         if (!effect->allowColorFilter() || !effect->children().empty()) {
74             return false;
75         }
76         return true;
77     }
78 
Hash(const SkRuntimeEffect & effect)79     static uint32_t Hash(const SkRuntimeEffect& effect) {
80         return effect.hash();
81     }
82 
HasName(const SkRuntimeEffect & effect)83     static bool HasName(const SkRuntimeEffect& effect) {
84         return !effect.fName.isEmpty();
85     }
86 
GetName(const SkRuntimeEffect & effect)87     static const char* GetName(const SkRuntimeEffect& effect) {
88         return effect.fName.c_str();
89     }
90 
StableKey(const SkRuntimeEffect & effect)91     static uint32_t StableKey(const SkRuntimeEffect& effect) {
92         return effect.fStableKey;
93     }
94 
95     // This method is only used on user-defined known runtime effects
SetStableKey(SkRuntimeEffect * effect,uint32_t stableKey)96     static void SetStableKey(SkRuntimeEffect* effect, uint32_t stableKey) {
97         SkASSERT(!effect->fStableKey);
98         SkASSERT(SkKnownRuntimeEffects::IsViableUserDefinedKnownRuntimeEffect(stableKey));
99         effect->fStableKey = stableKey;
100     }
101 
102     // This method is only used for Skia-internal known runtime effects
SetStableKeyOnOptions(SkRuntimeEffect::Options * options,uint32_t stableKey)103     static void SetStableKeyOnOptions(SkRuntimeEffect::Options* options, uint32_t stableKey) {
104         SkASSERT(!options->fStableKey);
105         SkASSERT(SkKnownRuntimeEffects::IsSkiaKnownRuntimeEffect(stableKey));
106         options->fStableKey = stableKey;
107     }
108 
ResetStableKey(SkRuntimeEffect * effect)109     static void ResetStableKey(SkRuntimeEffect* effect) {
110         effect->fStableKey = 0;
111     }
112 
Program(const SkRuntimeEffect & effect)113     static const SkSL::Program& Program(const SkRuntimeEffect& effect) {
114         return *effect.fBaseProgram;
115     }
116 
ES3Options()117     static SkRuntimeEffect::Options ES3Options() {
118         SkRuntimeEffect::Options options;
119         options.maxVersionAllowed = SkSL::Version::k300;
120         return options;
121     }
122 
AllowPrivateAccess(SkRuntimeEffect::Options * options)123     static void AllowPrivateAccess(SkRuntimeEffect::Options* options) {
124         options->allowPrivateAccess = true;
125     }
126 
127     static SkRuntimeEffect::Uniform VarAsUniform(const SkSL::Variable&,
128                                                  const SkSL::Context&,
129                                                  size_t* offset);
130 
131     static SkRuntimeEffect::Child VarAsChild(const SkSL::Variable& var,
132                                              int index);
133 
134     static const char* ChildTypeToStr(SkRuntimeEffect::ChildType type);
135 
136     // If there are layout(color) uniforms then this performs color space transformation on the
137     // color values and returns a new SkData. Otherwise, the original data is returned.
138     static sk_sp<const SkData> TransformUniforms(SkSpan<const SkRuntimeEffect::Uniform> uniforms,
139                                                  sk_sp<const SkData> originalData,
140                                                  const SkColorSpaceXformSteps&);
141     static sk_sp<const SkData> TransformUniforms(SkSpan<const SkRuntimeEffect::Uniform> uniforms,
142                                                  sk_sp<const SkData> originalData,
143                                                  const SkColorSpace* dstCS);
144     static SkSpan<const float> UniformsAsSpan(
145         SkSpan<const SkRuntimeEffect::Uniform> uniforms,
146         sk_sp<const SkData> originalData,
147         bool alwaysCopyIntoAlloc,
148         const SkColorSpace* destColorSpace,
149         SkArenaAlloc* alloc);
150 
151     static bool CanDraw(const SkCapabilities*, const SkSL::Program*);
152     static bool CanDraw(const SkCapabilities*, const SkRuntimeEffect*);
153 
154     static bool ReadChildEffects(SkReadBuffer& buffer,
155                                  const SkRuntimeEffect* effect,
156                                  skia_private::TArray<SkRuntimeEffect::ChildPtr>* children);
157     static void WriteChildEffects(SkWriteBuffer& buffer,
158                                   SkSpan<const SkRuntimeEffect::ChildPtr> children);
159 
UsesColorTransform(const SkRuntimeEffect * effect)160     static bool UsesColorTransform(const SkRuntimeEffect* effect) {
161         return effect->usesColorTransform();
162     }
163 };
164 
165 // These internal APIs for creating runtime effects vary from the public API in two ways:
166 //
167 //     1) they're used in contexts where it's not useful to receive an error message;
168 //     2) they're cached.
169 //
170 // Users of the public SkRuntimeEffect::Make*() can of course cache however they like themselves;
171 // keeping these APIs private means users will not be forced into our cache or cache policy.
172 
173 sk_sp<SkRuntimeEffect> SkMakeCachedRuntimeEffect(
174         SkRuntimeEffect::Result (*make)(SkString sksl, const SkRuntimeEffect::Options&),
175         SkString sksl);
176 
SkMakeCachedRuntimeEffect(SkRuntimeEffect::Result (* make)(SkString,const SkRuntimeEffect::Options &),const char * sksl)177 inline sk_sp<SkRuntimeEffect> SkMakeCachedRuntimeEffect(
178         SkRuntimeEffect::Result (*make)(SkString, const SkRuntimeEffect::Options&),
179         const char* sksl) {
180     return SkMakeCachedRuntimeEffect(make, SkString{sksl});
181 }
182 
183 // Internal API that assumes (and asserts) that the shader code is valid, but does no internal
184 // caching. Used when the caller will cache the result in a static variable. Ownership is passed to
185 // the caller; the effect will be leaked if the pointer is not stored or explicitly deleted.
186 inline SkRuntimeEffect* SkMakeRuntimeEffect(
187         SkRuntimeEffect::Result (*make)(SkString, const SkRuntimeEffect::Options&),
188         const char* sksl,
189         SkRuntimeEffect::Options options = SkRuntimeEffect::Options{}) {
190 #if defined(SK_DEBUG)
191     // Our SKSL snippets we embed in Skia should not have comments or excess indentation.
192     // Removing them helps trim down code size and speeds up parsing
193     if (SkStrContains(sksl, "//") || SkStrContains(sksl, "    ")) {
194         SkDEBUGFAILF("Found SkSL snippet that can be minified: \n %s\n", sksl);
195     }
196 #endif
197     SkRuntimeEffectPriv::AllowPrivateAccess(&options);
198     auto result = make(SkString{sksl}, options);
199     if (!result.effect) {
200         SK_ABORT("%s", result.errorText.c_str());
201     }
202     return result.effect.release();
203 }
204 
205 class RuntimeEffectRPCallbacks : public SkSL::RP::Callbacks {
206 public:
207     // SkStageRec::fPaintColor is used (strictly) to tint alpha-only image shaders with the paint
208     // color. We want to suppress that behavior when they're sampled from runtime effects, so we
209     // just override the paint color here. See also: SkImageShader::appendStages.
RuntimeEffectRPCallbacks(const SkStageRec & s,const SkShaders::MatrixRec & m,SkSpan<const SkRuntimeEffect::ChildPtr> c,SkSpan<const SkSL::SampleUsage> u)210     RuntimeEffectRPCallbacks(const SkStageRec& s,
211                              const SkShaders::MatrixRec& m,
212                              SkSpan<const SkRuntimeEffect::ChildPtr> c,
213                              SkSpan<const SkSL::SampleUsage> u)
214             : fStage{s.fPipeline,
215                      s.fAlloc,
216                      s.fDstColorType,
217                      s.fDstCS,
218                      SkColors::kTransparent,
219                      s.fSurfaceProps}
220             , fMatrix(m)
221             , fChildren(c)
222             , fSampleUsages(u) {}
223 
224     bool appendShader(int index) override;
225     bool appendColorFilter(int index) override;
226     bool appendBlender(int index) override;
227 
228     // TODO: If an effect calls these intrinsics more than once, we could cache and re-use the steps
229     // object(s), rather than re-creating them in the arena repeatedly.
230     void toLinearSrgb(const void* color) override;
231 
232     void fromLinearSrgb(const void* color) override;
233 
234 private:
235     void applyColorSpaceXform(const SkColorSpaceXformSteps& tempXform, const void* color);
236 
237     const SkStageRec fStage;
238     const SkShaders::MatrixRec& fMatrix;
239     SkSpan<const SkRuntimeEffect::ChildPtr> fChildren;
240     SkSpan<const SkSL::SampleUsage> fSampleUsages;
241 };
242 
243 #endif  // SkRuntimeEffectPriv_DEFINED
244