blob: 9453488a798730c60115bf41434bfaa5e6dc147f [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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 */
reed@google.com58af9a62011-10-12 13:43:52 +00007
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkBlitRow.h"
9#include "SkColorPriv.h"
10#include "SkDither.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000011#include "SkMathPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012
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);
reed@android.com8a1c16f2008-12-17 15:59:43 +000024 *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);
reed@android.com8a1c16f2008-12-17 15:59:43 +000039 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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000070
reed@android.com8a1c16f2008-12-17 15:59:43 +000071 if (count > 0) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 do {
73 SkPMColor sc = *src++;
74 SkPMColorAssert(sc);
reed@android.com8e4c93b2010-03-09 15:21:28 +000075 if (sc) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000076 uint16_t dc = *dst;
reed@android.com8e4c93b2010-03-09 15:21:28 +000077 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));
reed@android.com8a1c16f2008-12-17 15:59:43 +000082 }
83 dst += 1;
84 } while (--count != 0);
85 }
86}
87
88/////////////////////////////////////////////////////////////////////////////
rmistry@google.comfbfcd562012-08-23 18:09:54 +000089
reed@android.com8a1c16f2008-12-17 15:59:43 +000090static 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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000094
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 if (count > 0) {
96 DITHER_565_SCAN(y);
97 do {
98 SkPMColor c = *src++;
99 SkPMColorAssert(c);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100
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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000112
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113 if (count > 0) {
114 int scale = SkAlpha255To256(alpha);
115 DITHER_565_SCAN(y);
116 do {
117 SkPMColor c = *src++;
118 SkPMColorAssert(c);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000120 int dither = DITHER_VALUE(x);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121 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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000141
reed@android.com8a1c16f2008-12-17 15:59:43 +0000142 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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000149
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 int d = SkAlphaMul(DITHER_VALUE(x), SkAlpha255To256(a));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000151
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000158
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000175
reed@android.com8a1c16f2008-12-17 15:59:43 +0000176 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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000188
reed@android.com8a1c16f2008-12-17 15:59:43 +0000189 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);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000195
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 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;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000199
reed@android.com8a1c16f2008-12-17 15:59:43 +0000200 *dst = SkPackRGB16(dr, dg, db);
201 }
202 dst += 1;
203 DITHER_INC_X(x);
204 } while (--count != 0);
205 }
206}
207
208///////////////////////////////////////////////////////////////////////////////
209///////////////////////////////////////////////////////////////////////////////
210
reed@android.com7d2e3222009-07-30 02:22:31 +0000211static const SkBlitRow::Proc gDefault_565_Procs[] = {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 // no dither
213 S32_D565_Opaque,
214 S32_D565_Blend,
215
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 S32A_D565_Opaque,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 S32A_D565_Blend,
reed@android.com7d2e3222009-07-30 02:22:31 +0000218
reed@android.com8a1c16f2008-12-17 15:59:43 +0000219 // dither
220 S32_D565_Opaque_Dither,
221 S32_D565_Blend_Dither,
reed@android.com7d2e3222009-07-30 02:22:31 +0000222
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 S32A_D565_Opaque_Dither,
224 S32A_D565_Blend_Dither
225};
226
227extern SkBlitRow::Proc SkBlitRow_Factory_4444(unsigned flags);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000228
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229SkBlitRow::Proc SkBlitRow::Factory(unsigned flags, SkBitmap::Config config) {
reed@android.com7d2e3222009-07-30 02:22:31 +0000230 SkASSERT(flags < SK_ARRAY_COUNT(gDefault_565_Procs));
reed@android.comc4cae852009-09-23 15:06:10 +0000231 // just so we don't crash
232 flags &= kFlags16_Mask;
reed@android.com7d2e3222009-07-30 02:22:31 +0000233
234 SkBlitRow::Proc proc = NULL;
235
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 switch (config) {
237 case SkBitmap::kRGB_565_Config:
senorblanco@chromium.org92727612009-11-04 20:51:06 +0000238 proc = PlatformProcs565(flags);
reed@android.com7d2e3222009-07-30 02:22:31 +0000239 if (NULL == proc) {
240 proc = gDefault_565_Procs[flags];
241 }
242 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 case SkBitmap::kARGB_4444_Config:
senorblanco@chromium.org92727612009-11-04 20:51:06 +0000244 proc = PlatformProcs4444(flags);
reed@android.com7d2e3222009-07-30 02:22:31 +0000245 if (NULL == proc) {
246 proc = SkBlitRow_Factory_4444(flags);
247 }
248 break;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249 default:
250 break;
251 }
reed@android.com7d2e3222009-07-30 02:22:31 +0000252 return proc;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253}
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000254