1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SkDither_DEFINED
18#define SkDither_DEFINED
19
20#include "SkColorPriv.h"
21
22#define SK_DitherValueMax4444   15
23#define SK_DitherValueMax565    7
24
25/*  need to use macros for bit-counts for each component, and then
26    move these into SkColorPriv.h
27*/
28
29#define SkDITHER_R32_FOR_565_MACRO(r, d)    (r + d - (r >> 5))
30#define SkDITHER_G32_FOR_565_MACRO(g, d)    (g + (d >> 1) - (g >> 6))
31#define SkDITHER_B32_FOR_565_MACRO(b, d)    (b + d - (b >> 5))
32
33#define SkDITHER_A32_FOR_4444_MACRO(a, d)    (a + 15 - (a >> 4))
34#define SkDITHER_R32_FOR_4444_MACRO(r, d)    (r + d - (r >> 4))
35#define SkDITHER_G32_FOR_4444_MACRO(g, d)    (g + d - (g >> 4))
36#define SkDITHER_B32_FOR_4444_MACRO(b, d)    (b + d - (b >> 4))
37
38#ifdef SK_DEBUG
39    inline unsigned SkDITHER_R32_FOR_565(unsigned r, unsigned d)
40    {
41        SkASSERT(d <= SK_DitherValueMax565);
42        SkA32Assert(r);
43        r = SkDITHER_R32_FOR_565_MACRO(r, d);
44        SkA32Assert(r);
45        return r;
46    }
47    inline unsigned SkDITHER_G32_FOR_565(unsigned g, unsigned d)
48    {
49        SkASSERT(d <= SK_DitherValueMax565);
50        SkG32Assert(g);
51        g = SkDITHER_G32_FOR_565_MACRO(g, d);
52        SkG32Assert(g);
53        return g;
54    }
55    inline unsigned SkDITHER_B32_FOR_565(unsigned b, unsigned d)
56    {
57        SkASSERT(d <= SK_DitherValueMax565);
58        SkB32Assert(b);
59        b = SkDITHER_B32_FOR_565_MACRO(b, d);
60        SkB32Assert(b);
61        return b;
62    }
63#else
64    #define SkDITHER_R32_FOR_565(r, d)  SkDITHER_R32_FOR_565_MACRO(r, d)
65    #define SkDITHER_G32_FOR_565(g, d)  SkDITHER_G32_FOR_565_MACRO(g, d)
66    #define SkDITHER_B32_FOR_565(b, d)  SkDITHER_B32_FOR_565_MACRO(b, d)
67#endif
68
69#define SkDITHER_R32To565(r, d)  SkR32ToR16(SkDITHER_R32_FOR_565(r, d))
70#define SkDITHER_G32To565(g, d)  SkG32ToG16(SkDITHER_G32_FOR_565(g, d))
71#define SkDITHER_B32To565(b, d)  SkB32ToB16(SkDITHER_B32_FOR_565(b, d))
72
73#define SkDITHER_A32To4444(a, d)  SkA32To4444(SkDITHER_A32_FOR_4444_MACRO(a, d))
74#define SkDITHER_R32To4444(r, d)  SkR32To4444(SkDITHER_R32_FOR_4444_MACRO(r, d))
75#define SkDITHER_G32To4444(g, d)  SkG32To4444(SkDITHER_G32_FOR_4444_MACRO(g, d))
76#define SkDITHER_B32To4444(b, d)  SkB32To4444(SkDITHER_B32_FOR_4444_MACRO(b, d))
77
78static inline SkPMColor SkDitherARGB32For565(SkPMColor c, unsigned dither)
79{
80    SkASSERT(dither <= SK_DitherValueMax565);
81
82    unsigned sa = SkGetPackedA32(c);
83    dither = SkAlphaMul(dither, SkAlpha255To256(sa));
84
85    unsigned sr = SkGetPackedR32(c);
86    unsigned sg = SkGetPackedG32(c);
87    unsigned sb = SkGetPackedB32(c);
88    sr = SkDITHER_R32_FOR_565(sr, dither);
89    sg = SkDITHER_G32_FOR_565(sg, dither);
90    sb = SkDITHER_B32_FOR_565(sb, dither);
91
92    return SkPackARGB32(sa, sr, sg, sb);
93}
94
95static inline SkPMColor SkDitherRGB32For565(SkPMColor c, unsigned dither)
96{
97    SkASSERT(dither <= SK_DitherValueMax565);
98
99    unsigned sr = SkGetPackedR32(c);
100    unsigned sg = SkGetPackedG32(c);
101    unsigned sb = SkGetPackedB32(c);
102    sr = SkDITHER_R32_FOR_565(sr, dither);
103    sg = SkDITHER_G32_FOR_565(sg, dither);
104    sb = SkDITHER_B32_FOR_565(sb, dither);
105
106    return SkPackARGB32(0xFF, sr, sg, sb);
107}
108
109static inline uint16_t SkDitherRGBTo565(U8CPU r, U8CPU g, U8CPU b,
110                                              unsigned dither)
111{
112    SkASSERT(dither <= SK_DitherValueMax565);
113    r = SkDITHER_R32To565(r, dither);
114    g = SkDITHER_G32To565(g, dither);
115    b = SkDITHER_B32To565(b, dither);
116    return SkPackRGB16(r, g, b);
117}
118
119static inline uint16_t SkDitherRGB32To565(SkPMColor c, unsigned dither)
120{
121    SkASSERT(dither <= SK_DitherValueMax565);
122
123    unsigned sr = SkGetPackedR32(c);
124    unsigned sg = SkGetPackedG32(c);
125    unsigned sb = SkGetPackedB32(c);
126    sr = SkDITHER_R32To565(sr, dither);
127    sg = SkDITHER_G32To565(sg, dither);
128    sb = SkDITHER_B32To565(sb, dither);
129
130    return SkPackRGB16(sr, sg, sb);
131}
132
133static inline uint16_t SkDitherARGB32To565(U8CPU sa, SkPMColor c, unsigned dither)
134{
135    SkASSERT(dither <= SK_DitherValueMax565);
136    dither = SkAlphaMul(dither, SkAlpha255To256(sa));
137
138    unsigned sr = SkGetPackedR32(c);
139    unsigned sg = SkGetPackedG32(c);
140    unsigned sb = SkGetPackedB32(c);
141    sr = SkDITHER_R32To565(sr, dither);
142    sg = SkDITHER_G32To565(sg, dither);
143    sb = SkDITHER_B32To565(sb, dither);
144
145    return SkPackRGB16(sr, sg, sb);
146}
147
148///////////////////////// 4444
149
150static inline SkPMColor16 SkDitherARGB32To4444(U8CPU a, U8CPU r, U8CPU g,
151                                               U8CPU b, unsigned dither)
152{
153    dither = SkAlphaMul(dither, SkAlpha255To256(a));
154
155    a = SkDITHER_A32To4444(a, dither);
156    r = SkDITHER_R32To4444(r, dither);
157    g = SkDITHER_G32To4444(g, dither);
158    b = SkDITHER_B32To4444(b, dither);
159
160    return SkPackARGB4444(a, r, g, b);
161}
162
163static inline SkPMColor16 SkDitherARGB32To4444(SkPMColor c, unsigned dither)
164{
165    unsigned a = SkGetPackedA32(c);
166    unsigned r = SkGetPackedR32(c);
167    unsigned g = SkGetPackedG32(c);
168    unsigned b = SkGetPackedB32(c);
169
170    dither = SkAlphaMul(dither, SkAlpha255To256(a));
171
172    a = SkDITHER_A32To4444(a, dither);
173    r = SkDITHER_R32To4444(r, dither);
174    g = SkDITHER_G32To4444(g, dither);
175    b = SkDITHER_B32To4444(b, dither);
176
177    return SkPackARGB4444(a, r, g, b);
178}
179
180// TODO: need dither routines for 565 -> 4444
181
182// this toggles between a 4x4 and a 1x4 array
183//#define ENABLE_DITHER_MATRIX_4X4
184
185#ifdef ENABLE_DITHER_MATRIX_4X4
186    extern const uint8_t gDitherMatrix_4Bit_4X4[4][4];
187    extern const uint8_t gDitherMatrix_3Bit_4X4[4][4];
188
189    #define DITHER_4444_SCAN(y) const uint8_t* dither_scan = gDitherMatrix_4Bit_4X4[(y) & 3]
190    #define DITHER_565_SCAN(y)  const uint8_t* dither_scan = gDitherMatrix_3Bit_4X4[(y) & 3]
191
192    #define DITHER_VALUE(x) dither_scan[(x) & 3]
193#else
194    extern const uint16_t gDitherMatrix_4Bit_16[4];
195    extern const uint16_t gDitherMatrix_3Bit_16[4];
196
197    #define DITHER_4444_SCAN(y) const uint16_t dither_scan = gDitherMatrix_4Bit_16[(y) & 3]
198    #define DITHER_565_SCAN(y)  const uint16_t dither_scan = gDitherMatrix_3Bit_16[(y) & 3]
199
200    #define DITHER_VALUE(x) ((dither_scan >> (((x) & 3) << 2)) & 0xF)
201#endif
202
203#define DITHER_INC_X(x) ++(x)
204
205#endif
206