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
12///////////////////////////////////////////////////////////////////////////////
13
14static void S32_D565_Opaque(uint16_t* SK_RESTRICT dst,
15                            const SkPMColor* SK_RESTRICT src, int count,
16                            U8CPU alpha, int /*x*/, int /*y*/) {
17    SkASSERT(255 == alpha);
18
19    if (count > 0) {
20        do {
21            SkPMColor c = *src++;
22            SkPMColorAssert(c);
23            *dst++ = SkPixel32ToPixel16_ToU16(c);
24        } while (--count != 0);
25    }
26}
27
28static void S32_D565_Blend(uint16_t* SK_RESTRICT dst,
29                             const SkPMColor* SK_RESTRICT src, int count,
30                             U8CPU alpha, int /*x*/, int /*y*/) {
31    SkASSERT(255 > alpha);
32
33    if (count > 0) {
34        int scale = SkAlpha255To256(alpha);
35        do {
36            SkPMColor c = *src++;
37            SkPMColorAssert(c);
38            uint16_t d = *dst;
39            *dst++ = SkPackRGB16(
40                    SkAlphaBlend(SkPacked32ToR16(c), SkGetPackedR16(d), scale),
41                    SkAlphaBlend(SkPacked32ToG16(c), SkGetPackedG16(d), scale),
42                    SkAlphaBlend(SkPacked32ToB16(c), SkGetPackedB16(d), scale));
43        } while (--count != 0);
44    }
45}
46
47static void S32A_D565_Opaque(uint16_t* SK_RESTRICT dst,
48                               const SkPMColor* SK_RESTRICT src, int count,
49                               U8CPU alpha, int /*x*/, int /*y*/) {
50    SkASSERT(255 == alpha);
51
52    if (count > 0) {
53        do {
54            SkPMColor c = *src++;
55            SkPMColorAssert(c);
56//            if (__builtin_expect(c!=0, 1))
57            if (c) {
58                *dst = SkSrcOver32To16(c, *dst);
59            }
60            dst += 1;
61        } while (--count != 0);
62    }
63}
64
65static void S32A_D565_Blend(uint16_t* SK_RESTRICT dst,
66                              const SkPMColor* SK_RESTRICT src, int count,
67                               U8CPU alpha, int /*x*/, int /*y*/) {
68    SkASSERT(255 > alpha);
69
70    if (count > 0) {
71        do {
72            SkPMColor sc = *src++;
73            SkPMColorAssert(sc);
74            if (sc) {
75                uint16_t dc = *dst;
76                unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
77                unsigned dr = SkMulS16(SkPacked32ToR16(sc), alpha) + SkMulS16(SkGetPackedR16(dc), dst_scale);
78                unsigned dg = SkMulS16(SkPacked32ToG16(sc), alpha) + SkMulS16(SkGetPackedG16(dc), dst_scale);
79                unsigned db = SkMulS16(SkPacked32ToB16(sc), alpha) + SkMulS16(SkGetPackedB16(dc), dst_scale);
80                *dst = SkPackRGB16(SkDiv255Round(dr), SkDiv255Round(dg), SkDiv255Round(db));
81            }
82            dst += 1;
83        } while (--count != 0);
84    }
85}
86
87/////////////////////////////////////////////////////////////////////////////
88
89static void S32_D565_Opaque_Dither(uint16_t* SK_RESTRICT dst,
90                                     const SkPMColor* SK_RESTRICT src,
91                                     int count, U8CPU alpha, int x, int y) {
92    SkASSERT(255 == alpha);
93
94    if (count > 0) {
95        DITHER_565_SCAN(y);
96        do {
97            SkPMColor c = *src++;
98            SkPMColorAssert(c);
99
100            unsigned dither = DITHER_VALUE(x);
101            *dst++ = SkDitherRGB32To565(c, dither);
102            DITHER_INC_X(x);
103        } while (--count != 0);
104    }
105}
106
107static void S32_D565_Blend_Dither(uint16_t* SK_RESTRICT dst,
108                                    const SkPMColor* SK_RESTRICT src,
109                                    int count, U8CPU alpha, int x, int y) {
110    SkASSERT(255 > alpha);
111
112    if (count > 0) {
113        int scale = SkAlpha255To256(alpha);
114        DITHER_565_SCAN(y);
115        do {
116            SkPMColor c = *src++;
117            SkPMColorAssert(c);
118
119            int dither = DITHER_VALUE(x);
120            int sr = SkGetPackedR32(c);
121            int sg = SkGetPackedG32(c);
122            int sb = SkGetPackedB32(c);
123            sr = SkDITHER_R32To565(sr, dither);
124            sg = SkDITHER_G32To565(sg, dither);
125            sb = SkDITHER_B32To565(sb, dither);
126
127            uint16_t d = *dst;
128            *dst++ = SkPackRGB16(SkAlphaBlend(sr, SkGetPackedR16(d), scale),
129                                 SkAlphaBlend(sg, SkGetPackedG16(d), scale),
130                                 SkAlphaBlend(sb, SkGetPackedB16(d), scale));
131            DITHER_INC_X(x);
132        } while (--count != 0);
133    }
134}
135
136static void S32A_D565_Opaque_Dither(uint16_t* SK_RESTRICT dst,
137                                      const SkPMColor* SK_RESTRICT src,
138                                      int count, U8CPU alpha, int x, int y) {
139    SkASSERT(255 == alpha);
140
141    if (count > 0) {
142        DITHER_565_SCAN(y);
143        do {
144            SkPMColor c = *src++;
145            SkPMColorAssert(c);
146            if (c) {
147                unsigned a = SkGetPackedA32(c);
148
149                int d = SkAlphaMul(DITHER_VALUE(x), SkAlpha255To256(a));
150
151                unsigned sr = SkGetPackedR32(c);
152                unsigned sg = SkGetPackedG32(c);
153                unsigned sb = SkGetPackedB32(c);
154                sr = SkDITHER_R32_FOR_565(sr, d);
155                sg = SkDITHER_G32_FOR_565(sg, d);
156                sb = SkDITHER_B32_FOR_565(sb, d);
157
158                uint32_t src_expanded = (sg << 24) | (sr << 13) | (sb << 2);
159                uint32_t dst_expanded = SkExpand_rgb_16(*dst);
160                dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3);
161                // now src and dst expanded are in g:11 r:10 x:1 b:10
162                *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5);
163            }
164            dst += 1;
165            DITHER_INC_X(x);
166        } while (--count != 0);
167    }
168}
169
170static void S32A_D565_Blend_Dither(uint16_t* SK_RESTRICT dst,
171                                     const SkPMColor* SK_RESTRICT src,
172                                     int count, U8CPU alpha, int x, int y) {
173    SkASSERT(255 > alpha);
174
175    if (count > 0) {
176        int src_scale = SkAlpha255To256(alpha);
177        DITHER_565_SCAN(y);
178        do {
179            SkPMColor c = *src++;
180            SkPMColorAssert(c);
181            if (c)
182            {
183                unsigned d = *dst;
184                int sa = SkGetPackedA32(c);
185                int dst_scale = SkAlpha255To256(255 - SkAlphaMul(sa, src_scale));
186                int dither = DITHER_VALUE(x);
187
188                int sr = SkGetPackedR32(c);
189                int sg = SkGetPackedG32(c);
190                int sb = SkGetPackedB32(c);
191                sr = SkDITHER_R32To565(sr, dither);
192                sg = SkDITHER_G32To565(sg, dither);
193                sb = SkDITHER_B32To565(sb, dither);
194
195                int dr = (sr * src_scale + SkGetPackedR16(d) * dst_scale) >> 8;
196                int dg = (sg * src_scale + SkGetPackedG16(d) * dst_scale) >> 8;
197                int db = (sb * src_scale + SkGetPackedB16(d) * dst_scale) >> 8;
198
199                *dst = SkPackRGB16(dr, dg, db);
200            }
201            dst += 1;
202            DITHER_INC_X(x);
203        } while (--count != 0);
204    }
205}
206
207///////////////////////////////////////////////////////////////////////////////
208///////////////////////////////////////////////////////////////////////////////
209
210static const SkBlitRow::Proc gDefault_565_Procs[] = {
211    // no dither
212    S32_D565_Opaque,
213    S32_D565_Blend,
214
215    S32A_D565_Opaque,
216    S32A_D565_Blend,
217
218    // dither
219    S32_D565_Opaque_Dither,
220    S32_D565_Blend_Dither,
221
222    S32A_D565_Opaque_Dither,
223    S32A_D565_Blend_Dither
224};
225
226extern SkBlitRow::Proc SkBlitRow_Factory_4444(unsigned flags);
227
228SkBlitRow::Proc SkBlitRow::Factory(unsigned flags, SkBitmap::Config config) {
229    SkASSERT(flags < SK_ARRAY_COUNT(gDefault_565_Procs));
230    // just so we don't crash
231    flags &= kFlags16_Mask;
232
233    SkBlitRow::Proc proc = NULL;
234
235    switch (config) {
236        case SkBitmap::kRGB_565_Config:
237            proc = PlatformProcs565(flags);
238            if (NULL == proc) {
239                proc = gDefault_565_Procs[flags];
240            }
241            break;
242        case SkBitmap::kARGB_4444_Config:
243            proc = PlatformProcs4444(flags);
244            if (NULL == proc) {
245                proc = SkBlitRow_Factory_4444(flags);
246            }
247            break;
248        default:
249            break;
250    }
251    return proc;
252}
253
254