1
/* libs/graphics/sgl/SkBlitter_ARGB32.cpp
3
** Copyright 2006, The Android Open Source Project
5
** Licensed under the Apache License, Version 2.0 (the "License");
6
** you may not use this file except in compliance with the License.
7
** You may obtain a copy of the License at
9
** http://www.apache.org/licenses/LICENSE-2.0
11
** Unless required by applicable law or agreed to in writing, software
12
** distributed under the License is distributed on an "AS IS" BASIS,
13
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
** See the License for the specific language governing permissions and
15
** limitations under the License.
18
#include "SkCoreBlitters.h"
19
#include "SkColorPriv.h"
22
#include "SkTemplatesPriv.h"
24
#include "SkXfermode.h"
26
inline SkPMColor SkBlendARGB4444(SkPMColor16 src, SkPMColor16 dst, U8CPU aa)
28
SkASSERT((unsigned)aa <= 255);
30
unsigned src_scale = SkAlpha255To256(aa) >> 4;
31
unsigned dst_scale = SkAlpha15To16(15 - SkAlphaMul4(SkGetPackedA4444(src), src_scale));
33
uint32_t src32 = SkExpand_4444(src) * src_scale;
34
uint32_t dst32 = SkExpand_4444(dst) * dst_scale;
35
return SkCompact_4444((src32 + dst32) >> 4);
38
///////////////////////////////////////////////////////////////////////////////
40
class SkARGB4444_Blitter : public SkRasterBlitter {
42
SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint);
43
virtual void blitH(int x, int y, int width);
44
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]);
45
virtual void blitV(int x, int y, int height, SkAlpha alpha);
46
virtual void blitRect(int x, int y, int width, int height);
47
virtual void blitMask(const SkMask&, const SkIRect&);
48
virtual const SkBitmap* justAnOpaqueColor(uint32_t*);
51
SkPMColor16 fPMColor16, fPMColor16Other;
52
SkPMColor16 fRawColor16, fRawColor16Other;
57
SkARGB4444_Blitter& operator=(const SkARGB4444_Blitter&);
59
typedef SkRasterBlitter INHERITED;
63
SkARGB4444_Blitter::SkARGB4444_Blitter(const SkBitmap& device, const SkPaint& paint)
66
// cache premultiplied versions in 4444
67
SkPMColor c = SkPreMultiplyColor(paint.getColor());
68
fPMColor16 = SkPixel32ToPixel4444(c);
69
if (paint.isDither()) {
70
fPMColor16Other = SkDitherPixel32To4444(c);
72
fPMColor16Other = fPMColor16;
75
// cache raw versions in 4444
76
fRawColor16 = SkPackARGB4444(0xFF >> 4, SkColorGetR(c) >> 4,
77
SkColorGetG(c) >> 4, SkColorGetB(c) >> 4);
78
if (paint.isDither()) {
79
fRawColor16Other = SkDitherARGB32To4444(0xFF, SkColorGetR(c),
80
SkColorGetG(c), SkColorGetB(c));
82
fRawColor16Other = fRawColor16;
85
// our dithered color will be the same or more opaque than the original
86
// so use dithered to compute our scale
87
SkASSERT(SkGetPackedA4444(fPMColor16Other) >= SkGetPackedA4444(fPMColor16));
89
fScale16 = SkAlpha15To16(SkGetPackedA4444(fPMColor16Other));
91
// force the original to also be opaque
92
fPMColor16 |= (0xF << SK_A4444_SHIFT);
96
const SkBitmap* SkARGB4444_Blitter::justAnOpaqueColor(uint32_t* value)
105
static void src_over_4444(SkPMColor16 dst[], SkPMColor16 color,
106
SkPMColor16 other, unsigned invScale, int count)
108
int twice = count >> 1;
109
while (--twice >= 0) {
110
*dst = color + SkAlphaMulQ4(*dst, invScale);
112
*dst = other + SkAlphaMulQ4(*dst, invScale);
116
*dst = color + SkAlphaMulQ4(*dst, invScale);
120
static inline uint32_t SkExpand_4444_Replicate(SkPMColor16 c)
122
uint32_t c32 = SkExpand_4444(c);
123
return c32 | (c32 << 4);
126
static void src_over_4444x(SkPMColor16 dst[], uint32_t color,
127
uint32_t other, unsigned invScale, int count)
129
int twice = count >> 1;
131
while (--twice >= 0) {
132
tmp = SkExpand_4444(*dst) * invScale;
133
*dst++ = SkCompact_4444((color + tmp) >> 4);
134
tmp = SkExpand_4444(*dst) * invScale;
135
*dst++ = SkCompact_4444((other + tmp) >> 4);
138
tmp = SkExpand_4444(*dst) * invScale;
139
*dst = SkCompact_4444((color + tmp) >> 4);
143
void SkARGB4444_Blitter::blitH(int x, int y, int width)
145
SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
151
SkPMColor16* device = fDevice.getAddr16(x, y);
152
SkPMColor16 color = fPMColor16;
153
SkPMColor16 other = fPMColor16Other;
156
SkTSwap<SkPMColor16>(color, other);
159
if (16 == fScale16) {
160
sk_dither_memset16(device, color, other, width);
163
src_over_4444x(device, SkExpand_4444_Replicate(color),
164
SkExpand_4444_Replicate(other),
165
16 - fScale16, width);
169
void SkARGB4444_Blitter::blitV(int x, int y, int height, SkAlpha alpha)
171
if (0 == alpha || 0 == fScale16) {
175
SkPMColor16* device = fDevice.getAddr16(x, y);
176
SkPMColor16 color = fPMColor16;
177
SkPMColor16 other = fPMColor16Other;
178
unsigned rb = fDevice.rowBytes();
181
SkTSwap<SkPMColor16>(color, other);
184
if (16 == fScale16 && 255 == alpha) {
185
while (--height >= 0) {
187
device = (SkPMColor16*)((char*)device + rb);
188
SkTSwap<SkPMColor16>(color, other);
191
unsigned alphaScale = SkAlpha255To256(alpha);
192
uint32_t c32 = SkExpand_4444(color) * (alphaScale >> 4);
193
// need to normalize the low nibble of each expanded component
194
// so we don't overflow the add with d32
195
c32 = SkCompact_4444(c32 >> 4);
196
unsigned invScale = 16 - SkAlpha15To16(SkGetPackedA4444(c32));
197
// now re-expand and replicate
198
c32 = SkExpand_4444_Replicate(c32);
200
while (--height >= 0) {
201
uint32_t d32 = SkExpand_4444(*device) * invScale;
202
*device = SkCompact_4444((c32 + d32) >> 4);
203
device = (SkPMColor16*)((char*)device + rb);
208
void SkARGB4444_Blitter::blitRect(int x, int y, int width, int height)
210
SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width() && y + height <= fDevice.height());
216
SkPMColor16* device = fDevice.getAddr16(x, y);
217
SkPMColor16 color = fPMColor16;
218
SkPMColor16 other = fPMColor16Other;
221
SkTSwap<SkPMColor16>(color, other);
224
if (16 == fScale16) {
225
while (--height >= 0) {
226
sk_dither_memset16(device, color, other, width);
227
device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
228
SkTSwap<SkPMColor16>(color, other);
231
unsigned invScale = 16 - fScale16;
233
uint32_t c32 = SkExpand_4444_Replicate(color);
234
uint32_t o32 = SkExpand_4444_Replicate(other);
235
while (--height >= 0) {
236
src_over_4444x(device, c32, o32, invScale, width);
237
device = (SkPMColor16*)((char*)device + fDevice.rowBytes());
238
SkTSwap<uint32_t>(c32, o32);
243
void SkARGB4444_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])
249
SkPMColor16* device = fDevice.getAddr16(x, y);
250
SkPMColor16 color = fPMColor16;
251
SkPMColor16 other = fPMColor16Other;
254
SkTSwap<SkPMColor16>(color, other);
259
SkASSERT(count >= 0);
264
unsigned aa = antialias[0];
267
if (16 == fScale16) {
268
sk_dither_memset16(device, color, other, count);
270
src_over_4444(device, color, other, 16 - fScale16, count);
273
// todo: respect dithering
274
aa = SkAlpha255To256(aa); // FIX
275
SkPMColor16 src = SkAlphaMulQ4(color, aa >> 4);
276
unsigned dst_scale = SkAlpha15To16(15 - SkGetPackedA4444(src)); // FIX
280
device[n] = src + SkAlphaMulQ4(device[n], dst_scale);
290
SkTSwap<SkPMColor16>(color, other);
295
//////////////////////////////////////////////////////////////////////////////////////
297
#define solid_8_pixels(mask, dst, color) \
299
if (mask & 0x80) dst[0] = color; \
300
if (mask & 0x40) dst[1] = color; \
301
if (mask & 0x20) dst[2] = color; \
302
if (mask & 0x10) dst[3] = color; \
303
if (mask & 0x08) dst[4] = color; \
304
if (mask & 0x04) dst[5] = color; \
305
if (mask & 0x02) dst[6] = color; \
306
if (mask & 0x01) dst[7] = color; \
309
#define SK_BLITBWMASK_NAME SkARGB4444_BlitBW
310
#define SK_BLITBWMASK_ARGS , SkPMColor16 color
311
#define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color)
312
#define SK_BLITBWMASK_GETADDR getAddr16
313
#define SK_BLITBWMASK_DEVTYPE uint16_t
314
#include "SkBlitBWMaskTemplate.h"
316
#define blend_8_pixels(mask, dst, sc, dst_scale) \
318
if (mask & 0x80) { dst[0] = sc + SkAlphaMulQ4(dst[0], dst_scale); } \
319
if (mask & 0x40) { dst[1] = sc + SkAlphaMulQ4(dst[1], dst_scale); } \
320
if (mask & 0x20) { dst[2] = sc + SkAlphaMulQ4(dst[2], dst_scale); } \
321
if (mask & 0x10) { dst[3] = sc + SkAlphaMulQ4(dst[3], dst_scale); } \
322
if (mask & 0x08) { dst[4] = sc + SkAlphaMulQ4(dst[4], dst_scale); } \
323
if (mask & 0x04) { dst[5] = sc + SkAlphaMulQ4(dst[5], dst_scale); } \
324
if (mask & 0x02) { dst[6] = sc + SkAlphaMulQ4(dst[6], dst_scale); } \
325
if (mask & 0x01) { dst[7] = sc + SkAlphaMulQ4(dst[7], dst_scale); } \
328
#define SK_BLITBWMASK_NAME SkARGB4444_BlendBW
329
#define SK_BLITBWMASK_ARGS , uint16_t sc, unsigned dst_scale
330
#define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, sc, dst_scale)
331
#define SK_BLITBWMASK_GETADDR getAddr16
332
#define SK_BLITBWMASK_DEVTYPE uint16_t
333
#include "SkBlitBWMaskTemplate.h"
335
void SkARGB4444_Blitter::blitMask(const SkMask& mask, const SkIRect& clip)
337
SkASSERT(mask.fBounds.contains(clip));
343
if (mask.fFormat == SkMask::kBW_Format) {
344
if (16 == fScale16) {
345
SkARGB4444_BlitBW(fDevice, mask, clip, fPMColor16);
347
SkARGB4444_BlendBW(fDevice, mask, clip, fPMColor16, 16 - fScale16);
354
int width = clip.width();
355
int height = clip.height();
357
SkPMColor16* device = fDevice.getAddr16(x, y);
358
const uint8_t* alpha = mask.getAddr(x, y);
359
SkPMColor16 srcColor = fPMColor16;
360
unsigned devRB = fDevice.rowBytes() - (width << 1);
361
unsigned maskRB = mask.fRowBytes - width;
366
unsigned aa = *alpha++;
367
*device = SkBlendARGB4444(srcColor, *device, aa);
370
device = (SkPMColor16*)((char*)device + devRB);
372
} while (--height != 0);
375
//////////////////////////////////////////////////////////////////////////////////////////
377
class SkARGB4444_Shader_Blitter : public SkShaderBlitter {
378
SkXfermode* fXfermode;
379
SkBlitRow::Proc fOpaqueProc;
380
SkBlitRow::Proc fAlphaProc;
384
SkARGB4444_Shader_Blitter(const SkBitmap& device, const SkPaint& paint)
385
: INHERITED(device, paint)
387
const int width = device.width();
388
fBuffer = (SkPMColor*)sk_malloc_throw(width * sizeof(SkPMColor) + width);
389
fAAExpand = (uint8_t*)(fBuffer + width);
391
(fXfermode = paint.getXfermode())->safeRef();
394
if (!(fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) {
395
flags |= SkBlitRow::kSrcPixelAlpha_Flag;
397
if (paint.isDither()) {
398
flags |= SkBlitRow::kDither_Flag;
400
fOpaqueProc = SkBlitRow::Factory(flags, SkBitmap::kARGB_4444_Config);
401
fAlphaProc = SkBlitRow::Factory(flags | SkBlitRow::kGlobalAlpha_Flag,
402
SkBitmap::kARGB_4444_Config);
405
virtual ~SkARGB4444_Shader_Blitter()
407
fXfermode->safeUnref();
411
virtual void blitH(int x, int y, int width)
413
SkASSERT(x >= 0 && y >= 0 && x + width <= fDevice.width());
415
SkPMColor16* device = fDevice.getAddr16(x, y);
416
SkPMColor* span = fBuffer;
418
fShader->shadeSpan(x, y, span, width);
420
fXfermode->xfer4444(device, span, width, NULL);
423
fOpaqueProc(device, span, width, 0xFF, x, y);
427
virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[])
429
SkPMColor* SK_RESTRICT span = fBuffer;
430
uint8_t* SK_RESTRICT aaExpand = fAAExpand;
431
SkPMColor16* device = fDevice.getAddr16(x, y);
432
SkShader* shader = fShader;
433
SkXfermode* xfer = fXfermode;
442
shader->shadeSpan(x, y, span, count);
444
xfer->xfer4444(device, span, count, NULL);
446
const uint8_t* aaBuffer = antialias;
448
memset(aaExpand, aa, count);
451
xfer->xfer4444(device, span, count, aaBuffer);
459
} else { // no xfermode
466
fShader->shadeSpan(x, y, span, count);
468
fOpaqueProc(device, span, count, aa, x, y);
470
fAlphaProc(device, span, count, aa, x, y);
482
typedef SkShaderBlitter INHERITED;
485
///////////////////////////////////////////////////////////////////////////////
486
///////////////////////////////////////////////////////////////////////////////
488
SkBlitter* SkBlitter_ChooseD4444(const SkBitmap& device,
489
const SkPaint& paint,
490
void* storage, size_t storageSize)
494
if (paint.getShader()) {
495
SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Shader_Blitter, storage, storageSize, (device, paint));
497
SK_PLACEMENT_NEW_ARGS(blitter, SkARGB4444_Blitter, storage, storageSize, (device, paint));