1 /*
2  * Copyright 2016 Google Inc.
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 Sk4fGradientPriv_DEFINED
9 #define Sk4fGradientPriv_DEFINED
10 
11 #include "SkColor.h"
12 #include "SkHalf.h"
13 #include "SkImageInfo.h"
14 #include "SkNx.h"
15 #include "SkPM4f.h"
16 #include "SkPM4fPriv.h"
17 #include "SkUtils.h"
18 
19 // Templates shared by various 4f gradient flavors.
20 
21 namespace {
22 
23 enum class ApplyPremul { True, False };
24 
25 template <ApplyPremul>
26 struct PremulTraits;
27 
28 template <>
29 struct PremulTraits<ApplyPremul::False> {
30     static Sk4f apply(const Sk4f& c) { return c; }
31 };
32 
33 template <>
34 struct PremulTraits<ApplyPremul::True> {
35     static Sk4f apply(const Sk4f& c) {
36         const float alpha = c[SkPM4f::A];
37         // FIXME: portable swizzle?
38         return c * Sk4f(alpha, alpha, alpha, 1);
39     }
40 };
41 
42 // Struct encapsulating various dest-dependent ops:
43 //
44 //   - load()       Load a SkPM4f value into Sk4f.  Normally called once per interval
45 //                  advance.  Also applies a scale and swizzle suitable for DstType.
46 //
47 //   - store()      Store one Sk4f to dest.  Optionally handles premul, color space
48 //                  conversion, etc.
49 //
50 //   - store(count) Store the Sk4f value repeatedly to dest, count times.
51 //
52 //   - store4x()    Store 4 Sk4f values to dest (opportunistic optimization).
53 //
54 template <typename dst, ApplyPremul premul>
55 struct DstTraits;
56 
57 template <ApplyPremul premul>
58 struct DstTraits<SkPMColor, premul> {
59     using PM   = PremulTraits<premul>;
60 
61     // For L32, prescaling by 255 saves a per-pixel multiplication when premul is not needed.
62     static Sk4f load(const SkPM4f& c) {
63         return premul == ApplyPremul::False
64             ? c.to4f_pmorder() * Sk4f(255)
65             : c.to4f_pmorder();
66     }
67 
68     static void store(const Sk4f& c, SkPMColor* dst, const Sk4f& bias) {
69         if (premul == ApplyPremul::False) {
70             // c is pre-scaled by 255 and pre-biased, just store.
71             SkNx_cast<uint8_t>(c).store(dst);
72         } else {
73             *dst = Sk4f_toL32(PM::apply(c) + bias);
74         }
75     }
76 
77     static void store(const Sk4f& c, SkPMColor* dst, int n) {
78         SkPMColor pmc;
79         store(c, &pmc, Sk4f(0));
80         sk_memset32(dst, pmc, n);
81     }
82 
83     static void store4x(const Sk4f& c0, const Sk4f& c1,
84                         const Sk4f& c2, const Sk4f& c3,
85                         SkPMColor* dst,
86                         const Sk4f& bias0,
87                         const Sk4f& bias1) {
88         if (premul == ApplyPremul::False) {
89             // colors are pre-scaled and pre-biased.
90             Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3);
91         } else {
92             store(c0, dst + 0, bias0);
93             store(c1, dst + 1, bias1);
94             store(c2, dst + 2, bias0);
95             store(c3, dst + 3, bias1);
96         }
97     }
98 
99     static Sk4f pre_lerp_bias(const Sk4f& bias) {
100         // We can apply the bias before interpolation when the colors are premultiplied.
101         return premul == ApplyPremul::False ? bias : 0;
102     }
103 };
104 
105 template <ApplyPremul premul>
106 struct DstTraits<SkPM4f, premul> {
107     using PM   = PremulTraits<premul>;
108 
109     static Sk4f load(const SkPM4f& c) {
110         return c.to4f();
111     }
112 
113     static void store(const Sk4f& c, SkPM4f* dst, const Sk4f& /*bias*/) {
114         PM::apply(c).store(dst->fVec);
115     }
116 
117     static void store(const Sk4f& c, SkPM4f* dst, int n) {
118         const Sk4f pmc = PM::apply(c);
119         for (int i = 0; i < n; ++i) {
120             pmc.store(dst[i].fVec);
121         }
122     }
123 
124     static void store4x(const Sk4f& c0, const Sk4f& c1,
125                         const Sk4f& c2, const Sk4f& c3,
126                         SkPM4f* dst,
127                         const Sk4f& bias0, const Sk4f& bias1) {
128         store(c0, dst + 0, bias0);
129         store(c1, dst + 1, bias1);
130         store(c2, dst + 2, bias0);
131         store(c3, dst + 3, bias1);
132     }
133 
134     static Sk4f pre_lerp_bias(const Sk4f& /*bias*/) {
135         // For 4f dests we never bias.
136         return 0;
137     }
138 };
139 
140 } // anonymous namespace
141 
142 #endif // Sk4fGradientPriv_DEFINED
143