blob: 1f6c6747bb825863f26f2d29287c3b36eba5c321 [file] [log] [blame]
reed395eabe2016-01-30 18:52:31 -08001/*
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
12struct XferProcPair {
13 SkXfermode::PM4fProc1 fP1;
14 SkXfermode::PM4fProcN fPN;
15};
16
17enum DstType {
18 kLinear_Dst,
19 kSRGB_Dst,
20};
21
22static Sk4f scale_by_coverage(const Sk4f& x4, uint8_t coverage) {
23 return x4 * Sk4f(coverage * (1/255.0f));
24}
25
26static Sk4f lerp(const Sk4f& src, const Sk4f& dst, uint8_t srcCoverage) {
27 return dst + (src - dst) * Sk4f(srcCoverage * (1/255.0f));
28}
29
30template <DstType D> Sk4f load_dst(SkPMColor dstC) {
31 return (D == kSRGB_Dst) ? Sk4f_fromS32(dstC) : Sk4f_fromL32(dstC);
32}
33
reedbf907e62016-02-02 11:00:55 -080034static Sk4f srgb_4b_to_linear_unit(SkPMColor dstC) {
35 return Sk4f_fromS32(dstC);
36}
37
reed395eabe2016-01-30 18:52:31 -080038template <DstType D> uint32_t store_dst(const Sk4f& x4) {
39 return (D == kSRGB_Dst) ? Sk4f_toS32(x4) : Sk4f_toL32(x4);
40}
41
reedbf907e62016-02-02 11:00:55 -080042static Sk4f linear_unit_to_srgb_255f(const Sk4f& l4) {
43 return linear_to_srgb(l4) * Sk4f(255) + Sk4f(0.5f);
44}
45
reed395eabe2016-01-30 18:52:31 -080046///////////////////////////////////////////////////////////////////////////////////////////////////
47
48static Sk4f scale_255_round(const SkPM4f& pm4) {
49 return Sk4f::Load(pm4.fVec) * Sk4f(255) + Sk4f(0.5f);
50}
51
52static void pm4f_to_linear_32(SkPMColor dst[], const SkPM4f src[], int count) {
53 while (count >= 4) {
54 src[0].assertIsUnit();
55 src[1].assertIsUnit();
56 src[2].assertIsUnit();
57 src[3].assertIsUnit();
58 Sk4f_ToBytes((uint8_t*)dst,
59 scale_255_round(src[0]), scale_255_round(src[1]),
60 scale_255_round(src[2]), scale_255_round(src[3]));
61 src += 4;
62 dst += 4;
63 count -= 4;
64 }
65 for (int i = 0; i < count; ++i) {
66 src[i].assertIsUnit();
67 SkNx_cast<uint8_t>(scale_255_round(src[i])).store((uint8_t*)&dst[i]);
68 }
69}
70
71///////////////////////////////////////////////////////////////////////////////////////////////////
72// These are our fallback impl for the SkPM4f procs...
73//
74// They just convert the src color(s) into a linear SkPMColor value(s), and then
75// call the existing virtual xfer32. This clear throws away data (converting floats to bytes)
76// in the src, and ignores the sRGB flag, but should draw about the same as if the caller
77// had passed in SkPMColor values directly.
78//
79
80void xfer_pm4_proc_1(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f& src,
81 int count, const SkAlpha aa[]) {
82 uint32_t pm;
83 pm4f_to_linear_32(&pm, &src, 1);
84
85 const int N = 128;
86 SkPMColor tmp[N];
87 sk_memset32(tmp, pm, SkMin32(count, N));
88 while (count > 0) {
89 const int n = SkMin32(count, N);
90 state.fXfer->xfer32(dst, tmp, n, aa);
91
92 dst += n;
93 if (aa) {
94 aa += n;
95 }
96 count -= n;
97 }
98}
99
100void xfer_pm4_proc_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f src[],
101 int count, const SkAlpha aa[]) {
102 const int N = 128;
103 SkPMColor tmp[N];
104 while (count > 0) {
105 const int n = SkMin32(count, N);
106 pm4f_to_linear_32(tmp, src, n);
107 state.fXfer->xfer32(dst, tmp, n, aa);
108
109 src += n;
110 dst += n;
111 if (aa) {
112 aa += n;
113 }
114 count -= n;
115 }
116}
117
118///////////////////////////////////////////////////////////////////////////////////////////////////
119
120static void clear_linear_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f[],
121 int count, const SkAlpha aa[]) {
122 if (aa) {
123 for (int i = 0; i < count; ++i) {
124 unsigned a = aa[i];
125 if (a) {
126 SkPMColor dstC = dst[i];
127 SkPMColor C = 0;
128 if (0xFF != a) {
129 C = SkFourByteInterp(C, dstC, a);
130 }
131 dst[i] = C;
132 }
133 }
134 } else {
135 sk_bzero(dst, count * sizeof(SkPMColor));
136 }
137}
138
139static void clear_linear_1(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f&,
140 int count, const SkAlpha coverage[]) {
141 clear_linear_n(state, dst, nullptr, count, coverage);
142}
143
144static void clear_srgb_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f[],
145 int count, const SkAlpha aa[]) {
146 if (aa) {
147 for (int i = 0; i < count; ++i) {
148 unsigned a = aa[i];
149 if (a) {
150 Sk4f d = Sk4f_fromS32(dst[i]) * Sk4f((255 - a) * (1/255.0f));
151 dst[i] = Sk4f_toS32(d);
152 }
153 }
154 } else {
155 sk_bzero(dst, count * sizeof(SkPMColor));
156 }
157}
158
159static void clear_srgb_1(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f&,
160 int count, const SkAlpha coverage[]) {
161 clear_srgb_n(state, dst, nullptr, count, coverage);
162}
163
164const XferProcPair gProcs_Clear[] = {
165 { clear_linear_1, clear_linear_n }, // linear [alpha]
166 { clear_linear_1, clear_linear_n }, // linear [opaque]
167 { clear_srgb_1, clear_srgb_n }, // srgb [alpha]
168 { clear_srgb_1, clear_srgb_n }, // srgb [opaque]
169};
170
171///////////////////////////////////////////////////////////////////////////////////////////////////
172
173template <DstType D> void src_n(const SkXfermode::PM4fState& state, uint32_t dst[],
174 const SkPM4f src[], int count, const SkAlpha aa[]) {
175 for (int i = 0; i < count; ++i) {
176 unsigned a = 0xFF;
177 if (aa) {
178 a = aa[i];
179 if (0 == a) {
180 continue;
181 }
182 }
183 Sk4f r4 = Sk4f::Load(src[i].fVec); // src always overrides dst
184 if (a != 0xFF) {
185 Sk4f d4 = load_dst<D>(dst[i]);
186 r4 = lerp(r4, d4, a);
187 }
188 dst[i] = store_dst<D>(r4);
189 }
190}
191
reed6dfc7542016-02-03 10:09:22 -0800192static Sk4f lerp(const Sk4f& src, const Sk4f& dst, const Sk4f& src_scale) {
193 return dst + (src - dst) * src_scale;
194}
195
reed395eabe2016-01-30 18:52:31 -0800196template <DstType D> void src_1(const SkXfermode::PM4fState& state, uint32_t dst[],
197 const SkPM4f& src, int count, const SkAlpha aa[]) {
reed6dfc7542016-02-03 10:09:22 -0800198 const Sk4f s4 = Sk4f::Load(src.fVec);
reed395eabe2016-01-30 18:52:31 -0800199
200 if (aa) {
reed6dfc7542016-02-03 10:09:22 -0800201 if (D == kLinear_Dst) {
202 // operate in bias-255 space for src and dst
203 const Sk4f& s4_255 = s4 * Sk4f(255);
204 while (count >= 4) {
205 Sk4f aa4 = SkNx_cast<float>(Sk4b::Load(aa)) * Sk4f(1/255.f);
mtklein7c249e52016-02-21 10:54:19 -0800206 Sk4f r0 = lerp(s4_255, to_4f(dst[0]), Sk4f(aa4[0])) + Sk4f(0.5f);
207 Sk4f r1 = lerp(s4_255, to_4f(dst[1]), Sk4f(aa4[1])) + Sk4f(0.5f);
208 Sk4f r2 = lerp(s4_255, to_4f(dst[2]), Sk4f(aa4[2])) + Sk4f(0.5f);
209 Sk4f r3 = lerp(s4_255, to_4f(dst[3]), Sk4f(aa4[3])) + Sk4f(0.5f);
reed6dfc7542016-02-03 10:09:22 -0800210 Sk4f_ToBytes((uint8_t*)dst, r0, r1, r2, r3);
211
212 dst += 4;
213 aa += 4;
214 count -= 4;
reed395eabe2016-01-30 18:52:31 -0800215 }
reed6dfc7542016-02-03 10:09:22 -0800216 } else { // kSRGB
217 while (count >= 4) {
218 Sk4f aa4 = SkNx_cast<float>(Sk4b::Load(aa)) * Sk4f(1/255.0f);
219
220 /* If we ever natively support convert 255_linear -> 255_srgb, then perhaps
221 * it would be faster (and possibly allow more code sharing with kLinear) to
222 * stay in that space.
223 */
mtklein7c249e52016-02-21 10:54:19 -0800224 Sk4f r0 = lerp(s4, load_dst<D>(dst[0]), Sk4f(aa4[0]));
225 Sk4f r1 = lerp(s4, load_dst<D>(dst[1]), Sk4f(aa4[1]));
226 Sk4f r2 = lerp(s4, load_dst<D>(dst[2]), Sk4f(aa4[2]));
227 Sk4f r3 = lerp(s4, load_dst<D>(dst[3]), Sk4f(aa4[3]));
reed6dfc7542016-02-03 10:09:22 -0800228 Sk4f_ToBytes((uint8_t*)dst,
229 linear_unit_to_srgb_255f(r0),
230 linear_unit_to_srgb_255f(r1),
231 linear_unit_to_srgb_255f(r2),
232 linear_unit_to_srgb_255f(r3));
233
234 dst += 4;
235 aa += 4;
236 count -= 4;
reed395eabe2016-01-30 18:52:31 -0800237 }
238 }
reed6dfc7542016-02-03 10:09:22 -0800239 for (int i = 0; i < count; ++i) {
240 unsigned a = aa[i];
241 Sk4f d4 = load_dst<D>(dst[i]);
242 dst[i] = store_dst<D>(lerp(s4, d4, a));
243 }
reed395eabe2016-01-30 18:52:31 -0800244 } else {
reed6dfc7542016-02-03 10:09:22 -0800245 sk_memset32(dst, store_dst<D>(s4), count);
reed395eabe2016-01-30 18:52:31 -0800246 }
247}
248
249const XferProcPair gProcs_Src[] = {
250 { src_1<kLinear_Dst>, src_n<kLinear_Dst> }, // linear [alpha]
251 { src_1<kLinear_Dst>, src_n<kLinear_Dst> }, // linear [opaque]
252 { src_1<kSRGB_Dst>, src_n<kSRGB_Dst> }, // srgb [alpha]
253 { src_1<kSRGB_Dst>, src_n<kSRGB_Dst> }, // srgb [opaque]
254};
255
256///////////////////////////////////////////////////////////////////////////////////////////////////
257
258static void dst_n(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f[],
259 int count, const SkAlpha aa[]) {}
260
261static void dst_1(const SkXfermode::PM4fState& state, uint32_t dst[], const SkPM4f&,
262 int count, const SkAlpha coverage[]) {}
263
264const XferProcPair gProcs_Dst[] = {
265 { dst_1, dst_n },
266 { dst_1, dst_n },
267 { dst_1, dst_n },
268 { dst_1, dst_n },
269};
270
271///////////////////////////////////////////////////////////////////////////////////////////////////
272
273template <DstType D> void srcover_n(const SkXfermode::PM4fState& state, uint32_t dst[],
274 const SkPM4f src[], int count, const SkAlpha aa[]) {
275 if (aa) {
276 for (int i = 0; i < count; ++i) {
277 unsigned a = aa[i];
278 if (0 == a) {
279 continue;
280 }
281 Sk4f s4 = Sk4f::Load(src[i].fVec);
282 Sk4f d4 = load_dst<D>(dst[i]);
283 if (a != 0xFF) {
284 s4 = scale_by_coverage(s4, a);
285 }
286 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
287 dst[i] = store_dst<D>(r4);
288 }
289 } else {
290 for (int i = 0; i < count; ++i) {
291 Sk4f s4 = Sk4f::Load(src[i].fVec);
292 Sk4f d4 = load_dst<D>(dst[i]);
293 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
294 dst[i] = store_dst<D>(r4);
295 }
296 }
297}
298
reedbf907e62016-02-02 11:00:55 -0800299static void srcover_linear_dst_1(const SkXfermode::PM4fState& state, uint32_t dst[],
300 const SkPM4f& src, int count, const SkAlpha aa[]) {
reedef5252e2016-02-03 09:47:46 -0800301 const Sk4f s4 = Sk4f::Load(src.fVec);
302 const Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
reedbf907e62016-02-02 11:00:55 -0800303
304 if (aa) {
305 for (int i = 0; i < count; ++i) {
306 unsigned a = aa[i];
307 if (0 == a) {
308 continue;
309 }
310 Sk4f d4 = Sk4f_fromL32(dst[i]);
311 Sk4f r4;
312 if (a != 0xFF) {
reedef5252e2016-02-03 09:47:46 -0800313 Sk4f s4_aa = scale_by_coverage(s4, a);
314 r4 = s4_aa + d4 * Sk4f(1 - get_alpha(s4_aa));
reedbf907e62016-02-02 11:00:55 -0800315 } else {
316 r4 = s4 + d4 * dst_scale;
317 }
318 dst[i] = Sk4f_toL32(r4);
319 }
320 } else {
reedef5252e2016-02-03 09:47:46 -0800321 const Sk4f s4_255 = s4 * Sk4f(255) + Sk4f(0.5f); // +0.5 to pre-bias for rounding
reedbf907e62016-02-02 11:00:55 -0800322 while (count >= 4) {
323 Sk4f d0 = to_4f(dst[0]);
324 Sk4f d1 = to_4f(dst[1]);
325 Sk4f d2 = to_4f(dst[2]);
326 Sk4f d3 = to_4f(dst[3]);
327 Sk4f_ToBytes((uint8_t*)dst,
reedef5252e2016-02-03 09:47:46 -0800328 s4_255 + d0 * dst_scale,
329 s4_255 + d1 * dst_scale,
330 s4_255 + d2 * dst_scale,
331 s4_255 + d3 * dst_scale);
reedbf907e62016-02-02 11:00:55 -0800332 dst += 4;
333 count -= 4;
334 }
335 for (int i = 0; i < count; ++i) {
336 Sk4f d4 = to_4f(dst[i]);
reedef5252e2016-02-03 09:47:46 -0800337 dst[i] = to_4b(s4_255 + d4 * dst_scale);
reedbf907e62016-02-02 11:00:55 -0800338 }
339 }
340}
341
342static void srcover_srgb_dst_1(const SkXfermode::PM4fState& state, uint32_t dst[],
343 const SkPM4f& src, int count, const SkAlpha aa[]) {
344 Sk4f s4 = Sk4f::Load(src.fVec);
345 Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
reed395eabe2016-01-30 18:52:31 -0800346
347 if (aa) {
348 for (int i = 0; i < count; ++i) {
349 unsigned a = aa[i];
350 if (0 == a) {
351 continue;
352 }
reedbf907e62016-02-02 11:00:55 -0800353 Sk4f d4 = srgb_4b_to_linear_unit(dst[i]);
reed395eabe2016-01-30 18:52:31 -0800354 Sk4f r4;
355 if (a != 0xFF) {
reedef5252e2016-02-03 09:47:46 -0800356 const Sk4f s4_aa = scale_by_coverage(s4, a);
357 r4 = s4_aa + d4 * Sk4f(1 - get_alpha(s4_aa));
reed395eabe2016-01-30 18:52:31 -0800358 } else {
reedbf907e62016-02-02 11:00:55 -0800359 r4 = s4 + d4 * dst_scale;
reed395eabe2016-01-30 18:52:31 -0800360 }
reedef5252e2016-02-03 09:47:46 -0800361 dst[i] = to_4b(linear_unit_to_srgb_255f(r4));
reed395eabe2016-01-30 18:52:31 -0800362 }
363 } else {
reedbf907e62016-02-02 11:00:55 -0800364 while (count >= 4) {
365 Sk4f d0 = srgb_4b_to_linear_unit(dst[0]);
366 Sk4f d1 = srgb_4b_to_linear_unit(dst[1]);
367 Sk4f d2 = srgb_4b_to_linear_unit(dst[2]);
368 Sk4f d3 = srgb_4b_to_linear_unit(dst[3]);
369 Sk4f_ToBytes((uint8_t*)dst,
370 linear_unit_to_srgb_255f(s4 + d0 * dst_scale),
371 linear_unit_to_srgb_255f(s4 + d1 * dst_scale),
372 linear_unit_to_srgb_255f(s4 + d2 * dst_scale),
373 linear_unit_to_srgb_255f(s4 + d3 * dst_scale));
374 dst += 4;
375 count -= 4;
376 }
reed395eabe2016-01-30 18:52:31 -0800377 for (int i = 0; i < count; ++i) {
reedbf907e62016-02-02 11:00:55 -0800378 Sk4f d4 = srgb_4b_to_linear_unit(dst[i]);
379 dst[i] = to_4b(linear_unit_to_srgb_255f(s4 + d4 * dst_scale));
reed395eabe2016-01-30 18:52:31 -0800380 }
381 }
382}
383
384const XferProcPair gProcs_SrcOver[] = {
reedbf907e62016-02-02 11:00:55 -0800385 { srcover_linear_dst_1, srcover_n<kLinear_Dst> }, // linear alpha
386 { src_1<kLinear_Dst>, src_n<kLinear_Dst> }, // linear opaque [ we are src-mode ]
387 { srcover_srgb_dst_1, srcover_n<kSRGB_Dst> }, // srgb alpha
388 { src_1<kSRGB_Dst>, src_n<kSRGB_Dst> }, // srgb opaque [ we are src-mode ]
reed395eabe2016-01-30 18:52:31 -0800389};
390
391///////////////////////////////////////////////////////////////////////////////////////////////////
392
393static XferProcPair find_procs(SkXfermode::Mode mode, uint32_t flags) {
394 SkASSERT(0 == (flags & ~3));
395 flags &= 3;
396
397 switch (mode) {
398 case SkXfermode::kClear_Mode: return gProcs_Clear[flags];
399 case SkXfermode::kSrc_Mode: return gProcs_Src[flags];
400 case SkXfermode::kDst_Mode: return gProcs_Dst[flags];
401 case SkXfermode::kSrcOver_Mode: return gProcs_SrcOver[flags];
402 default:
403 break;
404 }
405 return { xfer_pm4_proc_1, xfer_pm4_proc_n };
406}
407
408SkXfermode::PM4fProc1 SkXfermode::GetPM4fProc1(Mode mode, uint32_t flags) {
409 return find_procs(mode, flags).fP1;
410}
411
412SkXfermode::PM4fProcN SkXfermode::GetPM4fProcN(Mode mode, uint32_t flags) {
413 return find_procs(mode, flags).fPN;
414}
415
416SkXfermode::PM4fProc1 SkXfermode::getPM4fProc1(uint32_t flags) const {
417 Mode mode;
418 return this->asMode(&mode) ? GetPM4fProc1(mode, flags) : xfer_pm4_proc_1;
419}
420
421SkXfermode::PM4fProcN SkXfermode::getPM4fProcN(uint32_t flags) const {
422 Mode mode;
423 return this->asMode(&mode) ? GetPM4fProcN(mode, flags) : xfer_pm4_proc_n;
424}
reed4528c862016-02-18 08:16:33 -0800425
426///////////////////////////////////////////////////////////////////////////////////////////////////
427#include "SkColorPriv.h"
428
429static Sk4f lcd16_to_unit_4f(uint16_t rgb) {
reed3b32bc52016-02-19 13:46:03 -0800430#ifdef SK_PMCOLOR_IS_RGBA
reed4528c862016-02-18 08:16:33 -0800431 Sk4i rgbi = Sk4i(SkGetPackedR16(rgb), SkGetPackedG16(rgb), SkGetPackedB16(rgb), 0);
reed3b32bc52016-02-19 13:46:03 -0800432#else
433 Sk4i rgbi = Sk4i(SkGetPackedB16(rgb), SkGetPackedG16(rgb), SkGetPackedR16(rgb), 0);
434#endif
reed4528c862016-02-18 08:16:33 -0800435 return SkNx_cast<float>(rgbi) * Sk4f(1.0f/31, 1.0f/63, 1.0f/31, 0);
436}
437
438template <DstType D>
439void src_1_lcd(uint32_t dst[], const SkPM4f* src, int count, const uint16_t lcd[]) {
440 const Sk4f s4 = Sk4f::Load(src->fVec);
441
442 if (D == kLinear_Dst) {
443 // operate in bias-255 space for src and dst
444 const Sk4f s4bias = s4 * Sk4f(255);
445 for (int i = 0; i < count; ++i) {
446 uint16_t rgb = lcd[i];
447 if (0 == rgb) {
448 continue;
449 }
450 Sk4f d4bias = to_4f(dst[i]);
451 dst[i] = to_4b(lerp(s4bias, d4bias, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
452 }
453 } else { // kSRGB
454 for (int i = 0; i < count; ++i) {
455 uint16_t rgb = lcd[i];
456 if (0 == rgb) {
457 continue;
458 }
459 Sk4f d4 = load_dst<D>(dst[i]);
460 dst[i] = store_dst<D>(lerp(s4, d4, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
461 }
462 }
463}
464
465template <DstType D>
466void src_n_lcd(uint32_t dst[], const SkPM4f src[], int count, const uint16_t lcd[]) {
467 for (int i = 0; i < count; ++i) {
468 uint16_t rgb = lcd[i];
469 if (0 == rgb) {
470 continue;
471 }
472 Sk4f s4 = Sk4f::Load(src[i].fVec);
473 Sk4f d4 = load_dst<D>(dst[i]);
474 dst[i] = store_dst<D>(lerp(s4, d4, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
475 }
476}
477
478template <DstType D>
479void srcover_1_lcd(uint32_t dst[], const SkPM4f* src, int count, const uint16_t lcd[]) {
480 const Sk4f s4 = Sk4f::Load(src->fVec);
481 Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
482
483 for (int i = 0; i < count; ++i) {
484 uint16_t rgb = lcd[i];
485 if (0 == rgb) {
486 continue;
487 }
488 Sk4f d4 = load_dst<D>(dst[i]);
489 Sk4f r4 = s4 + d4 * dst_scale;
490 r4 = lerp(r4, d4, lcd16_to_unit_4f(rgb));
491 dst[i] = store_dst<D>(r4) | (SK_A32_MASK << SK_A32_SHIFT);
492 }
493}
494
495template <DstType D>
496void srcover_n_lcd(uint32_t dst[], const SkPM4f src[], int count, const uint16_t lcd[]) {
497 for (int i = 0; i < count; ++i) {
498 uint16_t rgb = lcd[i];
499 if (0 == rgb) {
500 continue;
501 }
502 Sk4f s4 = Sk4f::Load(src[i].fVec);
503 Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
504 Sk4f d4 = load_dst<D>(dst[i]);
505 Sk4f r4 = s4 + d4 * dst_scale;
506 r4 = lerp(r4, d4, lcd16_to_unit_4f(rgb));
507 dst[i] = store_dst<D>(r4) | (SK_A32_MASK << SK_A32_SHIFT);
508 }
509}
510
511SkXfermode::LCD32Proc SkXfermode::GetLCD32Proc(uint32_t flags) {
512 SkASSERT((flags & ~7) == 0);
513 flags &= 7;
514
515 const LCD32Proc procs[] = {
516 srcover_n_lcd<kSRGB_Dst>, src_n_lcd<kSRGB_Dst>,
517 srcover_1_lcd<kSRGB_Dst>, src_1_lcd<kSRGB_Dst>,
518
519 srcover_n_lcd<kLinear_Dst>, src_n_lcd<kLinear_Dst>,
520 srcover_1_lcd<kLinear_Dst>, src_1_lcd<kLinear_Dst>,
521 };
522 return procs[flags];
523}