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                unsigned dst_scale = 255 - SkMulDiv255Round(SkGetPackedA32(sc), alpha);
78                unsigned dr = SkMulS16(SkPacked32ToR16(sc), alpha) + SkMulS16(SkGetPackedR16(dc), dst_scale);
79                unsigned dg = SkMulS16(SkPacked32ToG16(sc), alpha) + SkMulS16(SkGetPackedG16(dc), dst_scale);
80                unsigned db = SkMulS16(SkPacked32ToB16(sc), alpha) + SkMulS16(SkGetPackedB16(dc), dst_scale);
81                *dst = SkPackRGB16(SkDiv255Round(dr), SkDiv255Round(dg), SkDiv255Round(db));
82            }
83            dst += 1;
84        } while (--count != 0);
85    }
86}
87
88/////////////////////////////////////////////////////////////////////////////
89
90static void S32_D565_Opaque_Dither(uint16_t* SK_RESTRICT dst,
91                                     const SkPMColor* SK_RESTRICT src,
92                                     int count, U8CPU alpha, int x, int y) {
93    SkASSERT(255 == alpha);
94
95    if (count > 0) {
96        DITHER_565_SCAN(y);
97        do {
98            SkPMColor c = *src++;
99            SkPMColorAssert(c);
100
101            unsigned dither = DITHER_VALUE(x);
102            *dst++ = SkDitherRGB32To565(c, dither);
103            DITHER_INC_X(x);
104        } while (--count != 0);
105    }
106}
107
108static void S32_D565_Blend_Dither(uint16_t* SK_RESTRICT dst,
109                                    const SkPMColor* SK_RESTRICT src,
110                                    int count, U8CPU alpha, int x, int y) {
111    SkASSERT(255 > alpha);
112
113    if (count > 0) {
114        int scale = SkAlpha255To256(alpha);
115        DITHER_565_SCAN(y);
116        do {
117            SkPMColor c = *src++;
118            SkPMColorAssert(c);
119
120            int dither = DITHER_VALUE(x);
121            int sr = SkGetPackedR32(c);
122            int sg = SkGetPackedG32(c);
123            int sb = SkGetPackedB32(c);
124            sr = SkDITHER_R32To565(sr, dither);
125            sg = SkDITHER_G32To565(sg, dither);
126            sb = SkDITHER_B32To565(sb, dither);
127
128            uint16_t d = *dst;
129            *dst++ = SkPackRGB16(SkAlphaBlend(sr, SkGetPackedR16(d), scale),
130                                 SkAlphaBlend(sg, SkGetPackedG16(d), scale),
131                                 SkAlphaBlend(sb, SkGetPackedB16(d), scale));
132            DITHER_INC_X(x);
133        } while (--count != 0);
134    }
135}
136
137static void S32A_D565_Opaque_Dither(uint16_t* SK_RESTRICT dst,
138                                      const SkPMColor* SK_RESTRICT src,
139                                      int count, U8CPU alpha, int x, int y) {
140    SkASSERT(255 == alpha);
141
142    if (count > 0) {
143        DITHER_565_SCAN(y);
144        do {
145            SkPMColor c = *src++;
146            SkPMColorAssert(c);
147            if (c) {
148                unsigned a = SkGetPackedA32(c);
149
150                int d = SkAlphaMul(DITHER_VALUE(x), SkAlpha255To256(a));
151
152                unsigned sr = SkGetPackedR32(c);
153                unsigned sg = SkGetPackedG32(c);
154                unsigned sb = SkGetPackedB32(c);
155                sr = SkDITHER_R32_FOR_565(sr, d);
156                sg = SkDITHER_G32_FOR_565(sg, d);
157                sb = SkDITHER_B32_FOR_565(sb, d);
158
159                uint32_t src_expanded = (sg << 24) | (sr << 13) | (sb << 2);
160                uint32_t dst_expanded = SkExpand_rgb_16(*dst);
161                dst_expanded = dst_expanded * (SkAlpha255To256(255 - a) >> 3);
162                // now src and dst expanded are in g:11 r:10 x:1 b:10
163                *dst = SkCompact_rgb_16((src_expanded + dst_expanded) >> 5);
164            }
165            dst += 1;
166            DITHER_INC_X(x);
167        } while (--count != 0);
168    }
169}
170
171static void S32A_D565_Blend_Dither(uint16_t* SK_RESTRICT dst,
172                                     const SkPMColor* SK_RESTRICT src,
173                                     int count, U8CPU alpha, int x, int y) {
174    SkASSERT(255 > alpha);
175
176    if (count > 0) {
177        int src_scale = SkAlpha255To256(alpha);
178        DITHER_565_SCAN(y);
179        do {
180            SkPMColor c = *src++;
181            SkPMColorAssert(c);
182            if (c)
183            {
184                unsigned d = *dst;
185                int sa = SkGetPackedA32(c);
186                int dst_scale = SkAlpha255To256(255 - SkAlphaMul(sa, src_scale));
187                int dither = DITHER_VALUE(x);
188
189                int sr = SkGetPackedR32(c);
190                int sg = SkGetPackedG32(c);
191                int sb = SkGetPackedB32(c);
192                sr = SkDITHER_R32To565(sr, dither);
193                sg = SkDITHER_G32To565(sg, dither);
194                sb = SkDITHER_B32To565(sb, dither);
195
196                int dr = (sr * src_scale + SkGetPackedR16(d) * dst_scale) >> 8;
197                int dg = (sg * src_scale + SkGetPackedG16(d) * dst_scale) >> 8;
198                int db = (sb * src_scale + SkGetPackedB16(d) * dst_scale) >> 8;
199
200                *dst = SkPackRGB16(dr, dg, db);
201            }
202            dst += 1;
203            DITHER_INC_X(x);
204        } while (--count != 0);
205    }
206}
207
208///////////////////////////////////////////////////////////////////////////////
209///////////////////////////////////////////////////////////////////////////////
210
211static const SkBlitRow::Proc gDefault_565_Procs[] = {
212    // no dither
213    S32_D565_Opaque,
214    S32_D565_Blend,
215
216    S32A_D565_Opaque,
217    S32A_D565_Blend,
218
219    // dither
220    S32_D565_Opaque_Dither,
221    S32_D565_Blend_Dither,
222
223    S32A_D565_Opaque_Dither,
224    S32A_D565_Blend_Dither
225};
226
227SkBlitRow::Proc SkBlitRow::Factory(unsigned flags, SkColorType ct) {
228    SkASSERT(flags < SK_ARRAY_COUNT(gDefault_565_Procs));
229    // just so we don't crash
230    flags &= kFlags16_Mask;
231
232    SkBlitRow::Proc proc = NULL;
233
234    switch (ct) {
235        case kRGB_565_SkColorType:
236            proc = PlatformProcs565(flags);
237            if (NULL == proc) {
238                proc = gDefault_565_Procs[flags];
239            }
240            break;
241        default:
242            break;
243    }
244    return proc;
245}
246