blob: 3f712bb3ecfc4c96b10f1d4fd8a13cebcae0a6aa [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 "SkSpriteBlitter.h"
11#include "SkBlitRow.h"
12#include "SkTemplates.h"
13#include "SkUtils.h"
14#include "SkColorPriv.h"
15
16#define D16_S32A_Opaque_Pixel(dst, sc) \
17do { \
18 if (sc) { \
19 *dst = SkSrcOver32To16(sc, *dst); \
20 } \
21} while (0)
22
23static inline void D16_S32A_Blend_Pixel_helper(uint16_t* dst, SkPMColor sc,
24 unsigned src_scale) {
25 uint16_t dc = *dst;
26 unsigned sa = SkGetPackedA32(sc);
27 unsigned dr, dg, db;
28
29 if (255 == sa) {
30 dr = SkAlphaBlend(SkPacked32ToR16(sc), SkGetPackedR16(dc), src_scale);
31 dg = SkAlphaBlend(SkPacked32ToG16(sc), SkGetPackedG16(dc), src_scale);
32 db = SkAlphaBlend(SkPacked32ToB16(sc), SkGetPackedB16(dc), src_scale);
33 } else {
34 unsigned dst_scale = 255 - SkAlphaMul(sa, src_scale);
35 dr = (SkPacked32ToR16(sc) * src_scale +
36 SkGetPackedR16(dc) * dst_scale) >> 8;
37 dg = (SkPacked32ToG16(sc) * src_scale +
38 SkGetPackedG16(dc) * dst_scale) >> 8;
39 db = (SkPacked32ToB16(sc) * src_scale +
40 SkGetPackedB16(dc) * dst_scale) >> 8;
41 }
42 *dst = SkPackRGB16(dr, dg, db);
43}
44
45#define D16_S32A_Blend_Pixel(dst, sc, src_scale) \
46 do { if (sc) D16_S32A_Blend_Pixel_helper(dst, sc, src_scale); } while (0)
47
48
49///////////////////////////////////////////////////////////////////////////////
50
51class Sprite_D16_S16_Opaque : public SkSpriteBlitter {
52public:
53 Sprite_D16_S16_Opaque(const SkBitmap& source)
54 : SkSpriteBlitter(source) {}
55
56 // overrides
57 virtual void blitRect(int x, int y, int width, int height) {
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +000058 uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y);
59 const uint16_t* SK_RESTRICT src = fSource->getAddr16(x - fLeft,
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 y - fTop);
scroggo@google.come5f48242013-02-25 21:47:41 +000061 size_t dstRB = fDevice->rowBytes();
62 size_t srcRB = fSource->rowBytes();
reed@android.com8a1c16f2008-12-17 15:59:43 +000063
64 while (--height >= 0) {
65 memcpy(dst, src, width << 1);
66 dst = (uint16_t*)((char*)dst + dstRB);
67 src = (const uint16_t*)((const char*)src + srcRB);
68 }
69 }
70};
71
72#define D16_S16_Blend_Pixel(dst, sc, scale) \
73 do { \
74 uint16_t dc = *dst; \
75 *dst = SkBlendRGB16(sc, dc, scale); \
76 } while (0)
77
78#define SkSPRITE_CLASSNAME Sprite_D16_S16_Blend
79#define SkSPRITE_ARGS , uint8_t alpha
80#define SkSPRITE_FIELDS uint8_t fSrcAlpha;
81#define SkSPRITE_INIT fSrcAlpha = alpha;
82#define SkSPRITE_DST_TYPE uint16_t
83#define SkSPRITE_SRC_TYPE uint16_t
84#define SkSPRITE_DST_GETADDR getAddr16
85#define SkSPRITE_SRC_GETADDR getAddr16
86#define SkSPRITE_PREAMBLE(srcBM, x, y) int scale = SkAlpha255To256(fSrcAlpha);
87#define SkSPRITE_BLIT_PIXEL(dst, src) D16_S16_Blend_Pixel(dst, src, scale)
88#define SkSPRITE_NEXT_ROW
89#define SkSPRITE_POSTAMBLE(srcBM)
90#include "SkSpriteBlitterTemplate.h"
91
92///////////////////////////////////////////////////////////////////////////////
93
94#define D16_S4444_Opaque(dst, sc) \
95 do { \
96 uint16_t dc = *dst; \
97 *dst = SkSrcOver4444To16(sc, dc); \
98 } while (0)
99
100#define SkSPRITE_CLASSNAME Sprite_D16_S4444_Opaque
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000101#define SkSPRITE_ARGS
102#define SkSPRITE_FIELDS
103#define SkSPRITE_INIT
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104#define SkSPRITE_DST_TYPE uint16_t
105#define SkSPRITE_SRC_TYPE SkPMColor16
106#define SkSPRITE_DST_GETADDR getAddr16
107#define SkSPRITE_SRC_GETADDR getAddr16
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000108#define SkSPRITE_PREAMBLE(srcBM, x, y)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109#define SkSPRITE_BLIT_PIXEL(dst, src) D16_S4444_Opaque(dst, src)
110#define SkSPRITE_NEXT_ROW
111#define SkSPRITE_POSTAMBLE(srcBM)
112#include "SkSpriteBlitterTemplate.h"
113
114#define D16_S4444_Blend(dst, sc, scale16) \
115 do { \
116 uint16_t dc = *dst; \
117 *dst = SkBlend4444To16(sc, dc, scale16); \
118 } while (0)
119
120
121#define SkSPRITE_CLASSNAME Sprite_D16_S4444_Blend
122#define SkSPRITE_ARGS , uint8_t alpha
123#define SkSPRITE_FIELDS uint8_t fSrcAlpha;
124#define SkSPRITE_INIT fSrcAlpha = alpha;
125#define SkSPRITE_DST_TYPE uint16_t
126#define SkSPRITE_SRC_TYPE uint16_t
127#define SkSPRITE_DST_GETADDR getAddr16
128#define SkSPRITE_SRC_GETADDR getAddr16
129#define SkSPRITE_PREAMBLE(srcBM, x, y) int scale = SkAlpha15To16(fSrcAlpha);
130#define SkSPRITE_BLIT_PIXEL(dst, src) D16_S4444_Blend(dst, src, scale)
131#define SkSPRITE_NEXT_ROW
132#define SkSPRITE_POSTAMBLE(srcBM)
133#include "SkSpriteBlitterTemplate.h"
134
135///////////////////////////////////////////////////////////////////////////////
136
137#define SkSPRITE_CLASSNAME Sprite_D16_SIndex8A_Opaque
138#define SkSPRITE_ARGS
139#define SkSPRITE_FIELDS
140#define SkSPRITE_INIT
141#define SkSPRITE_DST_TYPE uint16_t
142#define SkSPRITE_SRC_TYPE uint8_t
143#define SkSPRITE_DST_GETADDR getAddr16
144#define SkSPRITE_SRC_GETADDR getAddr8
145#define SkSPRITE_PREAMBLE(srcBM, x, y) const SkPMColor* ctable = srcBM.getColorTable()->lockColors()
146#define SkSPRITE_BLIT_PIXEL(dst, src) D16_S32A_Opaque_Pixel(dst, ctable[src])
147#define SkSPRITE_NEXT_ROW
reed@google.com0a6151d2013-10-10 14:44:56 +0000148#define SkSPRITE_POSTAMBLE(srcBM) srcBM.getColorTable()->unlockColors()
reed@android.com8a1c16f2008-12-17 15:59:43 +0000149#include "SkSpriteBlitterTemplate.h"
150
151#define SkSPRITE_CLASSNAME Sprite_D16_SIndex8A_Blend
152#define SkSPRITE_ARGS , uint8_t alpha
153#define SkSPRITE_FIELDS uint8_t fSrcAlpha;
154#define SkSPRITE_INIT fSrcAlpha = alpha;
155#define SkSPRITE_DST_TYPE uint16_t
156#define SkSPRITE_SRC_TYPE uint8_t
157#define SkSPRITE_DST_GETADDR getAddr16
158#define SkSPRITE_SRC_GETADDR getAddr8
159#define SkSPRITE_PREAMBLE(srcBM, x, y) const SkPMColor* ctable = srcBM.getColorTable()->lockColors(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
160#define SkSPRITE_BLIT_PIXEL(dst, src) D16_S32A_Blend_Pixel(dst, ctable[src], src_scale)
161#define SkSPRITE_NEXT_ROW
reed@google.com0a6151d2013-10-10 14:44:56 +0000162#define SkSPRITE_POSTAMBLE(srcBM) srcBM.getColorTable()->unlockColors();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163#include "SkSpriteBlitterTemplate.h"
164
165///////////////////////////////////////////////////////////////////////////////
166
reed@android.com1c12abe2009-07-02 15:01:02 +0000167static intptr_t asint(const void* ptr) {
168 return reinterpret_cast<const char*>(ptr) - (const char*)0;
169}
170
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000171static void blitrow_d16_si8(uint16_t* SK_RESTRICT dst,
172 const uint8_t* SK_RESTRICT src, int count,
173 const uint16_t* SK_RESTRICT ctable) {
reed@android.com1c12abe2009-07-02 15:01:02 +0000174 if (count <= 8) {
175 do {
176 *dst++ = ctable[*src++];
177 } while (--count);
178 return;
179 }
180
181 // eat src until we're on a 4byte boundary
182 while (asint(src) & 3) {
183 *dst++ = ctable[*src++];
184 count -= 1;
185 }
186
187 int qcount = count >> 2;
188 SkASSERT(qcount > 0);
189 const uint32_t* qsrc = reinterpret_cast<const uint32_t*>(src);
190 if (asint(dst) & 2) {
191 do {
192 uint32_t s4 = *qsrc++;
193#ifdef SK_CPU_LENDIAN
194 *dst++ = ctable[s4 & 0xFF];
195 *dst++ = ctable[(s4 >> 8) & 0xFF];
196 *dst++ = ctable[(s4 >> 16) & 0xFF];
197 *dst++ = ctable[s4 >> 24];
198#else // BENDIAN
199 *dst++ = ctable[s4 >> 24];
200 *dst++ = ctable[(s4 >> 16) & 0xFF];
201 *dst++ = ctable[(s4 >> 8) & 0xFF];
202 *dst++ = ctable[s4 & 0xFF];
203#endif
204 } while (--qcount);
205 } else { // dst is on a 4byte boundary
206 uint32_t* ddst = reinterpret_cast<uint32_t*>(dst);
207 do {
208 uint32_t s4 = *qsrc++;
209#ifdef SK_CPU_LENDIAN
210 *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
211 *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
212#else // BENDIAN
213 *ddst++ = (ctable[s4 >> 24] << 16) | ctable[(s4 >> 16) & 0xFF];
214 *ddst++ = (ctable[(s4 >> 8) & 0xFF] << 16) | ctable[s4 & 0xFF];
215#endif
216 } while (--qcount);
217 dst = reinterpret_cast<uint16_t*>(ddst);
218 }
219 src = reinterpret_cast<const uint8_t*>(qsrc);
220 count &= 3;
221 // catch any remaining (will be < 4)
222 while (--count >= 0) {
223 *dst++ = ctable[*src++];
224 }
225}
226
227#define SkSPRITE_ROW_PROC(d, s, n, x, y) blitrow_d16_si8(d, s, n, ctable)
reed@android.com084ad422009-07-07 13:20:37 +0000228
reed@android.com8a1c16f2008-12-17 15:59:43 +0000229#define SkSPRITE_CLASSNAME Sprite_D16_SIndex8_Opaque
230#define SkSPRITE_ARGS
231#define SkSPRITE_FIELDS
232#define SkSPRITE_INIT
233#define SkSPRITE_DST_TYPE uint16_t
234#define SkSPRITE_SRC_TYPE uint8_t
235#define SkSPRITE_DST_GETADDR getAddr16
236#define SkSPRITE_SRC_GETADDR getAddr8
237#define SkSPRITE_PREAMBLE(srcBM, x, y) const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache()
238#define SkSPRITE_BLIT_PIXEL(dst, src) *dst = ctable[src]
239#define SkSPRITE_NEXT_ROW
240#define SkSPRITE_POSTAMBLE(srcBM) srcBM.getColorTable()->unlock16BitCache()
241#include "SkSpriteBlitterTemplate.h"
242
243#define SkSPRITE_CLASSNAME Sprite_D16_SIndex8_Blend
244#define SkSPRITE_ARGS , uint8_t alpha
245#define SkSPRITE_FIELDS uint8_t fSrcAlpha;
246#define SkSPRITE_INIT fSrcAlpha = alpha;
247#define SkSPRITE_DST_TYPE uint16_t
248#define SkSPRITE_SRC_TYPE uint8_t
249#define SkSPRITE_DST_GETADDR getAddr16
250#define SkSPRITE_SRC_GETADDR getAddr8
251#define SkSPRITE_PREAMBLE(srcBM, x, y) const uint16_t* ctable = srcBM.getColorTable()->lock16BitCache(); unsigned src_scale = SkAlpha255To256(fSrcAlpha);
252#define SkSPRITE_BLIT_PIXEL(dst, src) D16_S16_Blend_Pixel(dst, ctable[src], src_scale)
253#define SkSPRITE_NEXT_ROW
254#define SkSPRITE_POSTAMBLE(srcBM) srcBM.getColorTable()->unlock16BitCache();
255#include "SkSpriteBlitterTemplate.h"
256
257///////////////////////////////////////////////////////////////////////////////
258
259class Sprite_D16_S32_BlitRowProc : public SkSpriteBlitter {
260public:
261 Sprite_D16_S32_BlitRowProc(const SkBitmap& source)
262 : SkSpriteBlitter(source) {}
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000263
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 // overrides
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000265
reed@android.com8a1c16f2008-12-17 15:59:43 +0000266 virtual void setup(const SkBitmap& device, int left, int top,
267 const SkPaint& paint) {
268 this->INHERITED::setup(device, left, top, paint);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000269
reed@android.com8a1c16f2008-12-17 15:59:43 +0000270 unsigned flags = 0;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000271
reed@android.com8a1c16f2008-12-17 15:59:43 +0000272 if (paint.getAlpha() < 0xFF) {
273 flags |= SkBlitRow::kGlobalAlpha_Flag;
274 }
275 if (!fSource->isOpaque()) {
276 flags |= SkBlitRow::kSrcPixelAlpha_Flag;
277 }
278 if (paint.isDither()) {
279 flags |= SkBlitRow::kDither_Flag;
280 }
281 fProc = SkBlitRow::Factory(flags, SkBitmap::kRGB_565_Config);
282 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000283
reed@android.com8a1c16f2008-12-17 15:59:43 +0000284 virtual void blitRect(int x, int y, int width, int height) {
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000285 uint16_t* SK_RESTRICT dst = fDevice->getAddr16(x, y);
286 const SkPMColor* SK_RESTRICT src = fSource->getAddr32(x - fLeft,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287 y - fTop);
scroggo@google.come5f48242013-02-25 21:47:41 +0000288 size_t dstRB = fDevice->rowBytes();
289 size_t srcRB = fSource->rowBytes();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 SkBlitRow::Proc proc = fProc;
291 U8CPU alpha = fPaint->getAlpha();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000292
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293 while (--height >= 0) {
294 proc(dst, src, width, alpha, x, y);
295 y += 1;
tomhudson@google.coma87cd2a2011-06-15 16:50:27 +0000296 dst = (uint16_t* SK_RESTRICT)((char*)dst + dstRB);
297 src = (const SkPMColor* SK_RESTRICT)((const char*)src + srcRB);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000298 }
299 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000300
reed@android.com8a1c16f2008-12-17 15:59:43 +0000301private:
302 SkBlitRow::Proc fProc;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000303
reed@android.com8a1c16f2008-12-17 15:59:43 +0000304 typedef SkSpriteBlitter INHERITED;
305};
306
307///////////////////////////////////////////////////////////////////////////////
308
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000309SkSpriteBlitter* SkSpriteBlitter::ChooseD16(const SkBitmap& source, const SkPaint& paint,
310 SkTBlitterAllocator* allocator) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000312 SkASSERT(allocator != NULL);
313
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 if (paint.getMaskFilter() != NULL) { // may add cases for this
315 return NULL;
316 }
317 if (paint.getXfermode() != NULL) { // may add cases for this
318 return NULL;
319 }
320 if (paint.getColorFilter() != NULL) { // may add cases for this
321 return NULL;
322 }
323
324 SkSpriteBlitter* blitter = NULL;
325 unsigned alpha = paint.getAlpha();
326
reed@google.com900ecf22014-02-20 20:55:37 +0000327 switch (source.colorType()) {
commit-bot@chromium.org149e9a12014-04-09 20:45:29 +0000328 case kN32_SkColorType: {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000329 blitter = allocator->createT<Sprite_D16_S32_BlitRowProc>(source);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000330 break;
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000331 }
reed@google.com900ecf22014-02-20 20:55:37 +0000332 case kARGB_4444_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000333 if (255 == alpha) {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000334 blitter = allocator->createT<Sprite_D16_S4444_Opaque>(source);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 } else {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000336 blitter = allocator->createT<Sprite_D16_S4444_Blend>(source, alpha >> 4);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337 }
338 break;
reed@google.com900ecf22014-02-20 20:55:37 +0000339 case kRGB_565_SkColorType:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340 if (255 == alpha) {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000341 blitter = allocator->createT<Sprite_D16_S16_Opaque>(source);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000342 } else {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000343 blitter = allocator->createT<Sprite_D16_S16_Blend>(source, alpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000344 }
345 break;
reed@google.com900ecf22014-02-20 20:55:37 +0000346 case kIndex_8_SkColorType:
reed@android.com755dd472009-08-20 21:29:45 +0000347 if (paint.isDither()) {
348 // we don't support dither yet in these special cases
349 break;
350 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000351 if (source.isOpaque()) {
352 if (255 == alpha) {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000353 blitter = allocator->createT<Sprite_D16_SIndex8_Opaque>(source);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000354 } else {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000355 blitter = allocator->createT<Sprite_D16_SIndex8_Blend>(source, alpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000356 }
357 } else {
358 if (255 == alpha) {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000359 blitter = allocator->createT<Sprite_D16_SIndex8A_Opaque>(source);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000360 } else {
commit-bot@chromium.orga5572e52014-03-07 03:24:41 +0000361 blitter = allocator->createT<Sprite_D16_SIndex8A_Blend>(source, alpha);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000362 }
363 }
364 break;
365 default:
366 break;
367 }
368 return blitter;
369}