blob: e91e23fd69a29f698774dd19b871eec9bb41e566 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
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
Herb Derby83e939b2017-02-07 14:25:11 -05008#include "SkArenaAlloc.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkBlitRow.h"
10#include "SkCoreBlitters.h"
11#include "SkColorPriv.h"
12#include "SkDither.h"
13#include "SkShader.h"
14#include "SkUtils.h"
djsollen@google.come552dc82014-03-21 13:13:22 +000015#include "SkUtilsArm.h"
Mike Reedd4706732016-11-15 16:44:34 -050016#include "SkXfermodePriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
mtklein809ccf32016-05-05 10:58:39 -070018#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN)
reed@android.com867ee802009-10-20 13:55:41 +000019 #include <arm_neon.h>
yang.zhangdc77b352015-07-15 07:07:30 -070020extern void SkRGB16BlitterBlitV_neon(uint16_t* device,
21 int height,
22 size_t deviceRB,
23 unsigned scale,
24 uint32_t src32);
reed@android.com867ee802009-10-20 13:55:41 +000025#else
26 // if we don't have neon, then our black blitter is worth the extra code
27 #define USE_BLACK_BLITTER
28#endif
29
reed@android.com8a1c16f2008-12-17 15:59:43 +000030void sk_dither_memset16(uint16_t dst[], uint16_t value, uint16_t other,
31 int count) {
32 if (count > 0) {
33 // see if we need to write one short before we can cast to an 4byte ptr
34 // (we do this subtract rather than (unsigned)dst so we don't get warnings
35 // on 64bit machines)
36 if (((char*)dst - (char*)0) & 2) {
37 *dst++ = value;
38 count -= 1;
39 SkTSwap(value, other);
40 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000041
reed@android.com8a1c16f2008-12-17 15:59:43 +000042 // fast way to set [value,other] pairs
43#ifdef SK_CPU_BENDIAN
44 sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1);
45#else
46 sk_memset32((uint32_t*)dst, (other << 16) | value, count >> 1);
47#endif
rmistry@google.comfbfcd562012-08-23 18:09:54 +000048
reed@android.com8a1c16f2008-12-17 15:59:43 +000049 if (count & 1) {
50 dst[count - 1] = value;
51 }
52 }
53}
54
55///////////////////////////////////////////////////////////////////////////////
56
reed@android.com1fc4c602009-10-02 16:34:57 +000057class SkRGB16_Blitter : public SkRasterBlitter {
58public:
reed41e010c2015-06-09 12:16:53 -070059 SkRGB16_Blitter(const SkPixmap& device, const SkPaint& paint);
mtklein36352bf2015-03-25 18:17:31 -070060 void blitH(int x, int y, int width) override;
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000061 virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
mtklein36352bf2015-03-25 18:17:31 -070062 const int16_t* runs) override;
63 void blitV(int x, int y, int height, SkAlpha alpha) override;
64 void blitRect(int x, int y, int width, int height) override;
reed41e010c2015-06-09 12:16:53 -070065 void blitMask(const SkMask&, const SkIRect&) override;
66 const SkPixmap* justAnOpaqueColor(uint32_t*) override;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000067
reed@android.com1fc4c602009-10-02 16:34:57 +000068protected:
69 SkPMColor fSrcColor32;
reed@android.comea16cfa2009-10-02 19:11:02 +000070 uint32_t fExpandedRaw16;
reed@android.com1fc4c602009-10-02 16:34:57 +000071 unsigned fScale;
72 uint16_t fColor16; // already scaled by fScale
73 uint16_t fRawColor16; // unscaled
74 uint16_t fRawDither16; // unscaled
75 SkBool8 fDoDither;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000076
mlee402448d2015-01-29 06:22:41 -080077 SkBlitRow::ColorProc16 fColorProc16;
78
reed@android.com1fc4c602009-10-02 16:34:57 +000079 // illegal
80 SkRGB16_Blitter& operator=(const SkRGB16_Blitter&);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000081
reed@android.com1fc4c602009-10-02 16:34:57 +000082 typedef SkRasterBlitter INHERITED;
83};
84
85class SkRGB16_Opaque_Blitter : public SkRGB16_Blitter {
86public:
reed41e010c2015-06-09 12:16:53 -070087 SkRGB16_Opaque_Blitter(const SkPixmap& device, const SkPaint& paint);
mtklein36352bf2015-03-25 18:17:31 -070088 void blitH(int x, int y, int width) override;
reed41e010c2015-06-09 12:16:53 -070089 void blitAntiH(int x, int y, const SkAlpha* antialias, const int16_t* runs) override;
mtklein36352bf2015-03-25 18:17:31 -070090 void blitV(int x, int y, int height, SkAlpha alpha) override;
91 void blitRect(int x, int y, int width, int height) override;
reed41e010c2015-06-09 12:16:53 -070092 void blitMask(const SkMask&, const SkIRect&) override;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000093
reed@android.com1fc4c602009-10-02 16:34:57 +000094private:
95 typedef SkRGB16_Blitter INHERITED;
96};
97
reed@android.com867ee802009-10-20 13:55:41 +000098#ifdef USE_BLACK_BLITTER
reed@android.com1fc4c602009-10-02 16:34:57 +000099class SkRGB16_Black_Blitter : public SkRGB16_Opaque_Blitter {
100public:
reed41e010c2015-06-09 12:16:53 -0700101 SkRGB16_Black_Blitter(const SkPixmap& device, const SkPaint& paint);
mtklein36352bf2015-03-25 18:17:31 -0700102 void blitMask(const SkMask&, const SkIRect&) override;
reed41e010c2015-06-09 12:16:53 -0700103 void blitAntiH(int x, int y, const SkAlpha* antialias, const int16_t* runs) override;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000104
reed@android.com1fc4c602009-10-02 16:34:57 +0000105private:
106 typedef SkRGB16_Opaque_Blitter INHERITED;
107};
reed@android.com867ee802009-10-20 13:55:41 +0000108#endif
reed@android.com1fc4c602009-10-02 16:34:57 +0000109
110class SkRGB16_Shader_Blitter : public SkShaderBlitter {
111public:
reed41e010c2015-06-09 12:16:53 -0700112 SkRGB16_Shader_Blitter(const SkPixmap& device, const SkPaint& paint,
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000113 SkShader::Context* shaderContext);
reed@android.com1fc4c602009-10-02 16:34:57 +0000114 virtual ~SkRGB16_Shader_Blitter();
mtklein36352bf2015-03-25 18:17:31 -0700115 void blitH(int x, int y, int width) override;
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000116 virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
mtklein36352bf2015-03-25 18:17:31 -0700117 const int16_t* runs) override;
118 void blitRect(int x, int y, int width, int height) override;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000119
reed@android.com1fc4c602009-10-02 16:34:57 +0000120protected:
reeda7f11912015-01-13 13:51:00 -0800121 SkPMColor* fBuffer;
122 SkBlitRow::Proc16 fOpaqueProc;
123 SkBlitRow::Proc16 fAlphaProc;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000124
reed@android.com1fc4c602009-10-02 16:34:57 +0000125private:
126 // illegal
127 SkRGB16_Shader_Blitter& operator=(const SkRGB16_Shader_Blitter&);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000128
reed@android.com1fc4c602009-10-02 16:34:57 +0000129 typedef SkShaderBlitter INHERITED;
130};
131
reed@android.com1fc4c602009-10-02 16:34:57 +0000132class SkRGB16_Shader_Xfermode_Blitter : public SkShaderBlitter {
133public:
reed41e010c2015-06-09 12:16:53 -0700134 SkRGB16_Shader_Xfermode_Blitter(const SkPixmap& device, const SkPaint& paint,
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000135 SkShader::Context* shaderContext);
reed@android.com1fc4c602009-10-02 16:34:57 +0000136 virtual ~SkRGB16_Shader_Xfermode_Blitter();
mtklein36352bf2015-03-25 18:17:31 -0700137 void blitH(int x, int y, int width) override;
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000138 virtual void blitAntiH(int x, int y, const SkAlpha* antialias,
mtklein36352bf2015-03-25 18:17:31 -0700139 const int16_t* runs) override;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000140
reed@android.com1fc4c602009-10-02 16:34:57 +0000141private:
142 SkXfermode* fXfermode;
143 SkPMColor* fBuffer;
144 uint8_t* fAAExpand;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000145
reed@android.com1fc4c602009-10-02 16:34:57 +0000146 // illegal
147 SkRGB16_Shader_Xfermode_Blitter& operator=(const SkRGB16_Shader_Xfermode_Blitter&);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000148
reed@android.com1fc4c602009-10-02 16:34:57 +0000149 typedef SkShaderBlitter INHERITED;
150};
151
152///////////////////////////////////////////////////////////////////////////////
reed@android.com867ee802009-10-20 13:55:41 +0000153#ifdef USE_BLACK_BLITTER
reed41e010c2015-06-09 12:16:53 -0700154SkRGB16_Black_Blitter::SkRGB16_Black_Blitter(const SkPixmap& device, const SkPaint& paint)
reed@android.comdafaf7a2009-07-10 03:05:59 +0000155 : INHERITED(device, paint) {
halcanary96fcdcc2015-08-27 07:41:13 -0700156 SkASSERT(paint.getShader() == nullptr);
157 SkASSERT(paint.getColorFilter() == nullptr);
reed374772b2016-10-05 17:33:02 -0700158 SkASSERT(paint.isSrcOver());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 SkASSERT(paint.getColor() == SK_ColorBLACK);
160}
161
162#if 1
163#define black_8_pixels(mask, dst) \
164 do { \
165 if (mask & 0x80) dst[0] = 0; \
166 if (mask & 0x40) dst[1] = 0; \
167 if (mask & 0x20) dst[2] = 0; \
168 if (mask & 0x10) dst[3] = 0; \
169 if (mask & 0x08) dst[4] = 0; \
170 if (mask & 0x04) dst[5] = 0; \
171 if (mask & 0x02) dst[6] = 0; \
172 if (mask & 0x01) dst[7] = 0; \
173 } while (0)
174#else
175static inline black_8_pixels(U8CPU mask, uint16_t dst[])
176{
177 if (mask & 0x80) dst[0] = 0;
178 if (mask & 0x40) dst[1] = 0;
179 if (mask & 0x20) dst[2] = 0;
180 if (mask & 0x10) dst[3] = 0;
181 if (mask & 0x08) dst[4] = 0;
182 if (mask & 0x04) dst[5] = 0;
183 if (mask & 0x02) dst[6] = 0;
184 if (mask & 0x01) dst[7] = 0;
185}
186#endif
187
188#define SK_BLITBWMASK_NAME SkRGB16_Black_BlitBW
189#define SK_BLITBWMASK_ARGS
190#define SK_BLITBWMASK_BLIT8(mask, dst) black_8_pixels(mask, dst)
reed41e010c2015-06-09 12:16:53 -0700191#define SK_BLITBWMASK_GETADDR writable_addr16
reed@android.com8a1c16f2008-12-17 15:59:43 +0000192#define SK_BLITBWMASK_DEVTYPE uint16_t
193#include "SkBlitBWMaskTemplate.h"
194
tomhudson@google.com333d6cb2011-07-12 19:19:03 +0000195void SkRGB16_Black_Blitter::blitMask(const SkMask& mask,
196 const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 if (mask.fFormat == SkMask::kBW_Format) {
198 SkRGB16_Black_BlitBW(fDevice, mask, clip);
199 } else {
reed41e010c2015-06-09 12:16:53 -0700200 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(clip.fLeft, clip.fTop);
reed@google.com79891862011-10-18 15:44:57 +0000201 const uint8_t* SK_RESTRICT alpha = mask.getAddr8(clip.fLeft, clip.fTop);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000202 unsigned width = clip.width();
203 unsigned height = clip.height();
scroggo@google.come5f48242013-02-25 21:47:41 +0000204 size_t deviceRB = fDevice.rowBytes() - (width << 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 unsigned maskRB = mask.fRowBytes - width;
206
207 SkASSERT((int)height > 0);
208 SkASSERT((int)width > 0);
209 SkASSERT((int)deviceRB >= 0);
210 SkASSERT((int)maskRB >= 0);
211
212 do {
213 unsigned w = width;
214 do {
215 unsigned aa = *alpha++;
216 *device = SkAlphaMulRGB16(*device, SkAlpha255To256(255 - aa));
217 device += 1;
218 } while (--w != 0);
219 device = (uint16_t*)((char*)device + deviceRB);
220 alpha += maskRB;
221 } while (--height != 0);
222 }
223}
224
225void SkRGB16_Black_Blitter::blitAntiH(int x, int y,
226 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000227 const int16_t* SK_RESTRICT runs) {
reed41e010c2015-06-09 12:16:53 -0700228 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229
230 for (;;) {
231 int count = runs[0];
232 SkASSERT(count >= 0);
233 if (count <= 0) {
234 return;
235 }
236 runs += count;
237
238 unsigned aa = antialias[0];
239 antialias += count;
240 if (aa) {
241 if (aa == 255) {
242 memset(device, 0, count << 1);
243 } else {
244 aa = SkAlpha255To256(255 - aa);
245 do {
246 *device = SkAlphaMulRGB16(*device, aa);
247 device += 1;
248 } while (--count != 0);
249 continue;
250 }
251 }
252 device += count;
253 }
254}
reed@android.com867ee802009-10-20 13:55:41 +0000255#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256
reed@android.com9a74d312009-06-15 15:56:35 +0000257///////////////////////////////////////////////////////////////////////////////
258///////////////////////////////////////////////////////////////////////////////
259
reed41e010c2015-06-09 12:16:53 -0700260SkRGB16_Opaque_Blitter::SkRGB16_Opaque_Blitter(const SkPixmap& device, const SkPaint& paint)
261 : INHERITED(device, paint) {}
reed@android.com9a74d312009-06-15 15:56:35 +0000262
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000263void SkRGB16_Opaque_Blitter::blitH(int x, int y, int width) {
reed@android.com9a74d312009-06-15 15:56:35 +0000264 SkASSERT(width > 0);
265 SkASSERT(x + width <= fDevice.width());
reed41e010c2015-06-09 12:16:53 -0700266 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
reed@android.com9a74d312009-06-15 15:56:35 +0000267 uint16_t srcColor = fColor16;
reed@android.com31d1c642009-06-15 18:45:19 +0000268
reed@android.com9a74d312009-06-15 15:56:35 +0000269 SkASSERT(fRawColor16 == srcColor);
270 if (fDoDither) {
271 uint16_t ditherColor = fRawDither16;
272 if ((x ^ y) & 1) {
273 SkTSwap(ditherColor, srcColor);
274 }
275 sk_dither_memset16(device, srcColor, ditherColor, width);
276 } else {
277 sk_memset16(device, srcColor, width);
278 }
279}
280
281// return 1 or 0 from a bool
reed@android.com63debae2009-12-16 17:25:43 +0000282static inline int Bool2Int(int value) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000283 return !!value;
reed@android.com9a74d312009-06-15 15:56:35 +0000284}
285
286void SkRGB16_Opaque_Blitter::blitAntiH(int x, int y,
287 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000288 const int16_t* SK_RESTRICT runs) {
reed41e010c2015-06-09 12:16:53 -0700289 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
reed@android.com9a74d312009-06-15 15:56:35 +0000290 uint16_t srcColor = fRawColor16;
reed@android.comea16cfa2009-10-02 19:11:02 +0000291 uint32_t srcExpanded = fExpandedRaw16;
reed@android.com9a74d312009-06-15 15:56:35 +0000292 int ditherInt = Bool2Int(fDoDither);
reed@android.com9a74d312009-06-15 15:56:35 +0000293 uint16_t ditherColor = fRawDither16;
294 // if we have no dithering, this will always fail
295 if ((x ^ y) & ditherInt) {
296 SkTSwap(ditherColor, srcColor);
297 }
298 for (;;) {
299 int count = runs[0];
300 SkASSERT(count >= 0);
301 if (count <= 0) {
302 return;
303 }
304 runs += count;
reed@android.com31d1c642009-06-15 18:45:19 +0000305
reed@android.com9a74d312009-06-15 15:56:35 +0000306 unsigned aa = antialias[0];
307 antialias += count;
308 if (aa) {
309 if (aa == 255) {
310 if (ditherInt) {
311 sk_dither_memset16(device, srcColor,
312 ditherColor, count);
313 } else {
314 sk_memset16(device, srcColor, count);
315 }
316 } else {
317 // TODO: respect fDoDither
318 unsigned scale5 = SkAlpha255To256(aa) >> 3;
reed@android.comea16cfa2009-10-02 19:11:02 +0000319 uint32_t src32 = srcExpanded * scale5;
reed@android.com9a74d312009-06-15 15:56:35 +0000320 scale5 = 32 - scale5; // now we can use it on the device
321 int n = count;
322 do {
323 uint32_t dst32 = SkExpand_rgb_16(*device) * scale5;
324 *device++ = SkCompact_rgb_16((src32 + dst32) >> 5);
325 } while (--n != 0);
326 goto DONE;
327 }
328 }
329 device += count;
reed@android.com31d1c642009-06-15 18:45:19 +0000330
reed@android.com9a74d312009-06-15 15:56:35 +0000331 DONE:
332 // if we have no dithering, this will always fail
333 if (count & ditherInt) {
334 SkTSwap(ditherColor, srcColor);
335 }
336 }
337}
338
339#define solid_8_pixels(mask, dst, color) \
340 do { \
341 if (mask & 0x80) dst[0] = color; \
342 if (mask & 0x40) dst[1] = color; \
343 if (mask & 0x20) dst[2] = color; \
344 if (mask & 0x10) dst[3] = color; \
345 if (mask & 0x08) dst[4] = color; \
346 if (mask & 0x04) dst[5] = color; \
347 if (mask & 0x02) dst[6] = color; \
348 if (mask & 0x01) dst[7] = color; \
349 } while (0)
350
351#define SK_BLITBWMASK_NAME SkRGB16_BlitBW
352#define SK_BLITBWMASK_ARGS , uint16_t color
353#define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color)
reed41e010c2015-06-09 12:16:53 -0700354#define SK_BLITBWMASK_GETADDR writable_addr16
reed@android.com9a74d312009-06-15 15:56:35 +0000355#define SK_BLITBWMASK_DEVTYPE uint16_t
356#include "SkBlitBWMaskTemplate.h"
357
358static U16CPU blend_compact(uint32_t src32, uint32_t dst32, unsigned scale5) {
359 return SkCompact_rgb_16(dst32 + ((src32 - dst32) * scale5 >> 5));
360}
361
tomhudson@google.com333d6cb2011-07-12 19:19:03 +0000362void SkRGB16_Opaque_Blitter::blitMask(const SkMask& mask,
363 const SkIRect& clip) {
reed@android.com9a74d312009-06-15 15:56:35 +0000364 if (mask.fFormat == SkMask::kBW_Format) {
365 SkRGB16_BlitBW(fDevice, mask, clip, fColor16);
366 return;
367 }
reed@android.com31d1c642009-06-15 18:45:19 +0000368
reed41e010c2015-06-09 12:16:53 -0700369 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(clip.fLeft, clip.fTop);
reed@google.com79891862011-10-18 15:44:57 +0000370 const uint8_t* SK_RESTRICT alpha = mask.getAddr8(clip.fLeft, clip.fTop);
reed@android.com9a74d312009-06-15 15:56:35 +0000371 int width = clip.width();
372 int height = clip.height();
scroggo@google.come5f48242013-02-25 21:47:41 +0000373 size_t deviceRB = fDevice.rowBytes() - (width << 1);
reed@android.com9a74d312009-06-15 15:56:35 +0000374 unsigned maskRB = mask.fRowBytes - width;
reed@android.comea16cfa2009-10-02 19:11:02 +0000375 uint32_t expanded32 = fExpandedRaw16;
reed@android.com31d1c642009-06-15 18:45:19 +0000376
mtklein809ccf32016-05-05 10:58:39 -0700377#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN)
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000378#define UNROLL 8
reed@android.com867ee802009-10-20 13:55:41 +0000379 do {
380 int w = width;
381 if (w >= UNROLL) {
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000382 uint32x4_t color, dev_lo, dev_hi;
383 uint32x4_t wn1, wn2, tmp;
384 uint32x4_t vmask_g16, vmask_ng16;
385 uint16x8_t valpha, vdev;
386 uint16x4_t odev_lo, odev_hi, valpha_lo, valpha_hi;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000387
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000388 // prepare constants
389 vmask_g16 = vdupq_n_u32(SK_G16_MASK_IN_PLACE);
390 vmask_ng16 = vdupq_n_u32(~SK_G16_MASK_IN_PLACE);
reed@android.com867ee802009-10-20 13:55:41 +0000391 color = vdupq_n_u32(expanded32);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000392
reed@android.com867ee802009-10-20 13:55:41 +0000393 do {
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000394 // alpha is 8x8, widen and split to get a pair of 16x4
395 valpha = vaddw_u8(vdupq_n_u16(1), vld1_u8(alpha));
396 valpha = vshrq_n_u16(valpha, 3);
397 valpha_lo = vget_low_u16(valpha);
398 valpha_hi = vget_high_u16(valpha);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000399
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000400 // load pixels
401 vdev = vld1q_u16(device);
402 dev_lo = vmovl_u16(vget_low_u16(vdev));
403 dev_hi = vmovl_u16(vget_high_u16(vdev));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000404
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000405 // unpack them in 32 bits
406 dev_lo = (dev_lo & vmask_ng16) | vshlq_n_u32(dev_lo & vmask_g16, 16);
407 dev_hi = (dev_hi & vmask_ng16) | vshlq_n_u32(dev_hi & vmask_g16, 16);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000408
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000409 // blend with color
410 tmp = (color - dev_lo) * vmovl_u16(valpha_lo);
411 tmp = vshrq_n_u32(tmp, 5);
412 dev_lo += tmp;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000413
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000414 tmp = vmulq_u32(color - dev_hi, vmovl_u16(valpha_hi));
415 tmp = vshrq_n_u32(tmp, 5);
416 dev_hi += tmp;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000417
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000418 // re-compact
419 wn1 = dev_lo & vmask_ng16;
420 wn2 = vshrq_n_u32(dev_lo, 16) & vmask_g16;
421 odev_lo = vmovn_u32(wn1 | wn2);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000422
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000423 wn1 = dev_hi & vmask_ng16;
424 wn2 = vshrq_n_u32(dev_hi, 16) & vmask_g16;
425 odev_hi = vmovn_u32(wn1 | wn2);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000426
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000427 // store
428 vst1q_u16(device, vcombine_u16(odev_lo, odev_hi));
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000429
reed@android.com867ee802009-10-20 13:55:41 +0000430 device += UNROLL;
431 alpha += UNROLL;
432 w -= UNROLL;
433 } while (w >= UNROLL);
434 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000435
commit-bot@chromium.org641a2492013-08-08 10:51:45 +0000436 // residuals
reed@android.com867ee802009-10-20 13:55:41 +0000437 while (w > 0) {
438 *device = blend_compact(expanded32, SkExpand_rgb_16(*device),
439 SkAlpha255To256(*alpha++) >> 3);
440 device += 1;
441 --w;
442 }
443 device = (uint16_t*)((char*)device + deviceRB);
444 alpha += maskRB;
445 } while (--height != 0);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000446#undef UNROLL
reed@android.com867ee802009-10-20 13:55:41 +0000447#else // non-neon code
reed@android.com9a74d312009-06-15 15:56:35 +0000448 do {
449 int w = width;
450 do {
reed@android.comea16cfa2009-10-02 19:11:02 +0000451 *device = blend_compact(expanded32, SkExpand_rgb_16(*device),
reed@android.com9a74d312009-06-15 15:56:35 +0000452 SkAlpha255To256(*alpha++) >> 3);
453 device += 1;
454 } while (--w != 0);
455 device = (uint16_t*)((char*)device + deviceRB);
456 alpha += maskRB;
457 } while (--height != 0);
reed@android.com867ee802009-10-20 13:55:41 +0000458#endif
reed@android.com9a74d312009-06-15 15:56:35 +0000459}
460
reed@android.comea16cfa2009-10-02 19:11:02 +0000461void SkRGB16_Opaque_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
reed41e010c2015-06-09 12:16:53 -0700462 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
scroggo@google.come5f48242013-02-25 21:47:41 +0000463 size_t deviceRB = fDevice.rowBytes();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000464
reed@android.comea16cfa2009-10-02 19:11:02 +0000465 // TODO: respect fDoDither
466 unsigned scale5 = SkAlpha255To256(alpha) >> 3;
467 uint32_t src32 = fExpandedRaw16 * scale5;
468 scale5 = 32 - scale5;
mtklein809ccf32016-05-05 10:58:39 -0700469#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN)
yang.zhangdc77b352015-07-15 07:07:30 -0700470 SkRGB16BlitterBlitV_neon(device, height, deviceRB, scale5, src32);
471#else
reed@android.comea16cfa2009-10-02 19:11:02 +0000472 do {
473 uint32_t dst32 = SkExpand_rgb_16(*device) * scale5;
474 *device = SkCompact_rgb_16((src32 + dst32) >> 5);
475 device = (uint16_t*)((char*)device + deviceRB);
476 } while (--height != 0);
yang.zhangdc77b352015-07-15 07:07:30 -0700477#endif
reed@android.comea16cfa2009-10-02 19:11:02 +0000478}
479
reed@android.com9a74d312009-06-15 15:56:35 +0000480void SkRGB16_Opaque_Blitter::blitRect(int x, int y, int width, int height) {
481 SkASSERT(x + width <= fDevice.width() && y + height <= fDevice.height());
reed41e010c2015-06-09 12:16:53 -0700482 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
scroggo@google.come5f48242013-02-25 21:47:41 +0000483 size_t deviceRB = fDevice.rowBytes();
reed@android.com9a74d312009-06-15 15:56:35 +0000484 uint16_t color16 = fColor16;
reed@android.com31d1c642009-06-15 18:45:19 +0000485
reed@android.com9a74d312009-06-15 15:56:35 +0000486 if (fDoDither) {
487 uint16_t ditherColor = fRawDither16;
488 if ((x ^ y) & 1) {
489 SkTSwap(ditherColor, color16);
490 }
491 while (--height >= 0) {
492 sk_dither_memset16(device, color16, ditherColor, width);
493 SkTSwap(ditherColor, color16);
494 device = (uint16_t*)((char*)device + deviceRB);
495 }
496 } else { // no dither
497 while (--height >= 0) {
498 sk_memset16(device, color16, width);
499 device = (uint16_t*)((char*)device + deviceRB);
500 }
501 }
502}
503
504///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000505
reed41e010c2015-06-09 12:16:53 -0700506SkRGB16_Blitter::SkRGB16_Blitter(const SkPixmap& device, const SkPaint& paint)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000507 : INHERITED(device) {
508 SkColor color = paint.getColor();
509
510 fSrcColor32 = SkPreMultiplyColor(color);
511 fScale = SkAlpha255To256(SkColorGetA(color));
512
513 int r = SkColorGetR(color);
514 int g = SkColorGetG(color);
515 int b = SkColorGetB(color);
516
517 fRawColor16 = fRawDither16 = SkPack888ToRGB16(r, g, b);
518 // if we're dithered, use fRawDither16 to hold that.
519 if ((fDoDither = paint.isDither()) != false) {
520 fRawDither16 = SkDitherPack888ToRGB16(r, g, b);
521 }
reed@android.comea16cfa2009-10-02 19:11:02 +0000522
523 fExpandedRaw16 = SkExpand_rgb_16(fRawColor16);
524
reed@android.com8a1c16f2008-12-17 15:59:43 +0000525 fColor16 = SkPackRGB16( SkAlphaMul(r, fScale) >> (8 - SK_R16_BITS),
526 SkAlphaMul(g, fScale) >> (8 - SK_G16_BITS),
527 SkAlphaMul(b, fScale) >> (8 - SK_B16_BITS));
mlee402448d2015-01-29 06:22:41 -0800528
529 // compute SkBlitRow::Procs
530 unsigned flags = 0;
531
532 if (SkGetPackedA32(fSrcColor32) < 0xFF) {
533 flags |= SkBlitRow::kSrcPixelAlpha_Flag;
534 }
535
536 if (fDoDither) {
537 flags |= SkBlitRow::kDither_Flag;
538 }
539
540 fColorProc16 = SkBlitRow::ColorFactory16(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000541}
542
reed41e010c2015-06-09 12:16:53 -0700543const SkPixmap* SkRGB16_Blitter::justAnOpaqueColor(uint32_t* value) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000544 if (!fDoDither && 256 == fScale) {
545 *value = fRawColor16;
546 return &fDevice;
547 }
halcanary96fcdcc2015-08-27 07:41:13 -0700548 return nullptr;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000549}
550
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000551void SkRGB16_Blitter::blitH(int x, int y, int width) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000552 SkASSERT(width > 0);
553 SkASSERT(x + width <= fDevice.width());
reed41e010c2015-06-09 12:16:53 -0700554 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000555
mlee402448d2015-01-29 06:22:41 -0800556 fColorProc16(device, fSrcColor32, width, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000557}
558
559void SkRGB16_Blitter::blitAntiH(int x, int y,
560 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000561 const int16_t* SK_RESTRICT runs) {
reed41e010c2015-06-09 12:16:53 -0700562 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
reed@android.comea16cfa2009-10-02 19:11:02 +0000563 uint32_t srcExpanded = fExpandedRaw16;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000564 unsigned scale = fScale;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000565
reed@android.com9a74d312009-06-15 15:56:35 +0000566 // TODO: respect fDoDither
567 for (;;) {
568 int count = runs[0];
569 SkASSERT(count >= 0);
570 if (count <= 0) {
571 return;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000572 }
reed@android.com9a74d312009-06-15 15:56:35 +0000573 runs += count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000574
reed@android.com9a74d312009-06-15 15:56:35 +0000575 unsigned aa = antialias[0];
576 antialias += count;
577 if (aa) {
578 unsigned scale5 = SkAlpha255To256(aa) * scale >> (8 + 3);
reed@android.comea16cfa2009-10-02 19:11:02 +0000579 uint32_t src32 = srcExpanded * scale5;
reed@android.com9a74d312009-06-15 15:56:35 +0000580 scale5 = 32 - scale5;
581 do {
582 uint32_t dst32 = SkExpand_rgb_16(*device) * scale5;
583 *device++ = SkCompact_rgb_16((src32 + dst32) >> 5);
584 } while (--count != 0);
585 continue;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000586 }
reed@android.com9a74d312009-06-15 15:56:35 +0000587 device += count;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000588 }
589}
590
reed@android.com8a1c16f2008-12-17 15:59:43 +0000591static inline void blend_8_pixels(U8CPU bw, uint16_t dst[], unsigned dst_scale,
592 U16CPU srcColor) {
593 if (bw & 0x80) dst[0] = srcColor + SkAlphaMulRGB16(dst[0], dst_scale);
594 if (bw & 0x40) dst[1] = srcColor + SkAlphaMulRGB16(dst[1], dst_scale);
595 if (bw & 0x20) dst[2] = srcColor + SkAlphaMulRGB16(dst[2], dst_scale);
596 if (bw & 0x10) dst[3] = srcColor + SkAlphaMulRGB16(dst[3], dst_scale);
597 if (bw & 0x08) dst[4] = srcColor + SkAlphaMulRGB16(dst[4], dst_scale);
598 if (bw & 0x04) dst[5] = srcColor + SkAlphaMulRGB16(dst[5], dst_scale);
599 if (bw & 0x02) dst[6] = srcColor + SkAlphaMulRGB16(dst[6], dst_scale);
600 if (bw & 0x01) dst[7] = srcColor + SkAlphaMulRGB16(dst[7], dst_scale);
601}
602
603#define SK_BLITBWMASK_NAME SkRGB16_BlendBW
604#define SK_BLITBWMASK_ARGS , unsigned dst_scale, U16CPU src_color
605#define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, dst_scale, src_color)
reed41e010c2015-06-09 12:16:53 -0700606#define SK_BLITBWMASK_GETADDR writable_addr16
reed@android.com8a1c16f2008-12-17 15:59:43 +0000607#define SK_BLITBWMASK_DEVTYPE uint16_t
608#include "SkBlitBWMaskTemplate.h"
609
tomhudson@google.com333d6cb2011-07-12 19:19:03 +0000610void SkRGB16_Blitter::blitMask(const SkMask& mask,
611 const SkIRect& clip) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000612 if (mask.fFormat == SkMask::kBW_Format) {
reed@android.com9a74d312009-06-15 15:56:35 +0000613 SkRGB16_BlendBW(fDevice, mask, clip, 256 - fScale, fColor16);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000614 return;
615 }
616
reed41e010c2015-06-09 12:16:53 -0700617 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(clip.fLeft, clip.fTop);
reed@google.com79891862011-10-18 15:44:57 +0000618 const uint8_t* SK_RESTRICT alpha = mask.getAddr8(clip.fLeft, clip.fTop);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619 int width = clip.width();
620 int height = clip.height();
scroggo@google.come5f48242013-02-25 21:47:41 +0000621 size_t deviceRB = fDevice.rowBytes() - (width << 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000622 unsigned maskRB = mask.fRowBytes - width;
reed@android.comea16cfa2009-10-02 19:11:02 +0000623 uint32_t color32 = fExpandedRaw16;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000624
reed@android.com9a74d312009-06-15 15:56:35 +0000625 unsigned scale256 = fScale;
626 do {
627 int w = width;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000628 do {
reed@android.com9a74d312009-06-15 15:56:35 +0000629 unsigned aa = *alpha++;
630 unsigned scale = SkAlpha255To256(aa) * scale256 >> (8 + 3);
631 uint32_t src32 = color32 * scale;
632 uint32_t dst32 = SkExpand_rgb_16(*device) * (32 - scale);
633 *device++ = SkCompact_rgb_16((src32 + dst32) >> 5);
634 } while (--w != 0);
635 device = (uint16_t*)((char*)device + deviceRB);
636 alpha += maskRB;
637 } while (--height != 0);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000638}
639
640void SkRGB16_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
reed41e010c2015-06-09 12:16:53 -0700641 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
scroggo@google.come5f48242013-02-25 21:47:41 +0000642 size_t deviceRB = fDevice.rowBytes();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000643
reed@android.comea16cfa2009-10-02 19:11:02 +0000644 // TODO: respect fDoDither
645 unsigned scale5 = SkAlpha255To256(alpha) * fScale >> (8 + 3);
646 uint32_t src32 = fExpandedRaw16 * scale5;
647 scale5 = 32 - scale5;
mtklein809ccf32016-05-05 10:58:39 -0700648#if defined(SK_ARM_HAS_NEON) && defined(SK_CPU_LENDIAN)
yang.zhangdc77b352015-07-15 07:07:30 -0700649 SkRGB16BlitterBlitV_neon(device, height, deviceRB, scale5, src32);
650#else
reed@android.comea16cfa2009-10-02 19:11:02 +0000651 do {
652 uint32_t dst32 = SkExpand_rgb_16(*device) * scale5;
653 *device = SkCompact_rgb_16((src32 + dst32) >> 5);
654 device = (uint16_t*)((char*)device + deviceRB);
655 } while (--height != 0);
yang.zhangdc77b352015-07-15 07:07:30 -0700656#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000657}
658
659void SkRGB16_Blitter::blitRect(int x, int y, int width, int height) {
660 SkASSERT(x + width <= fDevice.width() && y + height <= fDevice.height());
reed41e010c2015-06-09 12:16:53 -0700661 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
scroggo@google.come5f48242013-02-25 21:47:41 +0000662 size_t deviceRB = fDevice.rowBytes();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000663
reed@android.com9a74d312009-06-15 15:56:35 +0000664 while (--height >= 0) {
mlee402448d2015-01-29 06:22:41 -0800665 fColorProc16(device, fSrcColor32, width, x, y);
reed@android.com9a74d312009-06-15 15:56:35 +0000666 device = (uint16_t*)((char*)device + deviceRB);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000667 }
668}
669
670///////////////////////////////////////////////////////////////////////////////
671
reed41e010c2015-06-09 12:16:53 -0700672SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkPixmap& device,
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000673 const SkPaint& paint,
674 SkShader::Context* shaderContext)
reed41e010c2015-06-09 12:16:53 -0700675 : INHERITED(device, paint, shaderContext)
676{
reed374772b2016-10-05 17:33:02 -0700677 SkASSERT(paint.isSrcOver());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000678
679 fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor));
680
681 // compute SkBlitRow::Procs
682 unsigned flags = 0;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000683
reed@android.com5119bdb2009-06-12 21:27:03 +0000684 uint32_t shaderFlags = fShaderFlags;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000685 // shaders take care of global alpha, so we never set it in SkBlitRow
686 if (!(shaderFlags & SkShader::kOpaqueAlpha_Flag)) {
687 flags |= SkBlitRow::kSrcPixelAlpha_Flag;
commit-bot@chromium.orgc2050e32013-07-15 13:10:31 +0000688 }
reed4e5a7582016-01-05 05:10:33 -0800689 if (paint.isDither()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000690 flags |= SkBlitRow::kDither_Flag;
691 }
692 // used when we know our global alpha is 0xFF
reeda7f11912015-01-13 13:51:00 -0800693 fOpaqueProc = SkBlitRow::Factory16(flags);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000694 // used when we know our global alpha is < 0xFF
reeda7f11912015-01-13 13:51:00 -0800695 fAlphaProc = SkBlitRow::Factory16(flags | SkBlitRow::kGlobalAlpha_Flag);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000696}
697
698SkRGB16_Shader_Blitter::~SkRGB16_Shader_Blitter() {
699 sk_free(fBuffer);
700}
701
702void SkRGB16_Shader_Blitter::blitH(int x, int y, int width) {
703 SkASSERT(x + width <= fDevice.width());
704
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000705 fShaderContext->shadeSpan(x, y, fBuffer, width);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000706 // shaders take care of global alpha, so we pass 0xFF (should be ignored)
reed41e010c2015-06-09 12:16:53 -0700707 fOpaqueProc(fDevice.writable_addr16(x, y), fBuffer, width, 0xFF, x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000708}
709
reed@android.com5119bdb2009-06-12 21:27:03 +0000710void SkRGB16_Shader_Blitter::blitRect(int x, int y, int width, int height) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000711 SkShader::Context* shaderContext = fShaderContext;
reeda7f11912015-01-13 13:51:00 -0800712 SkBlitRow::Proc16 proc = fOpaqueProc;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000713 SkPMColor* buffer = fBuffer;
reed41e010c2015-06-09 12:16:53 -0700714 uint16_t* dst = fDevice.writable_addr16(x, y);
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000715 size_t dstRB = fDevice.rowBytes();
reed@android.com5119bdb2009-06-12 21:27:03 +0000716
reed@android.com3c9b2a42009-08-27 19:28:37 +0000717 if (fShaderFlags & SkShader::kConstInY32_Flag) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000718 shaderContext->shadeSpan(x, y, buffer, width);
reed@android.com5119bdb2009-06-12 21:27:03 +0000719 do {
720 proc(dst, buffer, width, 0xFF, x, y);
721 y += 1;
722 dst = (uint16_t*)((char*)dst + dstRB);
723 } while (--height);
724 } else {
725 do {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000726 shaderContext->shadeSpan(x, y, buffer, width);
reed@android.com5119bdb2009-06-12 21:27:03 +0000727 proc(dst, buffer, width, 0xFF, x, y);
728 y += 1;
729 dst = (uint16_t*)((char*)dst + dstRB);
730 } while (--height);
731 }
732}
733
reed@android.com8a1c16f2008-12-17 15:59:43 +0000734static inline int count_nonzero_span(const int16_t runs[], const SkAlpha aa[]) {
735 int count = 0;
736 for (;;) {
737 int n = *runs;
738 if (n == 0 || *aa == 0) {
739 break;
740 }
741 runs += n;
742 aa += n;
743 count += n;
744 }
745 return count;
746}
747
748void SkRGB16_Shader_Blitter::blitAntiH(int x, int y,
749 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000750 const int16_t* SK_RESTRICT runs) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000751 SkShader::Context* shaderContext = fShaderContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000752 SkPMColor* SK_RESTRICT span = fBuffer;
reed41e010c2015-06-09 12:16:53 -0700753 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754
755 for (;;) {
756 int count = *runs;
757 if (count <= 0) {
758 break;
759 }
760 int aa = *antialias;
761 if (0 == aa) {
762 device += count;
763 runs += count;
764 antialias += count;
765 x += count;
766 continue;
767 }
768
769 int nonZeroCount = count + count_nonzero_span(runs + count, antialias + count);
770
771 SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000772 shaderContext->shadeSpan(x, y, span, nonZeroCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773
774 SkPMColor* localSpan = span;
775 for (;;) {
reeda7f11912015-01-13 13:51:00 -0800776 SkBlitRow::Proc16 proc = (aa == 0xFF) ? fOpaqueProc : fAlphaProc;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000777 proc(device, localSpan, count, aa, x, y);
778
779 x += count;
780 device += count;
781 runs += count;
782 antialias += count;
783 nonZeroCount -= count;
784 if (nonZeroCount == 0) {
785 break;
786 }
787 localSpan += count;
788 SkASSERT(nonZeroCount > 0);
789 count = *runs;
790 SkASSERT(count > 0);
791 aa = *antialias;
792 }
793 }
794}
795
796///////////////////////////////////////////////////////////////////////
797
798SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter(
reed41e010c2015-06-09 12:16:53 -0700799 const SkPixmap& device, const SkPaint& paint,
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000800 SkShader::Context* shaderContext)
reed41e010c2015-06-09 12:16:53 -0700801 : INHERITED(device, paint, shaderContext)
802{
reed374772b2016-10-05 17:33:02 -0700803 fXfermode = SkXfermode::Peek(paint.getBlendMode());
reed@android.com8a1c16f2008-12-17 15:59:43 +0000804 SkASSERT(fXfermode);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000805
806 int width = device.width();
807 fBuffer = (SkPMColor*)sk_malloc_throw((width + (SkAlign4(width) >> 2)) * sizeof(SkPMColor));
808 fAAExpand = (uint8_t*)(fBuffer + width);
809}
810
811SkRGB16_Shader_Xfermode_Blitter::~SkRGB16_Shader_Xfermode_Blitter() {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000812 sk_free(fBuffer);
813}
814
815void SkRGB16_Shader_Xfermode_Blitter::blitH(int x, int y, int width) {
816 SkASSERT(x + width <= fDevice.width());
817
reed41e010c2015-06-09 12:16:53 -0700818 uint16_t* device = fDevice.writable_addr16(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819 SkPMColor* span = fBuffer;
820
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000821 fShaderContext->shadeSpan(x, y, span, width);
halcanary96fcdcc2015-08-27 07:41:13 -0700822 fXfermode->xfer16(device, span, width, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823}
824
825void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y,
826 const SkAlpha* SK_RESTRICT antialias,
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000827 const int16_t* SK_RESTRICT runs) {
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000828 SkShader::Context* shaderContext = fShaderContext;
829 SkXfermode* mode = fXfermode;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000830 SkPMColor* SK_RESTRICT span = fBuffer;
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000831 uint8_t* SK_RESTRICT aaExpand = fAAExpand;
reed41e010c2015-06-09 12:16:53 -0700832 uint16_t* SK_RESTRICT device = fDevice.writable_addr16(x, y);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000833
834 for (;;) {
835 int count = *runs;
836 if (count <= 0) {
837 break;
838 }
839 int aa = *antialias;
840 if (0 == aa) {
841 device += count;
842 runs += count;
843 antialias += count;
844 x += count;
845 continue;
846 }
847
848 int nonZeroCount = count + count_nonzero_span(runs + count,
849 antialias + count);
850
851 SkASSERT(nonZeroCount <= fDevice.width()); // don't overrun fBuffer
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000852 shaderContext->shadeSpan(x, y, span, nonZeroCount);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000853
854 x += nonZeroCount;
855 SkPMColor* localSpan = span;
856 for (;;) {
857 if (aa == 0xFF) {
halcanary96fcdcc2015-08-27 07:41:13 -0700858 mode->xfer16(device, localSpan, count, nullptr);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000859 } else {
860 SkASSERT(aa);
861 memset(aaExpand, aa, count);
862 mode->xfer16(device, localSpan, count, aaExpand);
863 }
864 device += count;
865 runs += count;
866 antialias += count;
867 nonZeroCount -= count;
868 if (nonZeroCount == 0) {
869 break;
870 }
871 localSpan += count;
872 SkASSERT(nonZeroCount > 0);
873 count = *runs;
874 SkASSERT(count > 0);
875 aa = *antialias;
876 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000877 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000878}
879
reed@android.com1fc4c602009-10-02 16:34:57 +0000880///////////////////////////////////////////////////////////////////////////////
reed@android.com8a1c16f2008-12-17 15:59:43 +0000881
reed41e010c2015-06-09 12:16:53 -0700882SkBlitter* SkBlitter_ChooseD565(const SkPixmap& device, const SkPaint& paint,
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000883 SkShader::Context* shaderContext,
Herb Derby83e939b2017-02-07 14:25:11 -0500884 SkArenaAlloc* alloc) {
885 SkASSERT(alloc != nullptr);
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000886
reed@android.com1fc4c602009-10-02 16:34:57 +0000887 SkBlitter* blitter;
888 SkShader* shader = paint.getShader();
reed374772b2016-10-05 17:33:02 -0700889 bool is_srcover = paint.isSrcOver();
reed@android.com1fc4c602009-10-02 16:34:57 +0000890
891 // we require a shader if there is an xfermode, handled by our caller
reed374772b2016-10-05 17:33:02 -0700892 SkASSERT(is_srcover || shader);
reed@android.com1fc4c602009-10-02 16:34:57 +0000893
894 if (shader) {
halcanary96fcdcc2015-08-27 07:41:13 -0700895 SkASSERT(shaderContext != nullptr);
reed374772b2016-10-05 17:33:02 -0700896 if (!is_srcover) {
Herb Derby83e939b2017-02-07 14:25:11 -0500897 blitter = alloc->make<SkRGB16_Shader_Xfermode_Blitter>(device, paint,
commit-bot@chromium.org87fcd952014-04-23 19:10:51 +0000898 shaderContext);
reed@android.com1fc4c602009-10-02 16:34:57 +0000899 } else {
Herb Derby83e939b2017-02-07 14:25:11 -0500900 blitter = alloc->make<SkRGB16_Shader_Blitter>(device, paint, shaderContext);
reed@android.com1fc4c602009-10-02 16:34:57 +0000901 }
902 } else {
903 // no shader, no xfermode, (and we always ignore colorfilter)
904 SkColor color = paint.getColor();
905 if (0 == SkColorGetA(color)) {
Herb Derby83e939b2017-02-07 14:25:11 -0500906 blitter = alloc->make<SkNullBlitter>();
reed@android.com867ee802009-10-20 13:55:41 +0000907#ifdef USE_BLACK_BLITTER
reed@android.com1fc4c602009-10-02 16:34:57 +0000908 } else if (SK_ColorBLACK == color) {
Herb Derby83e939b2017-02-07 14:25:11 -0500909 blitter = alloc->make<SkRGB16_Black_Blitter>(device, paint);
reed@android.com867ee802009-10-20 13:55:41 +0000910#endif
reed@android.com1fc4c602009-10-02 16:34:57 +0000911 } else if (0xFF == SkColorGetA(color)) {
Herb Derby83e939b2017-02-07 14:25:11 -0500912 blitter = alloc->make<SkRGB16_Opaque_Blitter>(device, paint);
reed@android.com1fc4c602009-10-02 16:34:57 +0000913 } else {
Herb Derby83e939b2017-02-07 14:25:11 -0500914 blitter = alloc->make<SkRGB16_Blitter>(device, paint);
reed@android.com1fc4c602009-10-02 16:34:57 +0000915 }
916 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000917
reed@android.com1fc4c602009-10-02 16:34:57 +0000918 return blitter;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919}