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
15static 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
29static 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
48static 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
66static 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
87static 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
105static 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
134static 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
168static 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
207static 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
214static 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
227static 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
243SkBlitRow::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 (NULL == proc) {
250        proc = gDefault_565_Procs[flags];
251    }
252    return proc;
253}
254
255static 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
266SkBlitRow::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 (NULL == proc) {
278        proc = gDefault_565_ColorProcs[flags];
279    }
280    return proc;
281}
282