• 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 class SkRuntimeEffectPriv {
20 public:
21     // Helper function when creating an effect for a GrSkSLFP that verifies an effect will
22     // implement the constant output for constant input optimization flag.
SupportsConstantOutputForConstantInput(sk_sp<SkRuntimeEffect> effect)23     static bool SupportsConstantOutputForConstantInput(sk_sp<SkRuntimeEffect> effect) {
24         return effect->getFilterColorProgram();
25     }
26 
ES3Options()27     static SkRuntimeEffect::Options ES3Options() {
28         SkRuntimeEffect::Options options;
29         options.enforceES2Restrictions = false;
30         return options;
31     }
32 
EnableFragCoord(SkRuntimeEffect::Options * options)33     static void EnableFragCoord(SkRuntimeEffect::Options* options) {
34         options->allowFragCoord = true;
35     }
36 };
37 
38 // These internal APIs for creating runtime effects vary from the public API in two ways:
39 //
40 //     1) they're used in contexts where it's not useful to receive an error message;
41 //     2) they're cached.
42 //
43 // Users of the public SkRuntimeEffect::Make*() can of course cache however they like themselves;
44 // keeping these APIs private means users will not be forced into our cache or cache policy.
45 
46 sk_sp<SkRuntimeEffect> SkMakeCachedRuntimeEffect(SkRuntimeEffect::Result (*make)(SkString sksl),
47                                                  SkString sksl);
48 
SkMakeCachedRuntimeEffect(SkRuntimeEffect::Result (* make)(SkString),const char * sksl)49 inline sk_sp<SkRuntimeEffect> SkMakeCachedRuntimeEffect(SkRuntimeEffect::Result (*make)(SkString),
50                                                         const char* sksl) {
51     return SkMakeCachedRuntimeEffect(make, SkString{sksl});
52 }
53 
54 // Internal API that assumes (and asserts) that the shader code is valid, but does no internal
55 // caching. Used when the caller will cache the result in a static variable.
56 inline sk_sp<SkRuntimeEffect> SkMakeRuntimeEffect(
57         SkRuntimeEffect::Result (*make)(SkString, const SkRuntimeEffect::Options&),
58         const char* sksl,
59         SkRuntimeEffect::Options options = SkRuntimeEffect::Options{}) {
60     SkRuntimeEffectPriv::EnableFragCoord(&options);
61     auto result = make(SkString{sksl}, options);
62     SkASSERTF(result.effect, "%s", result.errorText.c_str());
63     return result.effect;
64 }
65 
66 // This is mostly from skvm's rgb->hsl code, with some GPU-related finesse pulled from
67 // GrHighContrastFilterEffect.fp, see next comment.
68 inline constexpr char kRGB_to_HSL_sksl[] =
69     "half3 rgb_to_hsl(half3 c) {"
70         "half mx = max(max(c.r,c.g),c.b),"
71         "     mn = min(min(c.r,c.g),c.b),"
72         "      d = mx-mn,                "
73         "   invd = 1.0 / d,              "
74         " g_lt_b = c.g < c.b ? 6.0 : 0.0;"
75 
76         // We'd prefer to write these tests like `mx == c.r`, but on some GPUs max(x,y) is
77         // not always equal to either x or y.  So we use long form, c.r >= c.g && c.r >= c.b.
78         "half h = (1/6.0) * (mx == mn                 ? 0.0 :"
79         "     /*mx==c.r*/    c.r >= c.g && c.r >= c.b ? invd * (c.g - c.b) + g_lt_b :"
80         "     /*mx==c.g*/    c.g >= c.b               ? invd * (c.b - c.r) + 2.0  "
81         "     /*mx==c.b*/                             : invd * (c.r - c.g) + 4.0);"
82 
83         "half sum = mx+mn,"
84         "       l = sum * 0.5,"
85         "       s = mx == mn ? 0.0"
86         "                    : d / (l > 0.5 ? 2.0 - sum : sum);"
87         "return half3(h,s,l);"
88     "}";
89 
90 //This is straight out of GrHSLToRGBFilterEffect.fp.
91 inline constexpr char kHSL_to_RGB_sksl[] =
92     "half3 hsl_to_rgb(half3 hsl) {"
93         "half  C = (1 - abs(2 * hsl.z - 1)) * hsl.y;"
94         "half3 p = hsl.xxx + half3(0, 2/3.0, 1/3.0);"
95         "half3 q = saturate(abs(fract(p) * 6 - 3) - 1);"
96         "return (q - 0.5) * C + hsl.z;"
97     "}";
98 
99 /**
100  * Runtime effects are often long lived & cached. Individual color filters or FPs created from them
101  * and are often short-lived. However, color filters and FPs may need to operate on a single color
102  * (on the CPU). This may be done at the paint level (eg, filter the paint color), or as part of
103  * FP tree analysis.
104  *
105  * SkFilterColorProgram is an skvm program representing a (color filter) SkRuntimeEffect. It can
106  * process a single color, without knowing the details of a particular instance (uniform values or
107  * children).
108  */
109 class SkFilterColorProgram {
110 public:
111     static std::unique_ptr<SkFilterColorProgram> Make(const SkRuntimeEffect* effect);
112 
113     SkPMColor4f eval(const SkPMColor4f& inColor,
114                      const void* uniformData,
115                      std::function<SkPMColor4f(int, SkPMColor4f)> evalChild) const;
116 
isAlphaUnchanged()117     bool isAlphaUnchanged() const { return fAlphaUnchanged; }
118 
119 private:
120     struct SampleCall {
121         enum class Kind {
122             kInputColor,  // eg child.eval(inputColor)
123             kImmediate,   // eg child.eval(half4(1))
124             kPrevious,    // eg child1.eval(child2.eval(...))
125             kUniform,     // eg uniform half4 color; ... child.eval(color)
126         };
127 
128         int  fChild;
129         Kind fKind;
130         union {
131             SkPMColor4f fImm;       // for kImmediate
132             int         fPrevious;  // for kPrevious
133             int         fOffset;    // for kUniform
134         };
135     };
136 
137     SkFilterColorProgram(skvm::Program program,
138                          std::vector<SampleCall> sampleCalls,
139                          bool alphaUnchanged);
140 
141     skvm::Program           fProgram;
142     std::vector<SampleCall> fSampleCalls;
143     bool                    fAlphaUnchanged;
144 };
145 
146 #endif  // SK_ENABLE_SKSL
147 
148 #endif  // SkRuntimeEffectPriv_DEFINED
149