OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef Sk4fGradientPriv_DEFINED | 8 #ifndef Sk4fGradientPriv_DEFINED |
9 #define Sk4fGradientPriv_DEFINED | 9 #define Sk4fGradientPriv_DEFINED |
10 | 10 |
11 #include "SkColor.h" | 11 #include "SkColor.h" |
12 #include "SkHalf.h" | 12 #include "SkHalf.h" |
13 #include "SkImageInfo.h" | 13 #include "SkImageInfo.h" |
14 #include "SkNx.h" | 14 #include "SkNx.h" |
15 #include "SkPM4f.h" | 15 #include "SkPM4f.h" |
16 #include "SkPM4fPriv.h" | 16 #include "SkPM4fPriv.h" |
| 17 #include "SkUtils.h" |
17 | 18 |
18 // Templates shared by various 4f gradient flavors. | 19 // Templates shared by various 4f gradient flavors. |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 enum class ApplyPremul { True, False }; | 23 enum class ApplyPremul { True, False }; |
23 | 24 |
24 inline Sk4f premul_4f(const Sk4f& c) { | 25 enum class DstType { |
25 const float alpha = c[SkPM4f::A]; | 26 L32, // Linear 32bit. Used for both shader/blitter paths. |
26 // FIXME: portable swizzle? | 27 S32, // SRGB 32bit. Used for the blitter path only. |
27 return c * Sk4f(alpha, alpha, alpha, 1); | 28 F16, // Linear half-float. Used for blitters only. |
28 } | 29 F32, // Linear float. Used for shaders only. |
| 30 }; |
29 | 31 |
30 template <ApplyPremul premul> | 32 template <ApplyPremul premul> |
31 inline SkPMColor trunc_from_4f_255(const Sk4f& c) { | 33 inline SkPMColor trunc_from_4f_255(const Sk4f& c) { |
32 SkPMColor pmc; | 34 SkPMColor pmc; |
33 SkNx_cast<uint8_t>(c).store(&pmc); | 35 SkNx_cast<uint8_t>(c).store(&pmc); |
34 if (premul == ApplyPremul::True) { | 36 if (premul == ApplyPremul::True) { |
35 pmc = SkPreMultiplyARGB(SkGetPackedA32(pmc), SkGetPackedR32(pmc), | 37 pmc = SkPreMultiplyARGB(SkGetPackedA32(pmc), SkGetPackedR32(pmc), |
36 SkGetPackedG32(pmc), SkGetPackedB32(pmc)); | 38 SkGetPackedG32(pmc), SkGetPackedB32(pmc)); |
37 } | 39 } |
38 return pmc; | 40 return pmc; |
39 } | 41 } |
40 | 42 |
41 template<typename DstType, SkColorProfileType, ApplyPremul premul> | 43 template <ApplyPremul> |
42 void store(const Sk4f& color, DstType* dst); | 44 struct PremulTraits; |
43 | 45 |
44 template<> | 46 template <> |
45 inline void store<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::False> | 47 struct PremulTraits<ApplyPremul::False> { |
46 (const Sk4f& c, SkPM4f* dst) { | 48 static Sk4f apply(const Sk4f& c) { return c; } |
47 c.store(dst); | 49 }; |
48 } | |
49 | 50 |
50 template<> | 51 template <> |
51 inline void store<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::True> | 52 struct PremulTraits<ApplyPremul::True> { |
52 (const Sk4f& c, SkPM4f* dst) { | 53 static Sk4f apply(const Sk4f& c) { |
53 premul_4f(c).store(dst); | 54 const float alpha = c[SkPM4f::A]; |
54 } | 55 // FIXME: portable swizzle? |
| 56 return c * Sk4f(alpha, alpha, alpha, 1); |
| 57 } |
| 58 }; |
55 | 59 |
56 template<> | 60 // Struct encapsulating various dest-dependent ops: |
57 inline void store<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::False> | 61 // |
58 (const Sk4f& c, SkPMColor* dst) { | 62 // - load() Load a SkPM4f value into Sk4f. Normally called once per int
erval |
59 *dst = trunc_from_4f_255<ApplyPremul::False>(c); | 63 // advance. Also applies a scale and swizzle suitable for DstT
ype. |
60 } | 64 // |
| 65 // - store() Store one Sk4f to dest. Optionally handles premul, color sp
ace |
| 66 // conversion, etc. |
| 67 // |
| 68 // - store(count) Store the Sk4f value repeatedly to dest, count times. |
| 69 // |
| 70 // - store4x() Store 4 Sk4f values to dest (opportunistic optimization). |
| 71 // |
| 72 template <DstType, ApplyPremul premul = ApplyPremul::False> |
| 73 struct DstTraits; |
61 | 74 |
62 template<> | 75 template <ApplyPremul premul> |
63 inline void store<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::True> | 76 struct DstTraits<DstType::L32, premul> { |
64 (const Sk4f& c, SkPMColor* dst) { | 77 using Type = SkPMColor; |
65 *dst = trunc_from_4f_255<ApplyPremul::True>(c); | |
66 } | |
67 | 78 |
68 template<> | 79 // For L32, we prescale the values by 255 to save a per-pixel multiplication
. |
69 inline void store<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::False> | 80 static Sk4f load(const SkPM4f& c) { |
70 (const Sk4f& c, SkPMColor* dst) { | 81 return c.to4f_pmorder() * Sk4f(255); |
71 // FIXME: this assumes opaque colors. Handle unpremultiplication. | 82 } |
72 *dst = Sk4f_toS32(c); | |
73 } | |
74 | 83 |
75 template<> | 84 static void store(const Sk4f& c, Type* dst) { |
76 inline void store<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::True> | 85 *dst = trunc_from_4f_255<premul>(c); |
77 (const Sk4f& c, SkPMColor* dst) { | 86 } |
78 *dst = Sk4f_toS32(premul_4f(c)); | |
79 } | |
80 | 87 |
81 template<> | 88 static void store(const Sk4f& c, Type* dst, int n) { |
82 inline void store<uint64_t, kLinear_SkColorProfileType, ApplyPremul::False> | 89 sk_memset32(dst, trunc_from_4f_255<premul>(c), n); |
83 (const Sk4f& c, uint64_t* dst) { | 90 } |
84 *dst = SkFloatToHalf_01(c); | |
85 } | |
86 | 91 |
87 template<> | 92 static void store4x(const Sk4f& c0, const Sk4f& c1, |
88 inline void store<uint64_t, kLinear_SkColorProfileType, ApplyPremul::True> | 93 const Sk4f& c2, const Sk4f& c3, |
89 (const Sk4f& c, uint64_t* dst) { | 94 Type* dst) { |
90 *dst = SkFloatToHalf_01(premul_4f(c)); | 95 if (premul == ApplyPremul::False) { |
91 } | 96 Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3); |
| 97 } else { |
| 98 store(c0, dst + 0); |
| 99 store(c1, dst + 1); |
| 100 store(c2, dst + 2); |
| 101 store(c3, dst + 3); |
| 102 } |
| 103 } |
| 104 }; |
92 | 105 |
93 template<typename DstType, SkColorProfileType profile, ApplyPremul premul> | 106 template <ApplyPremul premul> |
94 inline void store4x(const Sk4f& c0, | 107 struct DstTraits<DstType::S32, premul> { |
95 const Sk4f& c1, | 108 using PM = PremulTraits<premul>; |
96 const Sk4f& c2, | 109 using Type = SkPMColor; |
97 const Sk4f& c3, | |
98 DstType* dst) { | |
99 store<DstType, profile, premul>(c0, dst++); | |
100 store<DstType, profile, premul>(c1, dst++); | |
101 store<DstType, profile, premul>(c2, dst++); | |
102 store<DstType, profile, premul>(c3, dst++); | |
103 } | |
104 | 110 |
105 template<> | 111 // TODO: prescale by something like (255^2, 255^2, 255^2, 255) and use |
106 inline void store4x<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::False> | 112 // linear_to_srgb to save a mult in store? |
107 (const Sk4f& c0, const Sk4f& c1, | 113 static Sk4f load(const SkPM4f& c) { |
108 const Sk4f& c2, const Sk4f& c3, | 114 return c.to4f_pmorder(); |
109 SkPMColor* dst) { | 115 } |
110 Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3); | |
111 } | |
112 | 116 |
113 template<typename DstType, SkColorProfileType> | 117 static void store(const Sk4f& c, Type* dst) { |
114 Sk4f scale_for_dest(const Sk4f& c) { | 118 // FIXME: this assumes opaque colors. Handle unpremultiplication. |
115 return c; | 119 *dst = Sk4f_toS32(PM::apply(c)); |
116 } | 120 } |
117 | 121 |
118 template<> | 122 static void store(const Sk4f& c, Type* dst, int n) { |
119 inline Sk4f scale_for_dest<SkPMColor, kLinear_SkColorProfileType>(const Sk4f& c)
{ | 123 sk_memset32(dst, Sk4f_toS32(PM::apply(c)), n); |
120 return c * 255; | 124 } |
121 } | |
122 | 125 |
123 template<typename DstType> | 126 static void store4x(const Sk4f& c0, const Sk4f& c1, |
124 Sk4f dst_swizzle(const SkPM4f&); | 127 const Sk4f& c2, const Sk4f& c3, |
| 128 Type* dst) { |
| 129 store(c0, dst + 0); |
| 130 store(c1, dst + 1); |
| 131 store(c2, dst + 2); |
| 132 store(c3, dst + 3); |
| 133 } |
| 134 }; |
125 | 135 |
126 template<> | 136 template <ApplyPremul premul> |
127 inline Sk4f dst_swizzle<SkPM4f>(const SkPM4f& c) { | 137 struct DstTraits<DstType::F16, premul> { |
128 return c.to4f(); | 138 using PM = PremulTraits<premul>; |
129 } | 139 using Type = uint64_t; |
130 | 140 |
131 template<> | 141 static Sk4f load(const SkPM4f& c) { |
132 inline Sk4f dst_swizzle<SkPMColor>(const SkPM4f& c) { | 142 return c.to4f(); |
133 return c.to4f_pmorder(); | 143 } |
134 } | |
135 | 144 |
136 template<> | 145 static void store(const Sk4f& c, Type* dst) { |
137 inline Sk4f dst_swizzle<uint64_t>(const SkPM4f& c) { | 146 *dst = SkFloatToHalf_01(PM::apply(c)); |
138 return c.to4f(); | 147 } |
139 } | |
140 | 148 |
141 } | 149 static void store(const Sk4f& c, Type* dst, int n) { |
| 150 sk_memset64(dst, SkFloatToHalf_01(PM::apply(c)), n); |
| 151 } |
| 152 |
| 153 static void store4x(const Sk4f& c0, const Sk4f& c1, |
| 154 const Sk4f& c2, const Sk4f& c3, |
| 155 Type* dst) { |
| 156 store(c0, dst + 0); |
| 157 store(c1, dst + 1); |
| 158 store(c2, dst + 2); |
| 159 store(c3, dst + 3); |
| 160 } |
| 161 }; |
| 162 |
| 163 template <ApplyPremul premul> |
| 164 struct DstTraits<DstType::F32, premul> { |
| 165 using PM = PremulTraits<premul>; |
| 166 using Type = SkPM4f; |
| 167 |
| 168 static Sk4f load(const SkPM4f& c) { |
| 169 return c.to4f(); |
| 170 } |
| 171 |
| 172 static void store(const Sk4f& c, Type* dst) { |
| 173 PM::apply(c).store(dst->fVec); |
| 174 } |
| 175 |
| 176 static void store(const Sk4f& c, Type* dst, int n) { |
| 177 const Sk4f pmc = PM::apply(c); |
| 178 for (int i = 0; i < n; ++i) { |
| 179 pmc.store(dst[i].fVec); |
| 180 } |
| 181 } |
| 182 |
| 183 static void store4x(const Sk4f& c0, const Sk4f& c1, |
| 184 const Sk4f& c2, const Sk4f& c3, |
| 185 Type* dst) { |
| 186 store(c0, dst + 0); |
| 187 store(c1, dst + 1); |
| 188 store(c2, dst + 2); |
| 189 store(c3, dst + 3); |
| 190 } |
| 191 }; |
| 192 |
| 193 } // anonymous namespace |
142 | 194 |
143 #endif // Sk4fGradientPriv_DEFINED | 195 #endif // Sk4fGradientPriv_DEFINED |
OLD | NEW |