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 "SkColorPriv.h"
10 #include "SkDither.h"
11 #include "SkMathPriv.h"
12 
13 ///////////////////////////////////////////////////////////////////////////////
14 
S32_D565_Opaque(uint16_t * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha,int,int)15 static void S32_D565_Opaque(uint16_t* SK_RESTRICT dst,
16                             const SkPMColor* SK_RESTRICT src, int count,
17                             U8CPU alpha, int /*x*/, int /*y*/) {
18     SkASSERT(255 == alpha);
19 
20     if (count > 0) {
21         do {
22             SkPMColor c = *src++;
23             SkPMColorAssert(c);
24             *dst++ = SkPixel32ToPixel16_ToU16(c);
25         } while (--count != 0);
26     }
27 }
28 
S32_D565_Blend(uint16_t * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha,int,int)29 static void S32_D565_Blend(uint16_t* SK_RESTRICT dst,
30                              const SkPMColor* SK_RESTRICT src, int count,
31                              U8CPU alpha, int /*x*/, int /*y*/) {
32     SkASSERT(255 > alpha);
33 
34     if (count > 0) {
35         int scale = SkAlpha255To256(alpha);
36         do {
37             SkPMColor c = *src++;
38             SkPMColorAssert(c);
39             uint16_t d = *dst;
40             *dst++ = SkPackRGB16(
41                     SkAlphaBlend(SkPacked32ToR16(c), SkGetPackedR16(d), scale),
42                     SkAlphaBlend(SkPacked32ToG16(c), SkGetPackedG16(d), scale),
43                     SkAlphaBlend(SkPacked32ToB16(c), SkGetPackedB16(d), scale));
44         } while (--count != 0);
45     }
46 }
47 
S32A_D565_Opaque(uint16_t * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha,int,int)48 static void S32A_D565_Opaque(uint16_t* SK_RESTRICT dst,
49                                const SkPMColor* SK_RESTRICT src, int count,
50                                U8CPU alpha, int /*x*/, int /*y*/) {
51     SkASSERT(255 == alpha);
52 
53     if (count > 0) {
54         do {
55             SkPMColor c = *src++;
56             SkPMColorAssert(c);
57 //            if (__builtin_expect(c!=0, 1))
58             if (c) {
59                 *dst = SkSrcOver32To16(c, *dst);
60             }
61             dst += 1;
62         } while (--count != 0);
63     }
64 }
65 
S32A_D565_Blend(uint16_t * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha,int,int)66 static void S32A_D565_Blend(uint16_t* SK_RESTRICT dst,
67                               const SkPMColor* SK_RESTRICT src, int count,
68                                U8CPU alpha, int /*x*/, int /*y*/) {
69     SkASSERT(255 > alpha);
70 
71     if (count > 0) {
72         do {
73             SkPMColor sc = *src++;
74             SkPMColorAssert(sc);
75             if (sc) {
76                 uint16_t dc = *dst;
77                 SkPMColor res = SkBlendARGB32(sc, SkPixel16ToPixel32(dc), alpha);
78                 *dst = SkPixel32ToPixel16(res);
79             }
80             dst += 1;
81         } while (--count != 0);
82     }
83 }
84 
85 /////////////////////////////////////////////////////////////////////////////
86 
S32_D565_Opaque_Dither(uint16_t * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha,int x,int y)87 static void S32_D565_Opaque_Dither(uint16_t* SK_RESTRICT dst,
88                                      const SkPMColor* SK_RESTRICT src,
89                                      int count, U8CPU alpha, int x, int y) {
90     SkASSERT(255 == alpha);
91 
92     if (count > 0) {
93         DITHER_565_SCAN(y);
94         do {
95             SkPMColor c = *src++;
96             SkPMColorAssert(c);
97 
98             unsigned dither = DITHER_VALUE(x);
99             *dst++ = SkDitherRGB32To565(c, dither);
100             DITHER_INC_X(x);
101         } while (--count != 0);
102     }
103 }
104 
S32_D565_Blend_Dither(uint16_t * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha,int x,int y)105 static void S32_D565_Blend_Dither(uint16_t* SK_RESTRICT dst,
106                                     const SkPMColor* SK_RESTRICT src,
107                                     int count, U8CPU alpha, int x, int y) {
108     SkASSERT(255 > alpha);
109 
110     if (count > 0) {
111         int scale = SkAlpha255To256(alpha);
112         DITHER_565_SCAN(y);
113         do {
114             SkPMColor c = *src++;
115             SkPMColorAssert(c);
116 
117             int dither = DITHER_VALUE(x);
118             int sr = SkGetPackedR32(c);
119             int sg = SkGetPackedG32(c);
120             int sb = SkGetPackedB32(c);
121             sr = SkDITHER_R32To565(sr, dither);
122             sg = SkDITHER_G32To565(sg, dither);
123             sb = SkDITHER_B32To565(sb, dither);
124 
125             uint16_t d = *dst;
126             *dst++ = SkPackRGB16(SkAlphaBlend(sr, SkGetPackedR16(d), scale),
127                                  SkAlphaBlend(sg, SkGetPackedG16(d), scale),
128                                  SkAlphaBlend(sb, SkGetPackedB16(d), scale));
129             DITHER_INC_X(x);
130         } while (--count != 0);
131     }
132 }
133 
S32A_D565_Opaque_Dither(uint16_t * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha,int x,int y)134 static void S32A_D565_Opaque_Dither(uint16_t* SK_RESTRICT dst,
135                                       const SkPMColor* SK_RESTRICT src,
136                                       int count, U8CPU alpha, int x, int y) {
137     SkASSERT(255 == alpha);
138 
139     if (count > 0) {
140         DITHER_565_SCAN(y);
141         do {
142             SkPMColor c = *src++;
143             SkPMColorAssert(c);
144             if (c) {
145                 unsigned a = SkGetPackedA32(c);
146 
147                 int d = SkAlphaMul(DITHER_VALUE(x), SkAlpha255To256(a));
148 
149                 unsigned sr = SkGetPackedR32(c);
150                 unsigned sg = SkGetPackedG32(c);
151                 unsigned sb = SkGetPackedB32(c);
152                 sr = SkDITHER_R32_FOR_565(sr, d);
153                 sg = SkDITHER_G32_FOR_565(sg, d);
154                 sb = SkDITHER_B32_FOR_565(sb, d);
155 
156                 uint32_t src_expanded = (sg << 24) | (sr << 13) | (sb << 2);
157                 uint32_t dst_expanded = SkExpand_rgb_16(*dst);
158                 dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3);
159                 // now src and dst expanded are in g:11 r:10 x:1 b:10
160                 *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5);
161             }
162             dst += 1;
163             DITHER_INC_X(x);
164         } while (--count != 0);
165     }
166 }
167 
S32A_D565_Blend_Dither(uint16_t * SK_RESTRICT dst,const SkPMColor * SK_RESTRICT src,int count,U8CPU alpha,int x,int y)168 static void S32A_D565_Blend_Dither(uint16_t* SK_RESTRICT dst,
169                                      const SkPMColor* SK_RESTRICT src,
170                                      int count, U8CPU alpha, int x, int y) {
171     SkASSERT(255 > alpha);
172 
173     if (count > 0) {
174         int src_scale = SkAlpha255To256(alpha);
175         DITHER_565_SCAN(y);
176         do {
177             SkPMColor c = *src++;
178             SkPMColorAssert(c);
179             if (c)
180             {
181                 unsigned d = *dst;
182                 int sa = SkGetPackedA32(c);
183                 int dst_scale = SkAlpha255To256(255 - SkAlphaMul(sa, src_scale));
184                 int dither = DITHER_VALUE(x);
185 
186                 int sr = SkGetPackedR32(c);
187                 int sg = SkGetPackedG32(c);
188                 int sb = SkGetPackedB32(c);
189                 sr = SkDITHER_R32To565(sr, dither);
190                 sg = SkDITHER_G32To565(sg, dither);
191                 sb = SkDITHER_B32To565(sb, dither);
192 
193                 int dr = (sr * src_scale + SkGetPackedR16(d) * dst_scale) >> 8;
194                 int dg = (sg * src_scale + SkGetPackedG16(d) * dst_scale) >> 8;
195                 int db = (sb * src_scale + SkGetPackedB16(d) * dst_scale) >> 8;
196 
197                 *dst = SkPackRGB16(dr, dg, db);
198             }
199             dst += 1;
200             DITHER_INC_X(x);
201         } while (--count != 0);
202     }
203 }
204 
205 ///////////////////////////////////////////////////////////////////////////////
206 
pmcolor_to_expand16(SkPMColor c)207 static uint32_t pmcolor_to_expand16(SkPMColor c) {
208     unsigned r = SkGetPackedR32(c);
209     unsigned g = SkGetPackedG32(c);
210     unsigned b = SkGetPackedB32(c);
211     return (g << 24) | (r << 13) | (b << 2);
212 }
213 
Color32A_D565(uint16_t dst[],SkPMColor src,int count,int x,int y)214 static void Color32A_D565(uint16_t dst[], SkPMColor src, int count, int x, int y) {
215     SkASSERT(count > 0);
216     uint32_t src_expand = pmcolor_to_expand16(src);
217     unsigned scale = SkAlpha255To256(0xFF - SkGetPackedA32(src)) >> 3;
218     do {
219         *dst = SkBlend32_RGB16(src_expand, *dst, scale);
220         dst += 1;
221     } while (--count != 0);
222 }
223 
224 ///////////////////////////////////////////////////////////////////////////////
225 ///////////////////////////////////////////////////////////////////////////////
226 
227 static const SkBlitRow::Proc16 gDefault_565_Procs[] = {
228     // no dither
229     S32_D565_Opaque,
230     S32_D565_Blend,
231 
232     S32A_D565_Opaque,
233     S32A_D565_Blend,
234 
235     // dither
236     S32_D565_Opaque_Dither,
237     S32_D565_Blend_Dither,
238 
239     S32A_D565_Opaque_Dither,
240     S32A_D565_Blend_Dither
241 };
242 
Factory16(unsigned flags)243 SkBlitRow::Proc16 SkBlitRow::Factory16(unsigned flags) {
244     SkASSERT(flags < SK_ARRAY_COUNT(gDefault_565_Procs));
245     // just so we don't crash
246     flags &= kFlags16_Mask;
247 
248     SkBlitRow::Proc16 proc = PlatformFactory565(flags);
249     if (nullptr == proc) {
250         proc = gDefault_565_Procs[flags];
251     }
252     return proc;
253 }
254 
255 static const SkBlitRow::ColorProc16 gDefault_565_ColorProcs[] = {
256 #if 0
257     Color32A_D565,
258     Color32A_D565_Dither
259 #else
260     // TODO: stop cheating and fill dither from the above specializations!
261     Color32A_D565,
262     Color32A_D565,
263 #endif
264 };
265 
ColorFactory16(unsigned flags)266 SkBlitRow::ColorProc16 SkBlitRow::ColorFactory16(unsigned flags) {
267     SkASSERT((flags & ~kFlags16_Mask) == 0);
268     // just so we don't crash
269     flags &= kFlags16_Mask;
270     // we ignore both kGlobalAlpha_Flag and kSrcPixelAlpha_Flag, so shift down
271     // no need for the additional code specializing on opaque alpha at this time
272     flags >>= 2;
273 
274     SkASSERT(flags < SK_ARRAY_COUNT(gDefault_565_ColorProcs));
275 
276     SkBlitRow::ColorProc16 proc = PlatformColorFactory565(flags);
277     if (nullptr == proc) {
278         proc = gDefault_565_ColorProcs[flags];
279     }
280     return proc;
281 }
282