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