Coverage Report

Created: 2024-05-20 07:14

/src/skia/src/core/SkRuntimeEffectPriv.h
Line
Count
Source (jump to first uncovered line)
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.
70
88.6k
    static bool SupportsConstantOutputForConstantInput(const SkRuntimeEffect* effect) {
71
        // This optimization is only implemented for color filters without any children.
72
88.6k
        if (!effect->allowColorFilter() || !effect->children().empty()) {
73
58.5k
            return false;
74
58.5k
        }
75
30.0k
        return true;
76
88.6k
    }
77
78
0
    static uint32_t Hash(const SkRuntimeEffect& effect) {
79
0
        return effect.hash();
80
0
    }
81
82
0
    static uint32_t StableKey(const SkRuntimeEffect& effect) {
83
0
        return effect.fStableKey;
84
0
    }
85
86
0
    static const SkSL::Program& Program(const SkRuntimeEffect& effect) {
87
0
        return *effect.fBaseProgram;
88
0
    }
89
90
0
    static SkRuntimeEffect::Options ES3Options() {
91
0
        SkRuntimeEffect::Options options;
92
0
        options.maxVersionAllowed = SkSL::Version::k300;
93
0
        return options;
94
0
    }
95
96
9.45k
    static void AllowPrivateAccess(SkRuntimeEffect::Options* options) {
97
9.45k
        options->allowPrivateAccess = true;
98
9.45k
    }
99
100
62.2k
    static void SetStableKey(SkRuntimeEffect::Options* options, uint32_t stableKey) {
101
62.2k
        options->fStableKey = stableKey;
102
62.2k
    }
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
137
0
    static bool UsesColorTransform(const SkRuntimeEffect* effect) {
138
0
        return effect->usesColorTransform();
139
0
    }
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
154
inline sk_sp<SkRuntimeEffect> SkMakeCachedRuntimeEffect(
155
        SkRuntimeEffect::Result (*make)(SkString, const SkRuntimeEffect::Options&),
156
0
        const char* sksl) {
157
0
    return SkMakeCachedRuntimeEffect(make, SkString{sksl});
158
0
}
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
88
        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
88
    SkRuntimeEffectPriv::AllowPrivateAccess(&options);
175
88
    auto result = make(SkString{sksl}, options);
176
88
    if (!result.effect) {
177
0
        SK_ABORT("%s", result.errorText.c_str());
178
0
    }
179
88
    return result.effect.release();
180
88
}
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.
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
49.6k
            , 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