Line data Source code
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 0 : static Sk4f apply(const Sk4f& c) { return c; }
38 : };
39 :
40 : template <>
41 : struct PremulTraits<ApplyPremul::True> {
42 0 : static Sk4f apply(const Sk4f& c) {
43 0 : const float alpha = c[SkPM4f::A];
44 : // FIXME: portable swizzle?
45 0 : 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 0 : static Sk4f load(const SkPM4f& c) {
71 : return premul == ApplyPremul::False
72 0 : ? c.to4f_pmorder() * Sk4f(255)
73 0 : : c.to4f_pmorder();
74 : }
75 :
76 0 : static void store(const Sk4f& c, Type* dst) {
77 : if (premul == ApplyPremul::False) {
78 : // c is prescaled by 255, just store.
79 0 : SkNx_cast<uint8_t>(c).store(dst);
80 : } else {
81 0 : *dst = Sk4f_toL32(PM::apply(c));
82 : }
83 0 : }
84 :
85 0 : static void store(const Sk4f& c, Type* dst, int n) {
86 : Type pmc;
87 0 : store(c, &pmc);
88 0 : sk_memset32(dst, pmc, n);
89 0 : }
90 :
91 0 : 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 0 : store(c0, dst + 0);
98 0 : store(c1, dst + 1);
99 0 : store(c2, dst + 2);
100 0 : store(c3, dst + 3);
101 : }
102 0 : }
103 : };
104 :
105 : template <ApplyPremul premul>
106 : struct DstTraits<DstType::S32, premul> {
107 : using PM = PremulTraits<premul>;
108 : using Type = SkPMColor;
109 :
110 0 : static Sk4f load(const SkPM4f& c) {
111 0 : return c.to4f_pmorder();
112 : }
113 :
114 0 : static void store(const Sk4f& c, Type* dst) {
115 : // FIXME: this assumes opaque colors. Handle unpremultiplication.
116 0 : *dst = Sk4f_toS32(PM::apply(c));
117 0 : }
118 :
119 0 : static void store(const Sk4f& c, Type* dst, int n) {
120 0 : sk_memset32(dst, Sk4f_toS32(PM::apply(c)), n);
121 0 : }
122 :
123 0 : static void store4x(const Sk4f& c0, const Sk4f& c1,
124 : const Sk4f& c2, const Sk4f& c3,
125 : Type* dst) {
126 0 : store(c0, dst + 0);
127 0 : store(c1, dst + 1);
128 0 : store(c2, dst + 2);
129 0 : store(c3, dst + 3);
130 0 : }
131 : };
132 :
133 : template <ApplyPremul premul>
134 : struct DstTraits<DstType::F16, premul> {
135 : using PM = PremulTraits<premul>;
136 : using Type = uint64_t;
137 :
138 0 : static Sk4f load(const SkPM4f& c) {
139 0 : return c.to4f();
140 : }
141 :
142 0 : static void store(const Sk4f& c, Type* dst) {
143 0 : SkFloatToHalf_finite_ftz(PM::apply(c)).store(dst);
144 0 : }
145 :
146 0 : static void store(const Sk4f& c, Type* dst, int n) {
147 : uint64_t color;
148 0 : SkFloatToHalf_finite_ftz(PM::apply(c)).store(&color);
149 0 : sk_memset64(dst, color, n);
150 0 : }
151 :
152 0 : static void store4x(const Sk4f& c0, const Sk4f& c1,
153 : const Sk4f& c2, const Sk4f& c3,
154 : Type* dst) {
155 0 : store(c0, dst + 0);
156 0 : store(c1, dst + 1);
157 0 : store(c2, dst + 2);
158 0 : store(c3, dst + 3);
159 0 : }
160 : };
161 :
162 : template <ApplyPremul premul>
163 : struct DstTraits<DstType::F32, premul> {
164 : using PM = PremulTraits<premul>;
165 : using Type = SkPM4f;
166 :
167 0 : static Sk4f load(const SkPM4f& c) {
168 0 : return c.to4f();
169 : }
170 :
171 0 : static void store(const Sk4f& c, Type* dst) {
172 0 : PM::apply(c).store(dst->fVec);
173 0 : }
174 :
175 0 : static void store(const Sk4f& c, Type* dst, int n) {
176 0 : const Sk4f pmc = PM::apply(c);
177 0 : for (int i = 0; i < n; ++i) {
178 0 : pmc.store(dst[i].fVec);
179 : }
180 0 : }
181 :
182 0 : static void store4x(const Sk4f& c0, const Sk4f& c1,
183 : const Sk4f& c2, const Sk4f& c3,
184 : Type* dst) {
185 0 : store(c0, dst + 0);
186 0 : store(c1, dst + 1);
187 0 : store(c2, dst + 2);
188 0 : store(c3, dst + 3);
189 0 : }
190 : };
191 :
192 : } // anonymous namespace
193 :
194 : #endif // Sk4fGradientPriv_DEFINED
|