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 "SkXfermodePriv.h"
11 #include "Sk4x4f.h"
12
rgba_to_pmcolor_order(const SkPM4f & x)13 static SkPM4f rgba_to_pmcolor_order(const SkPM4f& x) {
14 #ifdef SK_PMCOLOR_IS_BGRA
15 return {{ x.fVec[2], x.fVec[1], x.fVec[0], x.fVec[3] }};
16 #else
17 return x;
18 #endif
19 }
20
21 enum DstType {
22 kLinear_Dst,
23 kSRGB_Dst,
24 };
25
scale_by_coverage(const Sk4f & x4,uint8_t coverage)26 static Sk4f scale_by_coverage(const Sk4f& x4, uint8_t coverage) {
27 return x4 * Sk4f(coverage * (1/255.0f));
28 }
29
lerp(const Sk4f & src,const Sk4f & dst,uint8_t srcCoverage)30 static Sk4f lerp(const Sk4f& src, const Sk4f& dst, uint8_t srcCoverage) {
31 return dst + (src - dst) * Sk4f(srcCoverage * (1/255.0f));
32 }
33
load_dst(SkPMColor dstC)34 template <DstType D> Sk4f load_dst(SkPMColor dstC) {
35 return (D == kSRGB_Dst) ? Sk4f_fromS32(dstC) : Sk4f_fromL32(dstC);
36 }
37
store_dst(const Sk4f & x4)38 template <DstType D> uint32_t store_dst(const Sk4f& x4) {
39 return (D == kSRGB_Dst) ? Sk4f_toS32(x4) : Sk4f_toL32(x4);
40 }
41
load_4_srgb(const void * vptr)42 static Sk4x4f load_4_srgb(const void* vptr) {
43 auto ptr = (const uint32_t*)vptr;
44
45 Sk4x4f rgba;
46
47 rgba.r = { sk_linear_from_srgb[(ptr[0] >> 0) & 0xff],
48 sk_linear_from_srgb[(ptr[1] >> 0) & 0xff],
49 sk_linear_from_srgb[(ptr[2] >> 0) & 0xff],
50 sk_linear_from_srgb[(ptr[3] >> 0) & 0xff] };
51
52 rgba.g = { sk_linear_from_srgb[(ptr[0] >> 8) & 0xff],
53 sk_linear_from_srgb[(ptr[1] >> 8) & 0xff],
54 sk_linear_from_srgb[(ptr[2] >> 8) & 0xff],
55 sk_linear_from_srgb[(ptr[3] >> 8) & 0xff] };
56
57 rgba.b = { sk_linear_from_srgb[(ptr[0] >> 16) & 0xff],
58 sk_linear_from_srgb[(ptr[1] >> 16) & 0xff],
59 sk_linear_from_srgb[(ptr[2] >> 16) & 0xff],
60 sk_linear_from_srgb[(ptr[3] >> 16) & 0xff] };
61
62 rgba.a = SkNx_cast<float>((Sk4i::Load(ptr) >> 24) & 0xff) * (1/255.0f);
63
64 return rgba;
65 }
66
store_4_srgb(void * ptr,const Sk4x4f & p)67 static void store_4_srgb(void* ptr, const Sk4x4f& p) {
68 ( sk_linear_to_srgb(p.r) << 0
69 | sk_linear_to_srgb(p.g) << 8
70 | sk_linear_to_srgb(p.b) << 16
71 | Sk4f_round(255.0f*p.a) << 24).store(ptr);
72 }
73
74 ///////////////////////////////////////////////////////////////////////////////////////////////////
75
general_1(SkBlendMode mode,uint32_t dst[],const SkPM4f * src,int count,const SkAlpha aa[])76 template <DstType D> void general_1(SkBlendMode mode, uint32_t dst[],
77 const SkPM4f* src, int count, const SkAlpha aa[]) {
78 const SkPM4f s = rgba_to_pmcolor_order(*src);
79 SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode);
80 SkPM4f d;
81 if (aa) {
82 for (int i = 0; i < count; ++i) {
83 Sk4f d4 = load_dst<D>(dst[i]);
84 d4.store(d.fVec);
85 Sk4f r4 = Sk4f::Load(proc(s, d).fVec);
86 dst[i] = store_dst<D>(lerp(r4, d4, aa[i]));
87 }
88 } else {
89 for (int i = 0; i < count; ++i) {
90 load_dst<D>(dst[i]).store(d.fVec);
91 Sk4f r4 = Sk4f::Load(proc(s, d).fVec);
92 dst[i] = store_dst<D>(r4);
93 }
94 }
95 }
96
general_n(SkBlendMode mode,uint32_t dst[],const SkPM4f src[],int count,const SkAlpha aa[])97 template <DstType D> void general_n(SkBlendMode mode, uint32_t dst[],
98 const SkPM4f src[], int count, const SkAlpha aa[]) {
99 SkXfermodeProc4f proc = SkXfermode::GetProc4f(mode);
100 SkPM4f d;
101 if (aa) {
102 for (int i = 0; i < count; ++i) {
103 Sk4f d4 = load_dst<D>(dst[i]);
104 d4.store(d.fVec);
105 Sk4f r4 = Sk4f::Load(proc(rgba_to_pmcolor_order(src[i]), d).fVec);
106 dst[i] = store_dst<D>(lerp(r4, d4, aa[i]));
107 }
108 } else {
109 for (int i = 0; i < count; ++i) {
110 load_dst<D>(dst[i]).store(d.fVec);
111 Sk4f r4 = Sk4f::Load(proc(rgba_to_pmcolor_order(src[i]), d).fVec);
112 dst[i] = store_dst<D>(r4);
113 }
114 }
115 }
116
117 const SkXfermode::D32Proc gProcs_General[] = {
118 general_n<kLinear_Dst>, general_n<kLinear_Dst>,
119 general_1<kLinear_Dst>, general_1<kLinear_Dst>,
120 general_n<kSRGB_Dst>, general_n<kSRGB_Dst>,
121 general_1<kSRGB_Dst>, general_1<kSRGB_Dst>,
122 };
123
124 ///////////////////////////////////////////////////////////////////////////////////////////////////
125
clear_linear(SkBlendMode,uint32_t dst[],const SkPM4f[],int count,const SkAlpha aa[])126 static void clear_linear(SkBlendMode, uint32_t dst[], const SkPM4f[], int count,
127 const SkAlpha aa[]) {
128 if (aa) {
129 for (int i = 0; i < count; ++i) {
130 unsigned a = aa[i];
131 if (a) {
132 SkPMColor dstC = dst[i];
133 SkPMColor C = 0;
134 if (0xFF != a) {
135 C = SkFourByteInterp(C, dstC, a);
136 }
137 dst[i] = C;
138 }
139 }
140 } else {
141 sk_memset32(dst, 0, count);
142 }
143 }
144
clear_srgb(SkBlendMode,uint32_t dst[],const SkPM4f[],int count,const SkAlpha aa[])145 static void clear_srgb(SkBlendMode, uint32_t dst[], const SkPM4f[], int count, const SkAlpha aa[]) {
146 if (aa) {
147 for (int i = 0; i < count; ++i) {
148 if (aa[i]) {
149 Sk4f d = Sk4f_fromS32(dst[i]) * Sk4f((255 - aa[i]) * (1/255.0f));
150 dst[i] = Sk4f_toS32(d);
151 }
152 }
153 } else {
154 sk_memset32(dst, 0, count);
155 }
156 }
157
158 const SkXfermode::D32Proc gProcs_Clear[] = {
159 clear_linear, clear_linear,
160 clear_linear, clear_linear,
161 clear_srgb, clear_srgb,
162 clear_srgb, clear_srgb,
163 };
164
165 ///////////////////////////////////////////////////////////////////////////////////////////////////
166
src_n(SkBlendMode,uint32_t dst[],const SkPM4f src[],int count,const SkAlpha aa[])167 template <DstType D> void src_n(SkBlendMode, uint32_t dst[], const SkPM4f src[], int count,
168 const SkAlpha aa[]) {
169 for (int i = 0; i < count; ++i) {
170 unsigned a = 0xFF;
171 if (aa) {
172 a = aa[i];
173 if (0 == a) {
174 continue;
175 }
176 }
177 Sk4f r4 = src[i].to4f_pmorder();
178 if (a != 0xFF) {
179 Sk4f d4 = load_dst<D>(dst[i]);
180 r4 = lerp(r4, d4, a);
181 }
182 dst[i] = store_dst<D>(r4);
183 }
184 }
185
lerp(const Sk4f & src,const Sk4f & dst,const Sk4f & src_scale)186 static Sk4f lerp(const Sk4f& src, const Sk4f& dst, const Sk4f& src_scale) {
187 return dst + (src - dst) * src_scale;
188 }
189
src_1(SkBlendMode,uint32_t dst[],const SkPM4f * src,int count,const SkAlpha aa[])190 template <DstType D> void src_1(SkBlendMode, uint32_t dst[], const SkPM4f* src, int count,
191 const SkAlpha aa[]) {
192 const Sk4f s4 = src->to4f_pmorder();
193
194 if (aa) {
195 SkPMColor srcColor = store_dst<D>(s4);
196 while (count-- > 0) {
197 SkAlpha cover = *aa++;
198 switch (cover) {
199 case 0xFF: {
200 *dst++ = srcColor;
201 break;
202 }
203 case 0x00: {
204 dst++;
205 break;
206 }
207 default: {
208 Sk4f d4 = load_dst<D>(*dst);
209 *dst++ = store_dst<D>(lerp(s4, d4, cover));
210 }
211 }
212 }
213 } else {
214 sk_memset32(dst, store_dst<D>(s4), count);
215 }
216 }
217
218 const SkXfermode::D32Proc gProcs_Src[] = {
219 src_n<kLinear_Dst>, src_n<kLinear_Dst>,
220 src_1<kLinear_Dst>, src_1<kLinear_Dst>,
221 src_n<kSRGB_Dst>, src_n<kSRGB_Dst>,
222 src_1<kSRGB_Dst>, src_1<kSRGB_Dst>,
223 };
224
225 ///////////////////////////////////////////////////////////////////////////////////////////////////
226
dst(SkBlendMode,uint32_t dst[],const SkPM4f[],int count,const SkAlpha aa[])227 static void dst(SkBlendMode, uint32_t dst[], const SkPM4f[], int count, const SkAlpha aa[]) {}
228
229 const SkXfermode::D32Proc gProcs_Dst[] = {
230 dst, dst, dst, dst, dst, dst, dst, dst,
231 };
232
233 ///////////////////////////////////////////////////////////////////////////////////////////////////
234
235
srcover_n(SkBlendMode,uint32_t dst[],const SkPM4f src[],int count,const SkAlpha aa[])236 template <DstType D> void srcover_n(SkBlendMode, uint32_t dst[], const SkPM4f src[], int count,
237 const SkAlpha aa[]) {
238 if (aa) {
239 for (int i = 0; i < count; ++i) {
240 unsigned a = aa[i];
241 if (0 == a) {
242 continue;
243 }
244 Sk4f s4 = src[i].to4f_pmorder();
245 Sk4f d4 = load_dst<D>(dst[i]);
246 if (a != 0xFF) {
247 s4 = scale_by_coverage(s4, a);
248 }
249 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
250 dst[i] = store_dst<D>(r4);
251 }
252 } else {
253 while (count >= 4 && D == kSRGB_Dst) {
254 auto d = load_4_srgb(dst);
255 auto s = Sk4x4f::Transpose(src->fVec);
256 #if defined(SK_PMCOLOR_IS_BGRA)
257 SkTSwap(s.r, s.b);
258 #endif
259 auto invSA = 1.0f - s.a;
260 auto r = s.r + d.r * invSA,
261 g = s.g + d.g * invSA,
262 b = s.b + d.b * invSA,
263 a = s.a + d.a * invSA;
264 store_4_srgb(dst, Sk4x4f{r,g,b,a});
265 count -= 4;
266 dst += 4;
267 src += 4;
268 }
269 for (int i = 0; i < count; ++i) {
270 Sk4f s4 = src[i].to4f_pmorder();
271 Sk4f d4 = load_dst<D>(dst[i]);
272 Sk4f r4 = s4 + d4 * Sk4f(1 - get_alpha(s4));
273 dst[i] = store_dst<D>(r4);
274 }
275 }
276 }
277
srcover_linear_dst_1(SkBlendMode,uint32_t dst[],const SkPM4f * src,int count,const SkAlpha aa[])278 static void srcover_linear_dst_1(SkBlendMode, uint32_t dst[], const SkPM4f* src, int count,
279 const SkAlpha aa[]) {
280 const Sk4f s4 = src->to4f_pmorder();
281 const Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
282
283 if (aa) {
284 for (int i = 0; i < count; ++i) {
285 unsigned a = aa[i];
286 if (0 == a) {
287 continue;
288 }
289 Sk4f d4 = Sk4f_fromL32(dst[i]);
290 Sk4f r4;
291 if (a != 0xFF) {
292 Sk4f s4_aa = scale_by_coverage(s4, a);
293 r4 = s4_aa + d4 * Sk4f(1 - get_alpha(s4_aa));
294 } else {
295 r4 = s4 + d4 * dst_scale;
296 }
297 dst[i] = Sk4f_toL32(r4);
298 }
299 } else {
300 for (int i = 0; i < count; ++i) {
301 Sk4f d4 = Sk4f_fromL32(dst[i]);
302 dst[i] = Sk4f_toL32(s4 + d4 * dst_scale);
303 }
304 }
305 }
306
srcover_srgb_dst_1(SkBlendMode,uint32_t dst[],const SkPM4f * src,int count,const SkAlpha aa[])307 static void srcover_srgb_dst_1(SkBlendMode, uint32_t dst[], const SkPM4f* src, int count,
308 const SkAlpha aa[]) {
309 Sk4f s4 = src->to4f_pmorder();
310 Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
311
312 if (aa) {
313 for (int i = 0; i < count; ++i) {
314 unsigned a = aa[i];
315 if (0 == a) {
316 continue;
317 }
318
319 Sk4f d4 = Sk4f_fromS32(dst[i]);
320 Sk4f r4;
321 if (a != 0xFF) {
322 const Sk4f s4_aa = scale_by_coverage(s4, a);
323 r4 = s4_aa + d4 * Sk4f(1 - get_alpha(s4_aa));
324 } else {
325 r4 = s4 + d4 * dst_scale;
326 }
327 dst[i] = Sk4f_toS32(r4);
328 }
329 } else {
330 while (count >= 4) {
331 auto d = load_4_srgb(dst);
332 auto s = Sk4x4f{{ src->r() }, { src->g() }, { src->b() }, { src->a() }};
333 #if defined(SK_PMCOLOR_IS_BGRA)
334 SkTSwap(s.r, s.b);
335 #endif
336 auto invSA = 1.0f - s.a;
337 auto r = s.r + d.r * invSA,
338 g = s.g + d.g * invSA,
339 b = s.b + d.b * invSA,
340 a = s.a + d.a * invSA;
341 store_4_srgb(dst, Sk4x4f{r,g,b,a});
342 count -= 4;
343 dst += 4;
344 }
345 for (int i = 0; i < count; ++i) {
346 Sk4f d4 = Sk4f_fromS32(dst[i]);
347 dst[i] = Sk4f_toS32(s4 + d4 * dst_scale);
348 }
349 }
350 }
351
352 const SkXfermode::D32Proc gProcs_SrcOver[] = {
353 srcover_n<kLinear_Dst>, src_n<kLinear_Dst>,
354 srcover_linear_dst_1, src_1<kLinear_Dst>,
355
356 srcover_n<kSRGB_Dst>, src_n<kSRGB_Dst>,
357 srcover_srgb_dst_1, src_1<kSRGB_Dst>,
358 };
359
360 ///////////////////////////////////////////////////////////////////////////////////////////////////
361
GetD32Proc(SkBlendMode mode,uint32_t flags)362 SkXfermode::D32Proc SkXfermode::GetD32Proc(SkBlendMode mode, uint32_t flags) {
363 SkASSERT(0 == (flags & ~7));
364 flags &= 7;
365
366 switch (mode) {
367 case SkBlendMode::kClear: return gProcs_Clear[flags];
368 case SkBlendMode::kSrc: return gProcs_Src[flags];
369 case SkBlendMode::kDst: return gProcs_Dst[flags];
370 case SkBlendMode::kSrcOver: return gProcs_SrcOver[flags];
371 default:
372 break;
373 }
374 return gProcs_General[flags];
375 }
376
377 ///////////////////////////////////////////////////////////////////////////////////////////////////
378 #include "SkColorPriv.h"
379
lcd16_to_unit_4f(uint16_t rgb)380 static Sk4f lcd16_to_unit_4f(uint16_t rgb) {
381 #ifdef SK_PMCOLOR_IS_RGBA
382 Sk4i rgbi = Sk4i(SkGetPackedR16(rgb), SkGetPackedG16(rgb), SkGetPackedB16(rgb), 0);
383 #else
384 Sk4i rgbi = Sk4i(SkGetPackedB16(rgb), SkGetPackedG16(rgb), SkGetPackedR16(rgb), 0);
385 #endif
386 return SkNx_cast<float>(rgbi) * Sk4f(1.0f/31, 1.0f/63, 1.0f/31, 0);
387 }
388
389 template <DstType D>
src_1_lcd(uint32_t dst[],const SkPM4f * src,int count,const uint16_t lcd[])390 void src_1_lcd(uint32_t dst[], const SkPM4f* src, int count, const uint16_t lcd[]) {
391 const Sk4f s4 = src->to4f_pmorder();
392
393 for (int i = 0; i < count; ++i) {
394 uint16_t rgb = lcd[i];
395 if (0 == rgb) {
396 continue;
397 }
398 Sk4f d4 = load_dst<D>(dst[i]);
399 dst[i] = store_dst<D>(lerp(s4, d4, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
400 }
401 }
402
403 template <DstType D>
src_n_lcd(uint32_t dst[],const SkPM4f src[],int count,const uint16_t lcd[])404 void src_n_lcd(uint32_t dst[], const SkPM4f src[], int count, const uint16_t lcd[]) {
405 for (int i = 0; i < count; ++i) {
406 uint16_t rgb = lcd[i];
407 if (0 == rgb) {
408 continue;
409 }
410 Sk4f s4 = src[i].to4f_pmorder();
411 Sk4f d4 = load_dst<D>(dst[i]);
412 dst[i] = store_dst<D>(lerp(s4, d4, lcd16_to_unit_4f(rgb))) | (SK_A32_MASK << SK_A32_SHIFT);
413 }
414 }
415
416 template <DstType D>
srcover_1_lcd(uint32_t dst[],const SkPM4f * src,int count,const uint16_t lcd[])417 void srcover_1_lcd(uint32_t dst[], const SkPM4f* src, int count, const uint16_t lcd[]) {
418 const Sk4f s4 = src->to4f_pmorder();
419 Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
420
421 for (int i = 0; i < count; ++i) {
422 uint16_t rgb = lcd[i];
423 if (0 == rgb) {
424 continue;
425 }
426 Sk4f d4 = load_dst<D>(dst[i]);
427 Sk4f r4 = s4 + d4 * dst_scale;
428 r4 = lerp(r4, d4, lcd16_to_unit_4f(rgb));
429 dst[i] = store_dst<D>(r4) | (SK_A32_MASK << SK_A32_SHIFT);
430 }
431 }
432
433 template <DstType D>
srcover_n_lcd(uint32_t dst[],const SkPM4f src[],int count,const uint16_t lcd[])434 void srcover_n_lcd(uint32_t dst[], const SkPM4f src[], int count, const uint16_t lcd[]) {
435 for (int i = 0; i < count; ++i) {
436 uint16_t rgb = lcd[i];
437 if (0 == rgb) {
438 continue;
439 }
440 Sk4f s4 = src[i].to4f_pmorder();
441 Sk4f dst_scale = Sk4f(1 - get_alpha(s4));
442 Sk4f d4 = load_dst<D>(dst[i]);
443 Sk4f r4 = s4 + d4 * dst_scale;
444 r4 = lerp(r4, d4, lcd16_to_unit_4f(rgb));
445 dst[i] = store_dst<D>(r4) | (SK_A32_MASK << SK_A32_SHIFT);
446 }
447 }
448
GetLCD32Proc(uint32_t flags)449 SkXfermode::LCD32Proc SkXfermode::GetLCD32Proc(uint32_t flags) {
450 SkASSERT((flags & ~7) == 0);
451 flags &= 7;
452
453 const LCD32Proc procs[] = {
454 srcover_n_lcd<kLinear_Dst>, src_n_lcd<kLinear_Dst>,
455 srcover_1_lcd<kLinear_Dst>, src_1_lcd<kLinear_Dst>,
456
457 srcover_n_lcd<kSRGB_Dst>, src_n_lcd<kSRGB_Dst>,
458 srcover_1_lcd<kSRGB_Dst>, src_1_lcd<kSRGB_Dst>,
459 };
460 return procs[flags];
461 }
462