blob: 175409ce2945a8a58301721ceccbeb4964bf1fbb [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkBlitRow.h"
11#include "SkCoreBlitters.h"
12#include "SkColorPriv.h"
13#include "SkDither.h"
14#include "SkShader.h"
reed@android.com1fc4c602009-10-02 16:34:57 +000015#include "SkTemplatesPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016#include "SkUtils.h"
17#include "SkXfermode.h"
18
reed@android.com867ee802009-10-20 13:55:41 +000019#if defined(__ARM_HAVE_NEON) && defined(SK_CPU_LENDIAN)
20 #define SK_USE_NEON
21 #include <arm_neon.h>
22#else
23 // if we don't have neon, then our black blitter is worth the extra code
24 #define USE_BLACK_BLITTER
25#endif
26
reed@android.com8a1c16f2008-12-17 15:59:43 +000027void sk_dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
28 int count) {
29 if (count > 0) {
30 // see if we need to write one short before we can cast to an 4byte ptr
31 // (we do this subtract rather than (unsigned)dst so we don't get warnings
32 // on 64bit machines)
33 if (((char*)dst - (char*)0) & 2) {
34 *dst++ = value;
35 count -= 1;
36 SkTSwap(value, other);
37 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000038
reed@android.com8a1c16f2008-12-17 15:59:43 +000039 // fast way to set [value,other] pairs
40#ifdef SK_CPU_BENDIAN
41 sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
42#else
43 sk_memset32((uint32_t*)dst, (other << 16) | value, count >> 1);
44#endif
rmistry@google.comfbfcd562012-08-23 18:09:54 +000045
reed@android.com8a1c16f2008-12-17 15:59:43 +000046 if (count & 1) {
47 dst[count - 1] = value;
48 }
49 }
50}
51
52///////////////////////////////////////////////////////////////////////////////
53
reed@android.com1fc4c602009-10-02 16:34:57 +000054class SkRGB16_Blitter : public SkRasterBlitter {
55public:
56 SkRGB16_Blitter(const SkBitmap& device, const SkPaint& paint);
57 virtual void blitH(int x, int y, int width);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000058 virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
59 const int16_t* runs);
reed@android.com1fc4c602009-10-02 16:34:57 +000060 virtual void blitV(int x, int y, int height, SkAlpha alpha);
61 virtual void blitRect(int x, int y, int width, int height);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000062 virtual void blitMask(const SkMask&,
63 const SkIRect&);
reed@android.com1fc4c602009-10-02 16:34:57 +000064 virtual const SkBitmap* justAnOpaqueColor(uint32_t*);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000065
reed@android.com1fc4c602009-10-02 16:34:57 +000066protected:
67 SkPMColor fSrcColor32;
reed@android.comea16cfa2009-10-02 19:11:02 +000068 uint32_t fExpandedRaw16;
reed@android.com1fc4c602009-10-02 16:34:57 +000069 unsigned fScale;
70 uint16_t fColor16; // already scaled by fScale
71 uint16_t fRawColor16; // unscaled
72 uint16_t fRawDither16; // unscaled
73 SkBool8 fDoDither;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000074
reed@android.com1fc4c602009-10-02 16:34:57 +000075 // illegal
76 SkRGB16_Blitter& operator=(const SkRGB16_Blitter&);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000077
reed@android.com1fc4c602009-10-02 16:34:57 +000078 typedef SkRasterBlitter INHERITED;
79};
80
81class SkRGB16_Opaque_Blitter : public SkRGB16_Blitter {
82public:
83 SkRGB16_Opaque_Blitter(const SkBitmap& device, const SkPaint& paint);
84 virtual void blitH(int x, int y, int width);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000085 virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
86 const int16_t* runs);
reed@android.comea16cfa2009-10-02 19:11:02 +000087 virtual void blitV(int x, int y, int height, SkAlpha alpha);
reed@android.com1fc4c602009-10-02 16:34:57 +000088 virtual void blitRect(int x, int y, int width, int height);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000089 virtual void blitMask(const SkMask&,
90 const SkIRect&);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000091
reed@android.com1fc4c602009-10-02 16:34:57 +000092private:
93 typedef SkRGB16_Blitter INHERITED;
94};
95
reed@android.com867ee802009-10-20 13:55:41 +000096#ifdef USE_BLACK_BLITTER
reed@android.com1fc4c602009-10-02 16:34:57 +000097class SkRGB16_Black_Blitter : public SkRGB16_Opaque_Blitter {
98public:
99 SkRGB16_Black_Blitter(const SkBitmap& device, const SkPaint& paint);
100 virtual void blitMask(const SkMask&, const SkIRect&);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000101 virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
102 const int16_t* runs);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000103
reed@android.com1fc4c602009-10-02 16:34:57 +0000104private:
105 typedef SkRGB16_Opaque_Blitter INHERITED;
106};
reed@android.com867ee802009-10-20 13:55:41 +0000107#endif
reed@android.com1fc4c602009-10-02 16:34:57 +0000108
109class SkRGB16_Shader_Blitter : public SkShaderBlitter {
110public:
111 SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint);
112 virtual ~SkRGB16_Shader_Blitter();
113 virtual void blitH(int x, int y, int width);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000114 virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
115 const int16_t* runs);
reed@android.com1fc4c602009-10-02 16:34:57 +0000116 virtual void blitRect(int x, int y, int width, int height);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000117
reed@android.com1fc4c602009-10-02 16:34:57 +0000118protected:
119 SkPMColor* fBuffer;
120 SkBlitRow::Proc fOpaqueProc;
121 SkBlitRow::Proc fAlphaProc;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000122
reed@android.com1fc4c602009-10-02 16:34:57 +0000123private:
124 // illegal
125 SkRGB16_Shader_Blitter& operator=(const SkRGB16_Shader_Blitter&);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000126
reed@android.com1fc4c602009-10-02 16:34:57 +0000127 typedef SkShaderBlitter INHERITED;
128};
129
130// used only if the shader can perform shadSpan16
131class SkRGB16_Shader16_Blitter : public SkRGB16_Shader_Blitter {
132public:
133 SkRGB16_Shader16_Blitter(const SkBitmap& device, const SkPaint& paint);
134 virtual void blitH(int x, int y, int width);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000135 virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
136 const int16_t* runs);
reed@android.com1fc4c602009-10-02 16:34:57 +0000137 virtual void blitRect(int x, int y, int width, int height);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000138
reed@android.com1fc4c602009-10-02 16:34:57 +0000139private:
140 typedef SkRGB16_Shader_Blitter INHERITED;
141};
142
143class SkRGB16_Shader_Xfermode_Blitter : public SkShaderBlitter {
144public:
145 SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint);
146 virtual ~SkRGB16_Shader_Xfermode_Blitter();
147 virtual void blitH(int x, int y, int width);
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000148 virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
149 const int16_t* runs);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000150
reed@android.com1fc4c602009-10-02 16:34:57 +0000151private:
152 SkXfermode* fXfermode;
153 SkPMColor* fBuffer;
154 uint8_t* fAAExpand;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000155
reed@android.com1fc4c602009-10-02 16:34:57 +0000156 // illegal
157 SkRGB16_Shader_Xfermode_Blitter& operator=(const SkRGB16_Shader_Xfermode_Blitter&);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000158
reed@android.com1fc4c602009-10-02 16:34:57 +0000159 typedef SkShaderBlitter INHERITED;
160};
161
162///////////////////////////////////////////////////////////////////////////////
reed@android.com867ee802009-10-20 13:55:41 +0000163#ifdef USE_BLACK_BLITTER
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164SkRGB16_Black_Blitter::SkRGB16_Black_Blitter(const SkBitmap& device, const SkPaint& paint)
reed@android.comdafaf7a2009-07-10 03:05:59 +0000165 : INHERITED(device, paint) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000166 SkASSERT(paint.getShader() == NULL);
167 SkASSERT(paint.getColorFilter() == NULL);
168 SkASSERT(paint.getXfermode() == NULL);
169 SkASSERT(paint.getColor() == SK_ColorBLACK);
170}
171
172#if 1
173#define black_8_pixels(mask, dst) \
174 do { \
175 if (mask & 0x80) dst[0] = 0; \
176 if (mask & 0x40) dst[1] = 0; \
177 if (mask & 0x20) dst[2] = 0; \
178 if (mask & 0x10) dst[3] = 0; \
179 if (mask & 0x08) dst[4] = 0; \
180 if (mask & 0x04) dst[5] = 0; \
181 if (mask & 0x02) dst[6] = 0; \
182 if (mask & 0x01) dst[7] = 0; \
183 } while (0)
184#else
185static inline black_8_pixels(U8CPU mask, uint16_t dst[])
186{
187 if (mask & 0x80) dst[0] = 0;
188 if (mask & 0x40) dst[1] = 0;
189 if (mask & 0x20) dst[2] = 0;
190 if (mask & 0x10) dst[3] = 0;
191 if (mask & 0x08) dst[4] = 0;
192 if (mask & 0x04) dst[5] = 0;
193 if (mask & 0x02) dst[6] = 0;
194 if (mask & 0x01) dst[7] = 0;
195}
196#endif
197
198#define SK_BLITBWMASK_NAME SkRGB16_Black_BlitBW
199#define SK_BLITBWMASK_ARGS
200#define SK_BLITBWMASK_BLIT8(mask, dst) black_8_pixels(mask, dst)
201#define SK_BLITBWMASK_GETADDR getAddr16
202#define SK_BLITBWMASK_DEVTYPE uint16_t
203#include "SkBlitBWMaskTemplate.h"
204
tomhudson@google.com333d6cb2011-07-12 19:19:03 +0000205void SkRGB16_Black_Blitter::blitMask(const SkMask& mask,
206 const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 if (mask.fFormat == SkMask::kBW_Format) {
208 SkRGB16_Black_BlitBW(fDevice, mask, clip);
209 } else {
210 uint16_t* SK_RESTRICT device = fDevice.getAddr16(clip.fLeft, clip.fTop);
reed@google.com79891862011-10-18 15:44:57 +0000211 const uint8_t* SK_RESTRICT alpha = mask.getAddr8(clip.fLeft, clip.fTop);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 unsigned width = clip.width();
213 unsigned height = clip.height();
214 unsigned deviceRB = fDevice.rowBytes() - (width << 1);
215 unsigned maskRB = mask.fRowBytes - width;
216
217 SkASSERT((int)height > 0);
218 SkASSERT((int)width > 0);
219 SkASSERT((int)deviceRB >= 0);
220 SkASSERT((int)maskRB >= 0);
221
222 do {
223 unsigned w = width;
224 do {
225 unsigned aa = *alpha++;
226 *device = SkAlphaMulRGB16(*device, SkAlpha255To256(255 - aa));
227 device += 1;
228 } while (--w != 0);
229 device = (uint16_t*)((char*)device + deviceRB);
230 alpha += maskRB;
231 } while (--height != 0);
232 }
233}
234
235void SkRGB16_Black_Blitter::blitAntiH(int x, int y,
236 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000237 const int16_t* SK_RESTRICT runs) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
239
240 for (;;) {
241 int count = runs[0];
242 SkASSERT(count >= 0);
243 if (count <= 0) {
244 return;
245 }
246 runs += count;
247
248 unsigned aa = antialias[0];
249 antialias += count;
250 if (aa) {
251 if (aa == 255) {
252 memset(device, 0, count << 1);
253 } else {
254 aa = SkAlpha255To256(255 - aa);
255 do {
256 *device = SkAlphaMulRGB16(*device, aa);
257 device += 1;
258 } while (--count != 0);
259 continue;
260 }
261 }
262 device += count;
263 }
264}
reed@android.com867ee802009-10-20 13:55:41 +0000265#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266
reed@android.com9a74d312009-06-15 15:56:35 +0000267///////////////////////////////////////////////////////////////////////////////
268///////////////////////////////////////////////////////////////////////////////
269
270SkRGB16_Opaque_Blitter::SkRGB16_Opaque_Blitter(const SkBitmap& device,
271 const SkPaint& paint)
272: INHERITED(device, paint) {}
273
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000274void SkRGB16_Opaque_Blitter::blitH(int x, int y, int width) {
reed@android.com9a74d312009-06-15 15:56:35 +0000275 SkASSERT(width > 0);
276 SkASSERT(x + width <= fDevice.width());
277 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
278 uint16_t srcColor = fColor16;
reed@android.com31d1c642009-06-15 18:45:19 +0000279
reed@android.com9a74d312009-06-15 15:56:35 +0000280 SkASSERT(fRawColor16 == srcColor);
281 if (fDoDither) {
282 uint16_t ditherColor = fRawDither16;
283 if ((x ^ y) & 1) {
284 SkTSwap(ditherColor, srcColor);
285 }
286 sk_dither_memset16(device, srcColor, ditherColor, width);
287 } else {
288 sk_memset16(device, srcColor, width);
289 }
290}
291
292// return 1 or 0 from a bool
reed@android.com63debae2009-12-16 17:25:43 +0000293static inline int Bool2Int(int value) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000294 return !!value;
reed@android.com9a74d312009-06-15 15:56:35 +0000295}
296
297void SkRGB16_Opaque_Blitter::blitAntiH(int x, int y,
298 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000299 const int16_t* SK_RESTRICT runs) {
reed@android.com9a74d312009-06-15 15:56:35 +0000300 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
301 uint16_t srcColor = fRawColor16;
reed@android.comea16cfa2009-10-02 19:11:02 +0000302 uint32_t srcExpanded = fExpandedRaw16;
reed@android.com9a74d312009-06-15 15:56:35 +0000303 int ditherInt = Bool2Int(fDoDither);
reed@android.com9a74d312009-06-15 15:56:35 +0000304 uint16_t ditherColor = fRawDither16;
305 // if we have no dithering, this will always fail
306 if ((x ^ y) & ditherInt) {
307 SkTSwap(ditherColor, srcColor);
308 }
309 for (;;) {
310 int count = runs[0];
311 SkASSERT(count >= 0);
312 if (count <= 0) {
313 return;
314 }
315 runs += count;
reed@android.com31d1c642009-06-15 18:45:19 +0000316
reed@android.com9a74d312009-06-15 15:56:35 +0000317 unsigned aa = antialias[0];
318 antialias += count;
319 if (aa) {
320 if (aa == 255) {
321 if (ditherInt) {
322 sk_dither_memset16(device, srcColor,
323 ditherColor, count);
324 } else {
325 sk_memset16(device, srcColor, count);
326 }
327 } else {
328 // TODO: respect fDoDither
329 unsigned scale5 = SkAlpha255To256(aa) >> 3;
reed@android.comea16cfa2009-10-02 19:11:02 +0000330 uint32_t src32 = srcExpanded * scale5;
reed@android.com9a74d312009-06-15 15:56:35 +0000331 scale5 = 32 - scale5; // now we can use it on the device
332 int n = count;
333 do {
334 uint32_t dst32 = SkExpand_rgb_16(*device) * scale5;
335 *device++ = SkCompact_rgb_16((src32 + dst32) >> 5);
336 } while (--n != 0);
337 goto DONE;
338 }
339 }
340 device += count;
reed@android.com31d1c642009-06-15 18:45:19 +0000341
reed@android.com9a74d312009-06-15 15:56:35 +0000342 DONE:
343 // if we have no dithering, this will always fail
344 if (count & ditherInt) {
345 SkTSwap(ditherColor, srcColor);
346 }
347 }
348}
349
350#define solid_8_pixels(mask, dst, color) \
351 do { \
352 if (mask & 0x80) dst[0] = color; \
353 if (mask & 0x40) dst[1] = color; \
354 if (mask & 0x20) dst[2] = color; \
355 if (mask & 0x10) dst[3] = color; \
356 if (mask & 0x08) dst[4] = color; \
357 if (mask & 0x04) dst[5] = color; \
358 if (mask & 0x02) dst[6] = color; \
359 if (mask & 0x01) dst[7] = color; \
360 } while (0)
361
362#define SK_BLITBWMASK_NAME SkRGB16_BlitBW
363#define SK_BLITBWMASK_ARGS , uint16_t color
364#define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color)
365#define SK_BLITBWMASK_GETADDR getAddr16
366#define SK_BLITBWMASK_DEVTYPE uint16_t
367#include "SkBlitBWMaskTemplate.h"
368
369static U16CPU blend_compact(uint32_t src32, uint32_t dst32, unsigned scale5) {
370 return SkCompact_rgb_16(dst32 + ((src32 - dst32) * scale5 >> 5));
371}
372
tomhudson@google.com333d6cb2011-07-12 19:19:03 +0000373void SkRGB16_Opaque_Blitter::blitMask(const SkMask& mask,
374 const SkIRect& clip) {
reed@android.com9a74d312009-06-15 15:56:35 +0000375 if (mask.fFormat == SkMask::kBW_Format) {
376 SkRGB16_BlitBW(fDevice, mask, clip, fColor16);
377 return;
378 }
reed@android.com31d1c642009-06-15 18:45:19 +0000379
reed@android.com9a74d312009-06-15 15:56:35 +0000380 uint16_t* SK_RESTRICT device = fDevice.getAddr16(clip.fLeft, clip.fTop);
reed@google.com79891862011-10-18 15:44:57 +0000381 const uint8_t* SK_RESTRICT alpha = mask.getAddr8(clip.fLeft, clip.fTop);
reed@android.com9a74d312009-06-15 15:56:35 +0000382 int width = clip.width();
383 int height = clip.height();
384 unsigned deviceRB = fDevice.rowBytes() - (width << 1);
385 unsigned maskRB = mask.fRowBytes - width;
reed@android.comea16cfa2009-10-02 19:11:02 +0000386 uint32_t expanded32 = fExpandedRaw16;
reed@android.com31d1c642009-06-15 18:45:19 +0000387
reed@android.com867ee802009-10-20 13:55:41 +0000388#ifdef SK_USE_NEON
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000389#define UNROLL 8
reed@android.com867ee802009-10-20 13:55:41 +0000390 do {
391 int w = width;
392 if (w >= UNROLL) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000393 uint32x4_t color; /* can use same one */
reed@android.com867ee802009-10-20 13:55:41 +0000394 uint32x4_t dev_lo, dev_hi;
395 uint32x4_t t1, t2;
396 uint32x4_t wn1, wn2;
397 uint16x4_t odev_lo, odev_hi;
398 uint16x4_t alpha_lo, alpha_hi;
399 uint16x8_t alpha_full;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000400
reed@android.com867ee802009-10-20 13:55:41 +0000401 color = vdupq_n_u32(expanded32);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000402
reed@android.com867ee802009-10-20 13:55:41 +0000403 do {
404 /* alpha is 8x8, widen and split to get pair of 16x4's */
405 alpha_full = vmovl_u8(vld1_u8(alpha));
406 alpha_full = vaddq_u16(alpha_full, vshrq_n_u16(alpha_full,7));
407 alpha_full = vshrq_n_u16(alpha_full, 3);
408 alpha_lo = vget_low_u16(alpha_full);
409 alpha_hi = vget_high_u16(alpha_full);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000410
reed@android.com867ee802009-10-20 13:55:41 +0000411 dev_lo = vmovl_u16(vld1_u16(device));
412 dev_hi = vmovl_u16(vld1_u16(device+4));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000413
reed@android.com867ee802009-10-20 13:55:41 +0000414 /* unpack in 32 bits */
415 dev_lo = vorrq_u32(
416 vandq_u32(dev_lo, vdupq_n_u32(0x0000F81F)),
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000417 vshlq_n_u32(vandq_u32(dev_lo,
reed@android.com867ee802009-10-20 13:55:41 +0000418 vdupq_n_u32(0x000007E0)),
419 16)
420 );
421 dev_hi = vorrq_u32(
422 vandq_u32(dev_hi, vdupq_n_u32(0x0000F81F)),
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000423 vshlq_n_u32(vandq_u32(dev_hi,
reed@android.com867ee802009-10-20 13:55:41 +0000424 vdupq_n_u32(0x000007E0)),
425 16)
426 );
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000427
reed@android.com867ee802009-10-20 13:55:41 +0000428 /* blend the two */
429 t1 = vmulq_u32(vsubq_u32(color, dev_lo), vmovl_u16(alpha_lo));
430 t1 = vshrq_n_u32(t1, 5);
431 dev_lo = vaddq_u32(dev_lo, t1);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000432
reed@android.com867ee802009-10-20 13:55:41 +0000433 t1 = vmulq_u32(vsubq_u32(color, dev_hi), vmovl_u16(alpha_hi));
434 t1 = vshrq_n_u32(t1, 5);
435 dev_hi = vaddq_u32(dev_hi, t1);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000436
reed@android.com867ee802009-10-20 13:55:41 +0000437 /* re-compact and store */
438 wn1 = vandq_u32(dev_lo, vdupq_n_u32(0x0000F81F)),
439 wn2 = vshrq_n_u32(dev_lo, 16);
440 wn2 = vandq_u32(wn2, vdupq_n_u32(0x000007E0));
441 odev_lo = vmovn_u32(vorrq_u32(wn1, wn2));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000442
reed@android.com867ee802009-10-20 13:55:41 +0000443 wn1 = vandq_u32(dev_hi, vdupq_n_u32(0x0000F81F)),
444 wn2 = vshrq_n_u32(dev_hi, 16);
445 wn2 = vandq_u32(wn2, vdupq_n_u32(0x000007E0));
446 odev_hi = vmovn_u32(vorrq_u32(wn1, wn2));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000447
reed@android.com867ee802009-10-20 13:55:41 +0000448 vst1_u16(device, odev_lo);
449 vst1_u16(device+4, odev_hi);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000450
reed@android.com867ee802009-10-20 13:55:41 +0000451 device += UNROLL;
452 alpha += UNROLL;
453 w -= UNROLL;
454 } while (w >= UNROLL);
455 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000456
reed@android.com867ee802009-10-20 13:55:41 +0000457 /* residuals (which is everything if we have no neon) */
458 while (w > 0) {
459 *device = blend_compact(expanded32, SkExpand_rgb_16(*device),
460 SkAlpha255To256(*alpha++) >> 3);
461 device += 1;
462 --w;
463 }
464 device = (uint16_t*)((char*)device + deviceRB);
465 alpha += maskRB;
466 } while (--height != 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000467#undef UNROLL
reed@android.com867ee802009-10-20 13:55:41 +0000468#else // non-neon code
reed@android.com9a74d312009-06-15 15:56:35 +0000469 do {
470 int w = width;
471 do {
reed@android.comea16cfa2009-10-02 19:11:02 +0000472 *device = blend_compact(expanded32, SkExpand_rgb_16(*device),
reed@android.com9a74d312009-06-15 15:56:35 +0000473 SkAlpha255To256(*alpha++) >> 3);
474 device += 1;
475 } while (--w != 0);
476 device = (uint16_t*)((char*)device + deviceRB);
477 alpha += maskRB;
478 } while (--height != 0);
reed@android.com867ee802009-10-20 13:55:41 +0000479#endif
reed@android.com9a74d312009-06-15 15:56:35 +0000480}
481
reed@android.comea16cfa2009-10-02 19:11:02 +0000482void SkRGB16_Opaque_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
483 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
484 unsigned deviceRB = fDevice.rowBytes();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000485
reed@android.comea16cfa2009-10-02 19:11:02 +0000486 // TODO: respect fDoDither
487 unsigned scale5 = SkAlpha255To256(alpha) >> 3;
488 uint32_t src32 = fExpandedRaw16 * scale5;
489 scale5 = 32 - scale5;
490 do {
491 uint32_t dst32 = SkExpand_rgb_16(*device) * scale5;
492 *device = SkCompact_rgb_16((src32 + dst32) >> 5);
493 device = (uint16_t*)((char*)device + deviceRB);
494 } while (--height != 0);
495}
496
reed@android.com9a74d312009-06-15 15:56:35 +0000497void SkRGB16_Opaque_Blitter::blitRect(int x, int y, int width, int height) {
498 SkASSERT(x + width <= fDevice.width() && y + height <= fDevice.height());
499 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
500 unsigned deviceRB = fDevice.rowBytes();
501 uint16_t color16 = fColor16;
reed@android.com31d1c642009-06-15 18:45:19 +0000502
reed@android.com9a74d312009-06-15 15:56:35 +0000503 if (fDoDither) {
504 uint16_t ditherColor = fRawDither16;
505 if ((x ^ y) & 1) {
506 SkTSwap(ditherColor, color16);
507 }
508 while (--height >= 0) {
509 sk_dither_memset16(device, color16, ditherColor, width);
510 SkTSwap(ditherColor, color16);
511 device = (uint16_t*)((char*)device + deviceRB);
512 }
513 } else { // no dither
514 while (--height >= 0) {
515 sk_memset16(device, color16, width);
516 device = (uint16_t*)((char*)device + deviceRB);
517 }
518 }
519}
520
521///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000522
523SkRGB16_Blitter::SkRGB16_Blitter(const SkBitmap& device, const SkPaint& paint)
524 : INHERITED(device) {
525 SkColor color = paint.getColor();
526
527 fSrcColor32 = SkPreMultiplyColor(color);
528 fScale = SkAlpha255To256(SkColorGetA(color));
529
530 int r = SkColorGetR(color);
531 int g = SkColorGetG(color);
532 int b = SkColorGetB(color);
533
534 fRawColor16 = fRawDither16 = SkPack888ToRGB16(r, g, b);
535 // if we're dithered, use fRawDither16 to hold that.
536 if ((fDoDither = paint.isDither()) != false) {
537 fRawDither16 = SkDitherPack888ToRGB16(r, g, b);
538 }
reed@android.comea16cfa2009-10-02 19:11:02 +0000539
540 fExpandedRaw16 = SkExpand_rgb_16(fRawColor16);
541
reed@android.com8a1c16f2008-12-17 15:59:43 +0000542 fColor16 = SkPackRGB16( SkAlphaMul(r, fScale) >> (8 - SK_R16_BITS),
543 SkAlphaMul(g, fScale) >> (8 - SK_G16_BITS),
544 SkAlphaMul(b, fScale) >> (8 - SK_B16_BITS));
545}
546
547const SkBitmap* SkRGB16_Blitter::justAnOpaqueColor(uint32_t* value) {
548 if (!fDoDither && 256 == fScale) {
549 *value = fRawColor16;
550 return &fDevice;
551 }
552 return NULL;
553}
554
reed@android.comdafaf7a2009-07-10 03:05:59 +0000555static uint32_t pmcolor_to_expand16(SkPMColor c) {
556 unsigned r = SkGetPackedR32(c);
557 unsigned g = SkGetPackedG32(c);
558 unsigned b = SkGetPackedB32(c);
559 return (g << 24) | (r << 13) | (b << 2);
560}
561
562static inline void blend32_16_row(SkPMColor src, uint16_t dst[], int count) {
563 SkASSERT(count > 0);
reed@android.comdafaf7a2009-07-10 03:05:59 +0000564 uint32_t src_expand = pmcolor_to_expand16(src);
reed@android.comb602b8e2009-07-10 15:58:53 +0000565 unsigned scale = SkAlpha255To256(0xFF - SkGetPackedA32(src)) >> 3;
reed@android.comdafaf7a2009-07-10 03:05:59 +0000566 do {
567 uint32_t dst_expand = SkExpand_rgb_16(*dst) * scale;
568 *dst = SkCompact_rgb_16((src_expand + dst_expand) >> 5);
569 dst += 1;
570 } while (--count != 0);
reed@android.comdafaf7a2009-07-10 03:05:59 +0000571}
572
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000573void SkRGB16_Blitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574 SkASSERT(width > 0);
575 SkASSERT(x + width <= fDevice.width());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000576 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000577
reed@android.com9a74d312009-06-15 15:56:35 +0000578 // TODO: respect fDoDither
reed@android.comdafaf7a2009-07-10 03:05:59 +0000579 blend32_16_row(fSrcColor32, device, width);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000580}
581
582void SkRGB16_Blitter::blitAntiH(int x, int y,
583 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000584 const int16_t* SK_RESTRICT runs) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000585 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
reed@android.comea16cfa2009-10-02 19:11:02 +0000586 uint32_t srcExpanded = fExpandedRaw16;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000587 unsigned scale = fScale;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588
reed@android.com9a74d312009-06-15 15:56:35 +0000589 // TODO: respect fDoDither
590 for (;;) {
591 int count = runs[0];
592 SkASSERT(count >= 0);
593 if (count <= 0) {
594 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000595 }
reed@android.com9a74d312009-06-15 15:56:35 +0000596 runs += count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000597
reed@android.com9a74d312009-06-15 15:56:35 +0000598 unsigned aa = antialias[0];
599 antialias += count;
600 if (aa) {
601 unsigned scale5 = SkAlpha255To256(aa) * scale >> (8 + 3);
reed@android.comea16cfa2009-10-02 19:11:02 +0000602 uint32_t src32 = srcExpanded * scale5;
reed@android.com9a74d312009-06-15 15:56:35 +0000603 scale5 = 32 - scale5;
604 do {
605 uint32_t dst32 = SkExpand_rgb_16(*device) * scale5;
606 *device++ = SkCompact_rgb_16((src32 + dst32) >> 5);
607 } while (--count != 0);
608 continue;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000609 }
reed@android.com9a74d312009-06-15 15:56:35 +0000610 device += count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000611 }
612}
613
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614static inline void blend_8_pixels(U8CPU bw, uint16_t dst[], unsigned dst_scale,
615 U16CPU srcColor) {
616 if (bw & 0x80) dst[0] = srcColor + SkAlphaMulRGB16(dst[0], dst_scale);
617 if (bw & 0x40) dst[1] = srcColor + SkAlphaMulRGB16(dst[1], dst_scale);
618 if (bw & 0x20) dst[2] = srcColor + SkAlphaMulRGB16(dst[2], dst_scale);
619 if (bw & 0x10) dst[3] = srcColor + SkAlphaMulRGB16(dst[3], dst_scale);
620 if (bw & 0x08) dst[4] = srcColor + SkAlphaMulRGB16(dst[4], dst_scale);
621 if (bw & 0x04) dst[5] = srcColor + SkAlphaMulRGB16(dst[5], dst_scale);
622 if (bw & 0x02) dst[6] = srcColor + SkAlphaMulRGB16(dst[6], dst_scale);
623 if (bw & 0x01) dst[7] = srcColor + SkAlphaMulRGB16(dst[7], dst_scale);
624}
625
626#define SK_BLITBWMASK_NAME SkRGB16_BlendBW
627#define SK_BLITBWMASK_ARGS , unsigned dst_scale, U16CPU src_color
628#define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, dst_scale, src_color)
629#define SK_BLITBWMASK_GETADDR getAddr16
630#define SK_BLITBWMASK_DEVTYPE uint16_t
631#include "SkBlitBWMaskTemplate.h"
632
tomhudson@google.com333d6cb2011-07-12 19:19:03 +0000633void SkRGB16_Blitter::blitMask(const SkMask& mask,
634 const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000635 if (mask.fFormat == SkMask::kBW_Format) {
reed@android.com9a74d312009-06-15 15:56:35 +0000636 SkRGB16_BlendBW(fDevice, mask, clip, 256 - fScale, fColor16);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637 return;
638 }
639
640 uint16_t* SK_RESTRICT device = fDevice.getAddr16(clip.fLeft, clip.fTop);
reed@google.com79891862011-10-18 15:44:57 +0000641 const uint8_t* SK_RESTRICT alpha = mask.getAddr8(clip.fLeft, clip.fTop);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000642 int width = clip.width();
643 int height = clip.height();
644 unsigned deviceRB = fDevice.rowBytes() - (width << 1);
645 unsigned maskRB = mask.fRowBytes - width;
reed@android.comea16cfa2009-10-02 19:11:02 +0000646 uint32_t color32 = fExpandedRaw16;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000647
reed@android.com9a74d312009-06-15 15:56:35 +0000648 unsigned scale256 = fScale;
649 do {
650 int w = width;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000651 do {
reed@android.com9a74d312009-06-15 15:56:35 +0000652 unsigned aa = *alpha++;
653 unsigned scale = SkAlpha255To256(aa) * scale256 >> (8 + 3);
654 uint32_t src32 = color32 * scale;
655 uint32_t dst32 = SkExpand_rgb_16(*device) * (32 - scale);
656 *device++ = SkCompact_rgb_16((src32 + dst32) >> 5);
657 } while (--w != 0);
658 device = (uint16_t*)((char*)device + deviceRB);
659 alpha += maskRB;
660 } while (--height != 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000661}
662
663void SkRGB16_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000665 unsigned deviceRB = fDevice.rowBytes();
666
reed@android.comea16cfa2009-10-02 19:11:02 +0000667 // TODO: respect fDoDither
668 unsigned scale5 = SkAlpha255To256(alpha) * fScale >> (8 + 3);
669 uint32_t src32 = fExpandedRaw16 * scale5;
670 scale5 = 32 - scale5;
671 do {
672 uint32_t dst32 = SkExpand_rgb_16(*device) * scale5;
673 *device = SkCompact_rgb_16((src32 + dst32) >> 5);
674 device = (uint16_t*)((char*)device + deviceRB);
675 } while (--height != 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000676}
677
678void SkRGB16_Blitter::blitRect(int x, int y, int width, int height) {
679 SkASSERT(x + width <= fDevice.width() && y + height <= fDevice.height());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000680 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
681 unsigned deviceRB = fDevice.rowBytes();
reed@android.com9a74d312009-06-15 15:56:35 +0000682 SkPMColor src32 = fSrcColor32;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000683
reed@android.com9a74d312009-06-15 15:56:35 +0000684 while (--height >= 0) {
reed@android.comdafaf7a2009-07-10 03:05:59 +0000685 blend32_16_row(src32, device, width);
reed@android.com9a74d312009-06-15 15:56:35 +0000686 device = (uint16_t*)((char*)device + deviceRB);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000687 }
688}
689
690///////////////////////////////////////////////////////////////////////////////
691
692SkRGB16_Shader16_Blitter::SkRGB16_Shader16_Blitter(const SkBitmap& device,
693 const SkPaint& paint)
694 : SkRGB16_Shader_Blitter(device, paint) {
reed@android.com5119bdb2009-06-12 21:27:03 +0000695 SkASSERT(SkShader::CanCallShadeSpan16(fShaderFlags));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696}
697
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000698void SkRGB16_Shader16_Blitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000699 SkASSERT(x + width <= fDevice.width());
700
701 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
702 SkShader* shader = fShader;
703
704 int alpha = shader->getSpan16Alpha();
705 if (0xFF == alpha) {
706 shader->shadeSpan16(x, y, device, width);
707 } else {
708 uint16_t* span16 = (uint16_t*)fBuffer;
709 shader->shadeSpan16(x, y, span16, width);
710 SkBlendRGB16(span16, device, SkAlpha255To256(alpha), width);
711 }
712}
713
reed@android.comdafaf7a2009-07-10 03:05:59 +0000714void SkRGB16_Shader16_Blitter::blitRect(int x, int y, int width, int height) {
715 SkShader* shader = fShader;
716 uint16_t* dst = fDevice.getAddr16(x, y);
717 size_t dstRB = fDevice.rowBytes();
718 int alpha = shader->getSpan16Alpha();
719
reed@android.comdafaf7a2009-07-10 03:05:59 +0000720 if (0xFF == alpha) {
reed@android.com3c9b2a42009-08-27 19:28:37 +0000721 if (fShaderFlags & SkShader::kConstInY16_Flag) {
reed@android.comdafaf7a2009-07-10 03:05:59 +0000722 // have the shader blit directly into the device the first time
723 shader->shadeSpan16(x, y, dst, width);
724 // and now just memcpy that line on the subsequent lines
725 if (--height > 0) {
726 const uint16_t* orig = dst;
727 do {
728 dst = (uint16_t*)((char*)dst + dstRB);
729 memcpy(dst, orig, width << 1);
730 } while (--height);
731 }
732 } else { // need to call shadeSpan16 for every line
733 do {
734 shader->shadeSpan16(x, y, dst, width);
735 y += 1;
736 dst = (uint16_t*)((char*)dst + dstRB);
737 } while (--height);
738 }
739 } else {
740 int scale = SkAlpha255To256(alpha);
741 uint16_t* span16 = (uint16_t*)fBuffer;
reed@android.com3c9b2a42009-08-27 19:28:37 +0000742 if (fShaderFlags & SkShader::kConstInY16_Flag) {
reed@android.comdafaf7a2009-07-10 03:05:59 +0000743 shader->shadeSpan16(x, y, span16, width);
744 do {
745 SkBlendRGB16(span16, dst, scale, width);
746 dst = (uint16_t*)((char*)dst + dstRB);
747 } while (--height);
748 } else {
749 do {
750 shader->shadeSpan16(x, y, span16, width);
751 SkBlendRGB16(span16, dst, scale, width);
752 y += 1;
753 dst = (uint16_t*)((char*)dst + dstRB);
754 } while (--height);
755 }
756 }
757}
758
reed@android.com8a1c16f2008-12-17 15:59:43 +0000759void SkRGB16_Shader16_Blitter::blitAntiH(int x, int y,
760 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000761 const int16_t* SK_RESTRICT runs) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000762 SkShader* shader = fShader;
763 SkPMColor* SK_RESTRICT span = fBuffer;
764 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
765
766 int alpha = shader->getSpan16Alpha();
767 uint16_t* span16 = (uint16_t*)span;
768
769 if (0xFF == alpha) {
770 for (;;) {
771 int count = *runs;
772 if (count <= 0) {
773 break;
774 }
775 SkASSERT(count <= fDevice.width()); // don't overrun fBuffer
776
777 int aa = *antialias;
778 if (aa == 255) {
779 // go direct to the device!
780 shader->shadeSpan16(x, y, device, count);
781 } else if (aa) {
782 shader->shadeSpan16(x, y, span16, count);
783 SkBlendRGB16(span16, device, SkAlpha255To256(aa), count);
784 }
785 device += count;
786 runs += count;
787 antialias += count;
788 x += count;
789 }
790 } else { // span alpha is < 255
791 alpha = SkAlpha255To256(alpha);
792 for (;;) {
793 int count = *runs;
794 if (count <= 0) {
795 break;
796 }
797 SkASSERT(count <= fDevice.width()); // don't overrun fBuffer
798
799 int aa = SkAlphaMul(*antialias, alpha);
800 if (aa) {
801 shader->shadeSpan16(x, y, span16, count);
802 SkBlendRGB16(span16, device, SkAlpha255To256(aa), count);
803 }
804
805 device += count;
806 runs += count;
807 antialias += count;
808 x += count;
809 }
810 }
811}
812
813///////////////////////////////////////////////////////////////////////////////
814
815SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkBitmap& device,
816 const SkPaint& paint)
817: INHERITED(device, paint) {
818 SkASSERT(paint.getXfermode() == NULL);
819
820 fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor));
821
822 // compute SkBlitRow::Procs
823 unsigned flags = 0;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000824
reed@android.com5119bdb2009-06-12 21:27:03 +0000825 uint32_t shaderFlags = fShaderFlags;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826 // shaders take care of global alpha, so we never set it in SkBlitRow
827 if (!(shaderFlags & SkShader::kOpaqueAlpha_Flag)) {
828 flags |= SkBlitRow::kSrcPixelAlpha_Flag;
829 }
830 // don't dither if the shader is really 16bit
831 if (paint.isDither() && !(shaderFlags & SkShader::kIntrinsicly16_Flag)) {
832 flags |= SkBlitRow::kDither_Flag;
833 }
834 // used when we know our global alpha is 0xFF
835 fOpaqueProc = SkBlitRow::Factory(flags, SkBitmap::kRGB_565_Config);
836 // used when we know our global alpha is < 0xFF
837 fAlphaProc = SkBlitRow::Factory(flags | SkBlitRow::kGlobalAlpha_Flag,
838 SkBitmap::kRGB_565_Config);
839}
840
841SkRGB16_Shader_Blitter::~SkRGB16_Shader_Blitter() {
842 sk_free(fBuffer);
843}
844
845void SkRGB16_Shader_Blitter::blitH(int x, int y, int width) {
846 SkASSERT(x + width <= fDevice.width());
847
848 fShader->shadeSpan(x, y, fBuffer, width);
849 // shaders take care of global alpha, so we pass 0xFF (should be ignored)
850 fOpaqueProc(fDevice.getAddr16(x, y), fBuffer, width, 0xFF, x, y);
851}
852
reed@android.com5119bdb2009-06-12 21:27:03 +0000853void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) {
854 SkShader* shader = fShader;
855 SkBlitRow::Proc proc = fOpaqueProc;
856 SkPMColor* buffer = fBuffer;
857 uint16_t* dst = fDevice.getAddr16(x, y);
858 size_t dstRB = fDevice.rowBytes();
859
reed@android.com3c9b2a42009-08-27 19:28:37 +0000860 if (fShaderFlags & SkShader::kConstInY32_Flag) {
reed@android.com5119bdb2009-06-12 21:27:03 +0000861 shader->shadeSpan(x, y, buffer, width);
862 do {
863 proc(dst, buffer, width, 0xFF, x, y);
864 y += 1;
865 dst = (uint16_t*)((char*)dst + dstRB);
866 } while (--height);
867 } else {
868 do {
869 shader->shadeSpan(x, y, buffer, width);
870 proc(dst, buffer, width, 0xFF, x, y);
871 y += 1;
872 dst = (uint16_t*)((char*)dst + dstRB);
873 } while (--height);
874 }
875}
876
reed@android.com8a1c16f2008-12-17 15:59:43 +0000877static inline int count_nonzero_span(const int16_t runs[], const SkAlpha aa[]) {
878 int count = 0;
879 for (;;) {
880 int n = *runs;
881 if (n == 0 || *aa == 0) {
882 break;
883 }
884 runs += n;
885 aa += n;
886 count += n;
887 }
888 return count;
889}
890
891void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
892 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000893 const int16_t* SK_RESTRICT runs) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000894 SkShader* shader = fShader;
895 SkPMColor* SK_RESTRICT span = fBuffer;
896 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
897
898 for (;;) {
899 int count = *runs;
900 if (count <= 0) {
901 break;
902 }
903 int aa = *antialias;
904 if (0 == aa) {
905 device += count;
906 runs += count;
907 antialias += count;
908 x += count;
909 continue;
910 }
911
912 int nonZeroCount = count + count_nonzero_span(runs + count, antialias + count);
913
914 SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer
915 shader->shadeSpan(x, y, span, nonZeroCount);
916
917 SkPMColor* localSpan = span;
918 for (;;) {
919 SkBlitRow::Proc proc = (aa == 0xFF) ? fOpaqueProc : fAlphaProc;
920 proc(device, localSpan, count, aa, x, y);
921
922 x += count;
923 device += count;
924 runs += count;
925 antialias += count;
926 nonZeroCount -= count;
927 if (nonZeroCount == 0) {
928 break;
929 }
930 localSpan += count;
931 SkASSERT(nonZeroCount > 0);
932 count = *runs;
933 SkASSERT(count > 0);
934 aa = *antialias;
935 }
936 }
937}
938
939///////////////////////////////////////////////////////////////////////
940
941SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter(
942 const SkBitmap& device, const SkPaint& paint)
943: INHERITED(device, paint) {
944 fXfermode = paint.getXfermode();
945 SkASSERT(fXfermode);
946 fXfermode->ref();
947
948 int width = device.width();
949 fBuffer = (SkPMColor*)sk_malloc_throw((width + (SkAlign4(width) >> 2)) * sizeof(SkPMColor));
950 fAAExpand = (uint8_t*)(fBuffer + width);
951}
952
953SkRGB16_Shader_Xfermode_Blitter::~SkRGB16_Shader_Xfermode_Blitter() {
954 fXfermode->unref();
955 sk_free(fBuffer);
956}
957
958void SkRGB16_Shader_Xfermode_Blitter::blitH(int x, int y, int width) {
959 SkASSERT(x + width <= fDevice.width());
960
961 uint16_t* device = fDevice.getAddr16(x, y);
962 SkPMColor* span = fBuffer;
963
964 fShader->shadeSpan(x, y, span, width);
965 fXfermode->xfer16(device, span, width, NULL);
966}
967
968void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
969 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000970 const int16_t* SK_RESTRICT runs) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000971 SkShader* shader = fShader;
972 SkXfermode* mode = fXfermode;
973 SkPMColor* SK_RESTRICT span = fBuffer;
974 uint8_t* SK_RESTRICT aaExpand = fAAExpand;
975 uint16_t* SK_RESTRICT device = fDevice.getAddr16(x, y);
976
977 for (;;) {
978 int count = *runs;
979 if (count <= 0) {
980 break;
981 }
982 int aa = *antialias;
983 if (0 == aa) {
984 device += count;
985 runs += count;
986 antialias += count;
987 x += count;
988 continue;
989 }
990
991 int nonZeroCount = count + count_nonzero_span(runs + count,
992 antialias + count);
993
994 SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer
995 shader->shadeSpan(x, y, span, nonZeroCount);
996
997 x += nonZeroCount;
998 SkPMColor* localSpan = span;
999 for (;;) {
1000 if (aa == 0xFF) {
1001 mode->xfer16(device, localSpan, count, NULL);
1002 } else {
1003 SkASSERT(aa);
1004 memset(aaExpand, aa, count);
1005 mode->xfer16(device, localSpan, count, aaExpand);
1006 }
1007 device += count;
1008 runs += count;
1009 antialias += count;
1010 nonZeroCount -= count;
1011 if (nonZeroCount == 0) {
1012 break;
1013 }
1014 localSpan += count;
1015 SkASSERT(nonZeroCount > 0);
1016 count = *runs;
1017 SkASSERT(count > 0);
1018 aa = *antialias;
1019 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001020 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001021}
1022
reed@android.com1fc4c602009-10-02 16:34:57 +00001023///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +00001024
reed@android.com1fc4c602009-10-02 16:34:57 +00001025SkBlitter* SkBlitter_ChooseD565(const SkBitmap& device, const SkPaint& paint,
1026 void* storage, size_t storageSize) {
1027 SkBlitter* blitter;
1028 SkShader* shader = paint.getShader();
1029 SkXfermode* mode = paint.getXfermode();
1030
1031 // we require a shader if there is an xfermode, handled by our caller
1032 SkASSERT(NULL == mode || NULL != shader);
1033
1034 if (shader) {
1035 if (mode) {
1036 SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Xfermode_Blitter,
1037 storage, storageSize, (device, paint));
1038 } else if (shader->canCallShadeSpan16()) {
1039 SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader16_Blitter,
1040 storage, storageSize, (device, paint));
1041 } else {
1042 SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Shader_Blitter,
1043 storage, storageSize, (device, paint));
1044 }
1045 } else {
1046 // no shader, no xfermode, (and we always ignore colorfilter)
1047 SkColor color = paint.getColor();
1048 if (0 == SkColorGetA(color)) {
1049 SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
reed@android.com867ee802009-10-20 13:55:41 +00001050#ifdef USE_BLACK_BLITTER
reed@android.com1fc4c602009-10-02 16:34:57 +00001051 } else if (SK_ColorBLACK == color) {
1052 SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Black_Blitter, storage,
1053 storageSize, (device, paint));
reed@android.com867ee802009-10-20 13:55:41 +00001054#endif
reed@android.com1fc4c602009-10-02 16:34:57 +00001055 } else if (0xFF == SkColorGetA(color)) {
1056 SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Opaque_Blitter, storage,
1057 storageSize, (device, paint));
1058 } else {
1059 SK_PLACEMENT_NEW_ARGS(blitter, SkRGB16_Blitter, storage,
1060 storageSize, (device, paint));
1061 }
1062 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001063
reed@android.com1fc4c602009-10-02 16:34:57 +00001064 return blitter;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001065}