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