1 /*
2  * Copyright 2011 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 "SkBlitRow.h"
9 #include "SkBlitMask.h"
10 #include "SkColorPriv.h"
11 #include "SkUtils.h"
12 
13 #define UNROLL
14 
S32_Opaque_BlitRow32(SkPMColor * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha)15 static void S32_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
16                                  const SkPMColor* SK_RESTRICT src,
17                                  int count, U8CPU alpha) {
18     SkASSERT(255 == alpha);
19     sk_memcpy32(dst, src, count);
20 }
21 
S32_Blend_BlitRow32(SkPMColor * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha)22 static void S32_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst,
23                                 const SkPMColor* SK_RESTRICT src,
24                                 int count, U8CPU alpha) {
25     SkASSERT(alpha <= 255);
26     if (count > 0) {
27         unsigned src_scale = SkAlpha255To256(alpha);
28         unsigned dst_scale = 256 - src_scale;
29 
30 #ifdef UNROLL
31         if (count & 1) {
32             *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
33             dst += 1;
34             count -= 1;
35         }
36 
37         const SkPMColor* SK_RESTRICT srcEnd = src + count;
38         while (src != srcEnd) {
39             *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
40             dst += 1;
41             *dst = SkAlphaMulQ(*(src++), src_scale) + SkAlphaMulQ(*dst, dst_scale);
42             dst += 1;
43         }
44 #else
45         do {
46             *dst = SkAlphaMulQ(*src, src_scale) + SkAlphaMulQ(*dst, dst_scale);
47             src += 1;
48             dst += 1;
49         } while (--count > 0);
50 #endif
51     }
52 }
53 
S32A_Opaque_BlitRow32(SkPMColor * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha)54 static void S32A_Opaque_BlitRow32(SkPMColor* SK_RESTRICT dst,
55                                   const SkPMColor* SK_RESTRICT src,
56                                   int count, U8CPU alpha) {
57     SkASSERT(255 == alpha);
58     if (count > 0) {
59 #ifdef UNROLL
60         if (count & 1) {
61             *dst = SkPMSrcOver(*(src++), *dst);
62             dst += 1;
63             count -= 1;
64         }
65 
66         const SkPMColor* SK_RESTRICT srcEnd = src + count;
67         while (src != srcEnd) {
68             *dst = SkPMSrcOver(*(src++), *dst);
69             dst += 1;
70             *dst = SkPMSrcOver(*(src++), *dst);
71             dst += 1;
72         }
73 #else
74         do {
75             *dst = SkPMSrcOver(*src, *dst);
76             src += 1;
77             dst += 1;
78         } while (--count > 0);
79 #endif
80     }
81 }
82 
S32A_Blend_BlitRow32(SkPMColor * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha)83 static void S32A_Blend_BlitRow32(SkPMColor* SK_RESTRICT dst,
84                                  const SkPMColor* SK_RESTRICT src,
85                                  int count, U8CPU alpha) {
86     SkASSERT(alpha <= 255);
87     if (count > 0) {
88 #ifdef UNROLL
89         if (count & 1) {
90             *dst = SkBlendARGB32(*(src++), *dst, alpha);
91             dst += 1;
92             count -= 1;
93         }
94 
95         const SkPMColor* SK_RESTRICT srcEnd = src + count;
96         while (src != srcEnd) {
97             *dst = SkBlendARGB32(*(src++), *dst, alpha);
98             dst += 1;
99             *dst = SkBlendARGB32(*(src++), *dst, alpha);
100             dst += 1;
101         }
102 #else
103         do {
104             *dst = SkBlendARGB32(*src, *dst, alpha);
105             src += 1;
106             dst += 1;
107         } while (--count > 0);
108 #endif
109     }
110 }
111 
112 ///////////////////////////////////////////////////////////////////////////////
113 
114 static const SkBlitRow::Proc32 gDefault_Procs32[] = {
115     S32_Opaque_BlitRow32,
116     S32_Blend_BlitRow32,
117     S32A_Opaque_BlitRow32,
118     S32A_Blend_BlitRow32
119 };
120 
Factory32(unsigned flags)121 SkBlitRow::Proc32 SkBlitRow::Factory32(unsigned flags) {
122     SkASSERT(flags < SK_ARRAY_COUNT(gDefault_Procs32));
123     // just so we don't crash
124     flags &= kFlags32_Mask;
125 
126     SkBlitRow::Proc32 proc = PlatformProcs32(flags);
127     if (NULL == proc) {
128         proc = gDefault_Procs32[flags];
129     }
130     SkASSERT(proc);
131     return proc;
132 }
133 
134 #include "Sk4px.h"
135 
136 // Color32 uses the blend_256_round_alt algorithm from tests/BlendTest.cpp.
137 // It's not quite perfect, but it's never wrong in the interesting edge cases,
138 // and it's quite a bit faster than blend_perfect.
139 //
140 // blend_256_round_alt is our currently blessed algorithm.  Please use it or an analogous one.
Color32(SkPMColor dst[],const SkPMColor src[],int count,SkPMColor color)141 void SkBlitRow::Color32(SkPMColor dst[], const SkPMColor src[], int count, SkPMColor color) {
142     switch (SkGetPackedA32(color)) {
143         case   0: memmove(dst, src, count * sizeof(SkPMColor)); return;
144         case 255: sk_memset32(dst, color, count);               return;
145     }
146 
147     unsigned invA = 255 - SkGetPackedA32(color);
148     invA += invA >> 7;
149     SkASSERT(invA < 256);  // We've already handled alpha == 0 above.
150 
151     Sk16h colorHighAndRound = Sk4px(color).widenHi() + Sk16h(128);
152     Sk16b invA_16x(invA);
153 
154     Sk4px::MapSrc(count, dst, src, [&](const Sk4px& src4) -> Sk4px {
155         return src4.mulWiden(invA_16x).addNarrowHi(colorHighAndRound);
156     });
157 }
158