• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 enum class DstType {
26     L32,  // Linear 32bit.  Used for both shader/blitter paths.
27     S32,  // SRGB 32bit.  Used for the blitter path only.
28     F16,  // Linear half-float.  Used for blitters only.
29     F32,  // Linear float.  Used for shaders only.
30 };
31 
32 template <ApplyPremul>
33 struct PremulTraits;
34 
35 template <>
36 struct PremulTraits<ApplyPremul::False> {
37     static Sk4f apply(const Sk4f& c) { return c; }
38 };
39 
40 template <>
41 struct PremulTraits<ApplyPremul::True> {
42     static Sk4f apply(const Sk4f& c) {
43         const float alpha = c[SkPM4f::A];
44         // FIXME: portable swizzle?
45         return c * Sk4f(alpha, alpha, alpha, 1);
46     }
47 };
48 
49 // Struct encapsulating various dest-dependent ops:
50 //
51 //   - load()       Load a SkPM4f value into Sk4f.  Normally called once per interval
52 //                  advance.  Also applies a scale and swizzle suitable for DstType.
53 //
54 //   - store()      Store one Sk4f to dest.  Optionally handles premul, color space
55 //                  conversion, etc.
56 //
57 //   - store(count) Store the Sk4f value repeatedly to dest, count times.
58 //
59 //   - store4x()    Store 4 Sk4f values to dest (opportunistic optimization).
60 //
61 template <DstType, ApplyPremul premul>
62 struct DstTraits;
63 
64 template <ApplyPremul premul>
65 struct DstTraits<DstType::L32, premul> {
66     using PM   = PremulTraits<premul>;
67     using Type = SkPMColor;
68 
69     // For L32, prescaling by 255 saves a per-pixel multiplication when premul is not needed.
70     static Sk4f load(const SkPM4f& c) {
71         return premul == ApplyPremul::False
72             ? c.to4f_pmorder() * Sk4f(255)
73             : c.to4f_pmorder();
74     }
75 
76     static void store(const Sk4f& c, Type* dst) {
77         if (premul == ApplyPremul::False) {
78             // c is prescaled by 255, just store.
79             SkNx_cast<uint8_t>(c).store(dst);
80         } else {
81             *dst = Sk4f_toL32(PM::apply(c));
82         }
83     }
84 
85     static void store(const Sk4f& c, Type* dst, int n) {
86         Type pmc;
87         store(c, &pmc);
88         sk_memset32(dst, pmc, n);
89     }
90 
91     static void store4x(const Sk4f& c0, const Sk4f& c1,
92                         const Sk4f& c2, const Sk4f& c3,
93                         Type* dst) {
94         if (premul == ApplyPremul::False) {
95             Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3);
96         } else {
97             store(c0, dst + 0);
98             store(c1, dst + 1);
99             store(c2, dst + 2);
100             store(c3, dst + 3);
101         }
102     }
103 };
104 
105 template <ApplyPremul premul>
106 struct DstTraits<DstType::S32, premul> {
107     using PM   = PremulTraits<premul>;
108     using Type = SkPMColor;
109 
110     static Sk4f load(const SkPM4f& c) {
111         return c.to4f_pmorder();
112     }
113 
114     static void store(const Sk4f& c, Type* dst) {
115         // FIXME: this assumes opaque colors.  Handle unpremultiplication.
116         *dst = Sk4f_toS32(PM::apply(c));
117     }
118 
119     static void store(const Sk4f& c, Type* dst, int n) {
120         sk_memset32(dst, Sk4f_toS32(PM::apply(c)), n);
121     }
122 
123     static void store4x(const Sk4f& c0, const Sk4f& c1,
124                         const Sk4f& c2, const Sk4f& c3,
125                         Type* dst) {
126         store(c0, dst + 0);
127         store(c1, dst + 1);
128         store(c2, dst + 2);
129         store(c3, dst + 3);
130     }
131 };
132 
133 template <ApplyPremul premul>
134 struct DstTraits<DstType::F16, premul> {
135     using PM   = PremulTraits<premul>;
136     using Type = uint64_t;
137 
138     static Sk4f load(const SkPM4f& c) {
139         return c.to4f();
140     }
141 
142     static void store(const Sk4f& c, Type* dst) {
143         SkFloatToHalf_finite_ftz(PM::apply(c)).store(dst);
144     }
145 
146     static void store(const Sk4f& c, Type* dst, int n) {
147         uint64_t color;
148         SkFloatToHalf_finite_ftz(PM::apply(c)).store(&color);
149         sk_memset64(dst, color, n);
150     }
151 
152     static void store4x(const Sk4f& c0, const Sk4f& c1,
153                         const Sk4f& c2, const Sk4f& c3,
154                         Type* dst) {
155         store(c0, dst + 0);
156         store(c1, dst + 1);
157         store(c2, dst + 2);
158         store(c3, dst + 3);
159     }
160 };
161 
162 template <ApplyPremul premul>
163 struct DstTraits<DstType::F32, premul> {
164     using PM   = PremulTraits<premul>;
165     using Type = SkPM4f;
166 
167     static Sk4f load(const SkPM4f& c) {
168         return c.to4f();
169     }
170 
171     static void store(const Sk4f& c, Type* dst) {
172         PM::apply(c).store(dst->fVec);
173     }
174 
175     static void store(const Sk4f& c, Type* dst, int n) {
176         const Sk4f pmc = PM::apply(c);
177         for (int i = 0; i < n; ++i) {
178             pmc.store(dst[i].fVec);
179         }
180     }
181 
182     static void store4x(const Sk4f& c0, const Sk4f& c1,
183                         const Sk4f& c2, const Sk4f& c3,
184                         Type* dst) {
185         store(c0, dst + 0);
186         store(c1, dst + 1);
187         store(c2, dst + 2);
188         store(c3, dst + 3);
189     }
190 };
191 
192 } // anonymous namespace
193 
194 #endif // Sk4fGradientPriv_DEFINED
195