• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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