SkBlitRow_D16.cpp revision e6b1a60758aa16c0456ff8e1cf717c369e4e84b0
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        uint32_t dst_expand = SkExpand_rgb_16(*dst) * scale;
220        *dst = SkCompact_rgb_16((src_expand + dst_expand) >> 5);
221        dst += 1;
222    } while (--count != 0);
223}
224
225///////////////////////////////////////////////////////////////////////////////
226///////////////////////////////////////////////////////////////////////////////
227
228static const SkBlitRow::Proc16 gDefault_565_Procs[] = {
229    // no dither
230    S32_D565_Opaque,
231    S32_D565_Blend,
232
233    S32A_D565_Opaque,
234    S32A_D565_Blend,
235
236    // dither
237    S32_D565_Opaque_Dither,
238    S32_D565_Blend_Dither,
239
240    S32A_D565_Opaque_Dither,
241    S32A_D565_Blend_Dither
242};
243
244SkBlitRow::Proc16 SkBlitRow::Factory16(unsigned flags) {
245    SkASSERT(flags < SK_ARRAY_COUNT(gDefault_565_Procs));
246    // just so we don't crash
247    flags &= kFlags16_Mask;
248
249    SkBlitRow::Proc16 proc = PlatformFactory565(flags);
250    if (NULL == proc) {
251        proc = gDefault_565_Procs[flags];
252    }
253    return proc;
254}
255
256static const SkBlitRow::ColorProc16 gDefault_565_ColorProcs[] = {
257#if 0
258    Color32A_D565,
259    Color32A_D565_Dither
260#else
261    // TODO: stop cheating and fill dither from the above specializations!
262    Color32A_D565,
263    Color32A_D565,
264#endif
265};
266
267SkBlitRow::ColorProc16 SkBlitRow::ColorFactory16(unsigned flags) {
268    SkASSERT((flags & ~kFlags16_Mask) == 0);
269    // just so we don't crash
270    flags &= kFlags16_Mask;
271    // we ignore both kGlobalAlpha_Flag and kSrcPixelAlpha_Flag, so shift down
272    // since this factory is only used for transparent source alphas
273    flags >>= 2;
274
275    SkASSERT(flags < SK_ARRAY_COUNT(gDefault_565_ColorProcs));
276
277    SkBlitRow::ColorProc16 proc = PlatformColorFactory565(flags);
278    if (NULL == proc) {
279        proc = gDefault_565_ColorProcs[flags];
280    }
281    return proc;
282}
283