OLD | NEW |
---|---|
(Empty) | |
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 #include "SkPM4fPriv.h" | |
9 #include "SkUtils.h" | |
10 #include "SkXfermode.h" | |
11 | |
12 struct XferProcPair { | |
13 SkXfermode::PM4fProc1 fP1; | |
14 SkXfermode::PM4fProcN fPN; | |
15 }; | |
16 | |
17 enum DstType { | |
18 kLinear_Dst, | |
19 kSRGB_Dst, | |
20 }; | |
21 | |
22 static Sk4f scale_by_coverage(const Sk4f& x4, uint8_t coverage) { | |
23 return x4 * Sk4f(coverage * (1/255.0f)); | |
24 } | |
25 | |
26 static Sk4f lerp(const Sk4f& src, const Sk4f& dst, uint8_t srcCoverage) { | |
27 return dst + (src - dst) * Sk4f(srcCoverage * (1/255.0f)); | |
28 } | |
29 | |
30 template <DstType D> Sk4f load_dst(SkPMColor dstC) { | |
31 return (D == kSRGB_Dst) ? Sk4f_fromS32(dstC) : Sk4f_fromL32(dstC); | |
32 } | |
33 | |
34 template <DstType D> uint32_t store_dst(const Sk4f& x4) { | |
35 return (D == kSRGB_Dst) ? Sk4f_toS32(x4) : Sk4f_toL32(x4); | |
36 } | |
37 | |
38 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
39 | |
40 static Sk4f scale_255_round(const SkPM4f& pm4) { | |
mtklein
2016/02/01 22:53:52
Generally I like to scope one-shot helpers like th
reed1
2016/02/02 14:20:54
We can change. I find some value in naming these a
mtklein
2016/02/02 14:24:10
Lambdas can have names too...
auto scale_255_roun
| |
41 return Sk4f::Load(pm4.fVec) * Sk4f(255) + Sk4f(0.5f); | |
42 } | |
43 | |
44 static void pm4f_to_linear_32(SkPMColor dst[], const SkPM4f src[], int count) { | |
45 while (count >= 4) { | |
46 src[0].assertIsUnit(); | |
47 src[1].assertIsUnit(); | |
48 src[2].assertIsUnit(); | |
49 src[3].assertIsUnit(); | |
50 Sk4f_ToBytes((uint8_t*)dst, | |
51 scale_255_round(src[0]), scale_255_round(src[1]), | |
52 scale_255_round(src[2]), scale_255_round(src[3])); | |
53 src += 4; | |
54 dst += 4; | |
55 count -= 4; | |
56 } | |
57 for (int i = 0; i < count; ++i) { | |
58 src[i].assertIsUnit(); | |
59 SkNx_cast<uint8_t>(scale_255_round(src[i])).store((uint8_t*)&dst[i]); | |
60 } | |
61 } | |
62 | |
63 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
64 // These are our fallback impl for the SkPM4f procs... | |
65 // | |
66 // They just convert the src color(s) into a linear SkPMColor value(s), and then | |
67 // call the existing virtual xfer32. This clear throws away data (converting flo ats to bytes) | |
68 // in the src, and ignores the sRGB flag, but should draw about the same as if t he caller | |
69 // had passed in SkPMColor values directly. | |
70 // | |
71 | |
72 void xfer_pm4_proc_1(const SkXfermode::PM4fState& state, uint32_t dst[], const S kPM4f& src, | |
73 int count, const SkAlpha aa[]) { | |
74 uint32_t pm; | |
75 pm4f_to_linear_32(&pm, &src, 1); | |
76 | |
77 const int N = 128; | |
78 SkPMColor tmp[N]; | |
mtklein
2016/02/01 22:53:52
yeesh. _1 variants are a really good idea. We mi
| |
79 sk_memset32(tmp, pm, SkMin32(count, N)); | |
80 while (count > 0) { | |
81 const int n = SkMin32(count, N); | |
82 state.fXfer->xfer32(dst, tmp, n, aa); | |
83 | |
84 dst += n; | |
85 if (aa) { | |
86 aa += n; | |
87 } | |
88 count -= n; | |
89 } | |
90 } | |
91 | |
92 void xfer_pm4_proc_n(const SkXfermode::PM4fState& state, uint32_t dst[], const S kPM4f src[], | |
93 int count, const SkAlpha aa[]) { | |
94 const int N = 128; | |
95 SkPMColor tmp[N]; | |
96 while (count > 0) { | |
97 const int n = SkMin32(count, N); | |
98 pm4f_to_linear_32(tmp, src, n); | |
99 state.fXfer->xfer32(dst, tmp, n, aa); | |
100 | |
101 src += n; | |
102 dst += n; | |
103 if (aa) { | |
104 aa += n; | |
105 } | |
106 count -= n; | |
107 } | |
108 } | |
109 | |
110 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
111 | |
112 static void clear_linear_n(const SkXfermode::PM4fState& state, uint32_t dst[], c onst SkPM4f[], | |
113 int count, const SkAlpha aa[]) { | |
114 if (aa) { | |
115 for (int i = 0; i < count; ++i) { | |
116 unsigned a = aa[i]; | |
117 if (a) { | |
118 SkPMColor dstC = dst[i]; | |
119 SkPMColor C = 0; | |
120 if (0xFF != a) { | |
121 C = SkFourByteInterp(C, dstC, a); | |
122 } | |
123 dst[i] = C; | |
124 } | |
125 } | |
126 } else { | |
127 sk_bzero(dst, count * sizeof(SkPMColor)); | |
128 } | |
129 } | |
130 | |
131 static void clear_linear_1(const SkXfermode::PM4fState& state, uint32_t dst[], c onst SkPM4f&, | |
132 int count, const SkAlpha coverage[]) { | |
133 clear_linear_n(state, dst, nullptr, count, coverage); | |
mtklein
2016/02/01 22:53:52
We might want to make the _1 and _n variants take
reed1
2016/02/02 14:20:54
I certainly pondered this. Can't tell if that help
| |
134 } | |
135 | |
136 static void clear_srgb_n(const SkXfermode::PM4fState& state, uint32_t dst[], con st SkPM4f[], | |
137 int count, const SkAlpha aa[]) { | |
138 if (aa) { | |
139 for (int i = 0; i < count; ++i) { | |
140 unsigned a = aa[i]; | |
141 if (a) { | |
142 Sk4f d = Sk4f_fromS32(dst[i]) * Sk4f((255 - a) * (1/255.0f)); | |
143 dst[i] = Sk4f_toS32(d); | |
144 } | |
145 } | |
146 } else { | |
147 sk_bzero(dst, count * sizeof(SkPMColor)); | |
148 } | |
149 } | |
150 | |
151 static void clear_srgb_1(const SkXfermode::PM4fState& state, uint32_t dst[], con st SkPM4f&, | |
152 int count, const SkAlpha coverage[]) { | |
153 clear_srgb_n(state, dst, nullptr, count, coverage); | |
154 } | |
155 | |
156 const XferProcPair gProcs_Clear[] = { | |
157 { clear_linear_1, clear_linear_n }, // linear [alpha] | |
158 { clear_linear_1, clear_linear_n }, // linear [opaque] | |
159 { clear_srgb_1, clear_srgb_n }, // srgb [alpha] | |
160 { clear_srgb_1, clear_srgb_n }, // srgb [opaque] | |
161 }; | |
162 | |
163 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
164 | |
165 template <DstType D> void src_n(const SkXfermode::PM4fState& state, uint32_t dst [], | |
166 const SkPM4f src[], int count, const SkAlpha aa[ ]) { | |
167 for (int i = 0; i < count; ++i) { | |
168 unsigned a = 0xFF; | |
169 if (aa) { | |
170 a = aa[i]; | |
171 if (0 == a) { | |
172 continue; | |
173 } | |
174 } | |
175 Sk4f r4 = Sk4f::Load(src[i].fVec); // src always overrides dst | |
176 if (a != 0xFF) { | |
177 Sk4f d4 = load_dst<D>(dst[i]); | |
178 r4 = lerp(r4, d4, a); | |
179 } | |
180 dst[i] = store_dst<D>(r4); | |
181 } | |
182 } | |
183 | |
184 template <DstType D> void src_1(const SkXfermode::PM4fState& state, uint32_t dst [], | |
185 const SkPM4f& src, int count, const SkAlpha aa[] ) { | |
186 const Sk4f r4 = Sk4f::Load(src.fVec); // src always overrides dst | |
187 const uint32_t r32 = store_dst<D>(r4); | |
188 | |
189 if (aa) { | |
190 for (int i = 0; i < count; ++i) { | |
191 unsigned a = aa[i]; | |
192 if (0 == a) { | |
193 continue; | |
194 } | |
195 if (a != 0xFF) { | |
196 Sk4f d4 = load_dst<D>(dst[i]); | |
197 dst[i] = store_dst<D>(lerp(r4, d4, a)); | |
198 } else { | |
199 dst[i] = r32; | |
200 } | |
201 } | |
202 } else { | |
203 sk_memset32(dst, r32, count); | |
204 } | |
205 } | |
206 | |
207 const XferProcPair gProcs_Src[] = { | |
208 { src_1<kLinear_Dst>, src_n<kLinear_Dst> }, // linear [alpha] | |
209 { src_1<kLinear_Dst>, src_n<kLinear_Dst> }, // linear [opaque] | |
210 { src_1<kSRGB_Dst>, src_n<kSRGB_Dst> }, // srgb [alpha] | |
211 { src_1<kSRGB_Dst>, src_n<kSRGB_Dst> }, // srgb [opaque] | |
212 }; | |
213 | |
214 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
215 | |
216 static void dst_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM 4f[], | |
217 int count, const SkAlpha aa[]) {} | |
218 | |
219 static void dst_1(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM 4f&, | |
220 int count, const SkAlpha coverage[]) {} | |
221 | |
222 const XferProcPair gProcs_Dst[] = { | |
223 { dst_1, dst_n }, | |
224 { dst_1, dst_n }, | |
225 { dst_1, dst_n }, | |
226 { dst_1, dst_n }, | |
227 }; | |
228 | |
229 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
230 | |
231 template <DstType D> void srcover_n(const SkXfermode::PM4fState& state, uint32_t dst[], | |
232 const SkPM4f src[], int count, const SkAlpha aa[]) { | |
233 if (aa) { | |
234 for (int i = 0; i < count; ++i) { | |
235 unsigned a = aa[i]; | |
236 if (0 == a) { | |
237 continue; | |
238 } | |
239 Sk4f s4 = Sk4f::Load(src[i].fVec); | |
240 Sk4f d4 = load_dst<D>(dst[i]); | |
241 if (a != 0xFF) { | |
242 s4 = scale_by_coverage(s4, a); | |
243 } | |
244 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); | |
245 dst[i] = store_dst<D>(r4); | |
246 } | |
247 } else { | |
248 for (int i = 0; i < count; ++i) { | |
249 Sk4f s4 = Sk4f::Load(src[i].fVec); | |
250 Sk4f d4 = load_dst<D>(dst[i]); | |
251 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); | |
252 dst[i] = store_dst<D>(r4); | |
253 } | |
254 } | |
255 } | |
256 | |
257 template <DstType D> void srcover_1(const SkXfermode::PM4fState& state, uint32_t dst[], | |
258 const SkPM4f& src, int count, const SkAlpha aa[]) { | |
259 Sk4f s4 = Sk4f::Load(src.fVec); | |
260 Sk4f scale = Sk4f(1 - get_alpha(s4)); | |
261 | |
262 if (aa) { | |
263 for (int i = 0; i < count; ++i) { | |
264 unsigned a = aa[i]; | |
265 if (0 == a) { | |
266 continue; | |
267 } | |
268 Sk4f d4 = load_dst<D>(dst[i]); | |
269 Sk4f r4; | |
270 if (a != 0xFF) { | |
271 s4 = scale_by_coverage(s4, a); | |
272 r4 = s4 + d4 * Sk4f(1 - get_alpha(s4)); | |
273 } else { | |
274 r4 = s4 + d4 * scale; | |
275 } | |
276 dst[i] = store_dst<D>(r4); | |
277 } | |
278 } else { | |
279 for (int i = 0; i < count; ++i) { | |
280 Sk4f d4 = load_dst<D>(dst[i]); | |
281 Sk4f r4 = s4 + d4 * scale; | |
282 dst[i] = store_dst<D>(r4); | |
283 } | |
284 } | |
285 } | |
286 | |
287 const XferProcPair gProcs_SrcOver[] = { | |
288 { srcover_1<kLinear_Dst>, srcover_n<kLinear_Dst> }, // linear alpha | |
289 { src_1<kLinear_Dst>, src_n<kLinear_Dst> }, // linear opaque [ we are src-mode ] | |
290 { srcover_1<kSRGB_Dst>, srcover_n<kSRGB_Dst> }, // srgb alpha | |
291 { src_1<kSRGB_Dst>, src_n<kSRGB_Dst> }, // srgb opaque [ we are src-mode ] | |
292 }; | |
293 | |
294 //////////////////////////////////////////////////////////////////////////////// /////////////////// | |
295 | |
296 static XferProcPair find_procs(SkXfermode::Mode mode, uint32_t flags) { | |
297 SkASSERT(0 == (flags & ~3)); | |
298 flags &= 3; | |
299 | |
300 switch (mode) { | |
301 case SkXfermode::kClear_Mode: return gProcs_Clear[flags]; | |
302 case SkXfermode::kSrc_Mode: return gProcs_Src[flags]; | |
303 case SkXfermode::kDst_Mode: return gProcs_Dst[flags]; | |
304 case SkXfermode::kSrcOver_Mode: return gProcs_SrcOver[flags]; | |
305 default: | |
306 break; | |
307 } | |
308 return { xfer_pm4_proc_1, xfer_pm4_proc_n }; | |
309 } | |
310 | |
311 SkXfermode::PM4fProc1 SkXfermode::GetPM4fProc1(Mode mode, uint32_t flags) { | |
312 return find_procs(mode, flags).fP1; | |
313 } | |
314 | |
315 SkXfermode::PM4fProcN SkXfermode::GetPM4fProcN(Mode mode, uint32_t flags) { | |
316 return find_procs(mode, flags).fPN; | |
317 } | |
318 | |
319 SkXfermode::PM4fProc1 SkXfermode::getPM4fProc1(uint32_t flags) const { | |
320 Mode mode; | |
321 return this->asMode(&mode) ? GetPM4fProc1(mode, flags) : xfer_pm4_proc_1; | |
322 } | |
323 | |
324 SkXfermode::PM4fProcN SkXfermode::getPM4fProcN(uint32_t flags) const { | |
325 Mode mode; | |
326 return this->asMode(&mode) ? GetPM4fProcN(mode, flags) : xfer_pm4_proc_n; | |
327 } | |
OLD | NEW |