diff options
Diffstat (limited to 'libs/graphics/sgl/SkBlitter_RGB16.cpp')
-rw-r--r-- | libs/graphics/sgl/SkBlitter_RGB16.cpp | 674 |
1 files changed, 674 insertions, 0 deletions
diff --git a/libs/graphics/sgl/SkBlitter_RGB16.cpp b/libs/graphics/sgl/SkBlitter_RGB16.cpp new file mode 100644 index 0000000000..56b2b419f2 --- /dev/null +++ b/libs/graphics/sgl/SkBlitter_RGB16.cpp @@ -0,0 +1,674 @@ +#include "SkCoreBlitters.h" +#include "SkColorPriv.h" +#include "SkShader.h" +#include "SkUtils.h" +#include "SkXfermode.h" + +#ifdef SK_DEBUG + static unsigned RGB16Add(U16CPU a, U16CPU b) + { + SkASSERT(SkGetPackedR16(a) + SkGetPackedR16(b) <= SK_R16_MASK); + SkASSERT(SkGetPackedG16(a) + SkGetPackedG16(b) <= SK_G16_MASK); + SkASSERT(SkGetPackedB16(a) + SkGetPackedB16(b) <= SK_B16_MASK); + + return a + b; + } +#else + #define RGB16Add(a, b) (a + b) +#endif + +#if 1 +#define black_8_pixels(mask, dst) \ + do { \ + if (mask & 0x80) dst[0] = 0; \ + if (mask & 0x40) dst[1] = 0; \ + if (mask & 0x20) dst[2] = 0; \ + if (mask & 0x10) dst[3] = 0; \ + if (mask & 0x08) dst[4] = 0; \ + if (mask & 0x04) dst[5] = 0; \ + if (mask & 0x02) dst[6] = 0; \ + if (mask & 0x01) dst[7] = 0; \ + } while (0) +#else +static inline black_8_pixels(U8CPU mask, U16 dst[]) +{ + if (mask & 0x80) dst[0] = 0; + if (mask & 0x40) dst[1] = 0; + if (mask & 0x20) dst[2] = 0; + if (mask & 0x10) dst[3] = 0; + if (mask & 0x08) dst[4] = 0; + if (mask & 0x04) dst[5] = 0; + if (mask & 0x02) dst[6] = 0; + if (mask & 0x01) dst[7] = 0; +} +#endif + +#define SK_BLITBWMASK_NAME SkRGB16_Black_BlitBW +#define SK_BLITBWMASK_ARGS +#define SK_BLITBWMASK_BLIT8(mask, dst) black_8_pixels(mask, dst) +#define SK_BLITBWMASK_GETADDR getAddr16 +#define SK_BLITBWMASK_DEVTYPE U16 +#include "SkBlitBWMaskTemplate.h" + +void SkRGB16_Black_Blitter::blitMask(const SkMask& mask, const SkRect16& clip) +{ + if (mask.fFormat == SkMask::kBW_Format) + { + SkRGB16_Black_BlitBW(fDevice, mask, clip); + } + else + { + U16* device = fDevice.getAddr16(clip.fLeft, clip.fTop); + const U8* alpha = mask.getAddr(clip.fLeft, clip.fTop); + unsigned width = clip.width(); + unsigned height = clip.height(); + unsigned deviceRB = fDevice.rowBytes() - (width << 1); + unsigned maskRB = mask.fRowBytes - width; + + SkASSERT((int)height > 0); + SkASSERT((int)width > 0); + SkASSERT((int)deviceRB >= 0); + SkASSERT((int)maskRB >= 0); + + do { + unsigned w = width; + do { + unsigned aa = *alpha++; + if (aa) + { + if (aa == 255) + *device = 0; + else + *device = SkToU16(SkAlphaMulRGB16(*device, SkAlpha255To256(255 - aa))); + } + device += 1; + } while (--w != 0); + device = (U16*)((char*)device + deviceRB); + alpha += maskRB; + } while (--height != 0); + } +} + +////////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////////////////// + +SkRGB16_Blitter::SkRGB16_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device) +{ + U32 color = paint.getColor(); + + fScale = SkAlpha255To256(SkColorGetA(color)); + + fRawColor16 = SkPackRGB16( SkColorGetR(color) >> (8 - SK_R16_BITS), + SkColorGetG(color) >> (8 - SK_G16_BITS), + SkColorGetB(color) >> (8 - SK_B16_BITS)); + + fColor16 = SkPackRGB16( SkAlphaMul(SkColorGetR(color), fScale) >> (8 - SK_R16_BITS), + SkAlphaMul(SkColorGetG(color), fScale) >> (8 - SK_G16_BITS), + SkAlphaMul(SkColorGetB(color), fScale) >> (8 - SK_B16_BITS)); +} + +void SkRGB16_Blitter::blitH(int x, int y, int width) +{ + SkASSERT(width > 0); + SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width()); + + if (fScale == 0) + return; + + U16* device = fDevice.getAddr16(x, y); + unsigned srcColor = fColor16; + + if (fScale == 256) + { + sk_memset16(device, srcColor, width); + } + else + { + unsigned scale = 256 - fScale; + do { + *device = (U16)RGB16Add(srcColor, SkAlphaMulRGB16(*device, scale)); + device += 1; + } while (--width != 0); + } +} + +void SkRGB16_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]) +{ + if (fScale == 0) + return; + + U16* device = fDevice.getAddr16(x, y); + U16 srcColor = fColor16; + unsigned scale = fScale; + + if (scale == 256) + { + for (;;) + { + int count = runs[0]; + SkASSERT(count >= 0); + if (count == 0) + return; + runs += count; + + unsigned aa = antialias[0]; + antialias += count; + if (aa) + { + if (aa == 255) + { + sk_memset16(device, srcColor, count); + } + else + { + unsigned src = SkAlphaMulRGB16(srcColor, SkAlpha255To256(aa)); + unsigned dst_scale = SkAlpha255To256(255 - aa); + do { + *device = (U16)RGB16Add(src, SkAlphaMulRGB16(*device, dst_scale)); + device += 1; + } while (--count != 0); + continue; + } + } + device += count; + } + } + else + { + for (;;) + { + int count = runs[0]; + SkASSERT(count >= 0); + if (count == 0) + return; + runs += count; + + unsigned aa = antialias[0]; + antialias += count; + if (aa) + { + unsigned src = SkAlphaMulRGB16(srcColor, SkAlpha255To256(aa)); + unsigned dst_scale = SkAlpha255To256(255 - SkAlphaMul(aa, scale)); + do { + *device = (U16)RGB16Add(src, SkAlphaMulRGB16(*device, dst_scale)); + device += 1; + } while (--count != 0); + continue; + } + device += count; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////// + +#define solid_8_pixels(mask, dst, color) \ + do { \ + if (mask & 0x80) dst[0] = color; \ + if (mask & 0x40) dst[1] = color; \ + if (mask & 0x20) dst[2] = color; \ + if (mask & 0x10) dst[3] = color; \ + if (mask & 0x08) dst[4] = color; \ + if (mask & 0x04) dst[5] = color; \ + if (mask & 0x02) dst[6] = color; \ + if (mask & 0x01) dst[7] = color; \ + } while (0) + +#define SK_BLITBWMASK_NAME SkRGB16_BlitBW +#define SK_BLITBWMASK_ARGS , U16 color +#define SK_BLITBWMASK_BLIT8(mask, dst) solid_8_pixels(mask, dst, color) +#define SK_BLITBWMASK_GETADDR getAddr16 +#define SK_BLITBWMASK_DEVTYPE U16 +#include "SkBlitBWMaskTemplate.h" + +static inline void blend_8_pixels(U8CPU bw, U16 dst[], unsigned dst_scale, U16CPU srcColor) +{ + if (bw & 0x80) dst[0] = SkToU16(srcColor + SkAlphaMulRGB16(dst[0], dst_scale)); + if (bw & 0x40) dst[1] = SkToU16(srcColor + SkAlphaMulRGB16(dst[1], dst_scale)); + if (bw & 0x20) dst[2] = SkToU16(srcColor + SkAlphaMulRGB16(dst[2], dst_scale)); + if (bw & 0x10) dst[3] = SkToU16(srcColor + SkAlphaMulRGB16(dst[3], dst_scale)); + if (bw & 0x08) dst[4] = SkToU16(srcColor + SkAlphaMulRGB16(dst[4], dst_scale)); + if (bw & 0x04) dst[5] = SkToU16(srcColor + SkAlphaMulRGB16(dst[5], dst_scale)); + if (bw & 0x02) dst[6] = SkToU16(srcColor + SkAlphaMulRGB16(dst[6], dst_scale)); + if (bw & 0x01) dst[7] = SkToU16(srcColor + SkAlphaMulRGB16(dst[7], dst_scale)); +} + +#define SK_BLITBWMASK_NAME SkRGB16_BlendBW +#define SK_BLITBWMASK_ARGS , unsigned dst_scale, U16CPU src_color +#define SK_BLITBWMASK_BLIT8(mask, dst) blend_8_pixels(mask, dst, dst_scale, src_color) +#define SK_BLITBWMASK_GETADDR getAddr16 +#define SK_BLITBWMASK_DEVTYPE U16 +#include "SkBlitBWMaskTemplate.h" + +void SkRGB16_Blitter::blitMask(const SkMask& mask, const SkRect16& clip) +{ + if (fScale == 0) + return; + + if (mask.fFormat == SkMask::kBW_Format) + { + if (fScale == 256) + SkRGB16_BlitBW(fDevice, mask, clip, fColor16); + else + SkRGB16_BlendBW(fDevice, mask, clip, 256 - fScale, fColor16); + return; + } + + U16* device = fDevice.getAddr16(clip.fLeft, clip.fTop); + const U8* alpha = mask.getAddr(clip.fLeft, clip.fTop); + int width = clip.width(); + int height = clip.height(); + unsigned maskRB = mask.fRowBytes; + U16 color16 = fRawColor16; + unsigned scale = fScale; + unsigned deviceRB = fDevice.rowBytes(); + + if (scale == 256) + { + while (--height >= 0) + { + for (int i = width - 1; i >= 0; --i) + { + unsigned aa = alpha[i]; + if (aa) + { + if (aa == 255) + device[i] = color16; + else + { + unsigned src_scale = SkAlpha255To256(aa); + unsigned dst_scale = SkAlpha255To256(255 - aa); + device[i] = (U16)RGB16Add(SkAlphaMulRGB16(color16, src_scale), SkAlphaMulRGB16(device[i], dst_scale)); + } + } + } + device = (U16*)((char*)device + deviceRB); + alpha += maskRB; + } + } + else // scale < 256 + { + while (--height >= 0) + { + for (int i = width - 1; i >= 0; --i) + { + unsigned aa = alpha[i]; + if (aa) + { + aa = SkAlphaMul(aa, scale); + unsigned src_scale = SkAlpha255To256(aa); + unsigned dst_scale = SkAlpha255To256(255 - aa); + device[i] = (U16)RGB16Add(SkAlphaMulRGB16(color16, src_scale), SkAlphaMulRGB16(device[i], dst_scale)); + } + } + device = (U16*)((char*)device + deviceRB); + alpha += maskRB; + } + } +} + +void SkRGB16_Blitter::blitV(int x, int y, int height, SkAlpha alpha) +{ + if (fScale == 0) + return; + + U16* device = fDevice.getAddr16(x, y); + U16 color16 = fColor16; + unsigned deviceRB = fDevice.rowBytes(); + + if (alpha + fScale == (255 + 256)) + { + do { + device[0] = color16; + device = (U16*)((char*)device + deviceRB); + } while (--height != 0); + } + else + { + unsigned scale = fScale; + + if (alpha < 255) + { + scale = SkAlphaMul(alpha, scale); + color16 = SkToU16(SkAlphaMulRGB16(fRawColor16, scale)); + } + scale = 256 - scale; + do { + *device = (U16)RGB16Add(color16, SkAlphaMulRGB16(device[0], scale)); + device = (U16*)((char*)device + deviceRB); + } while (--height != 0); + } +} + +void SkRGB16_Blitter::blitRect(int x, int y, int width, int height) +{ + SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width() && (unsigned)(y + height) <= fDevice.height()); + + if (fScale == 0) + return; + + U16* device = fDevice.getAddr16(x, y); + unsigned deviceRB = fDevice.rowBytes(); + U16 color16 = fColor16; + + if (fScale == 256) + { + while (--height >= 0) + { + sk_memset16(device, color16, width); + device = (U16*)((char*)device + deviceRB); + } + } + else + { + unsigned dst_scale = 256 - fScale; // apply it to the dst + + while (--height >= 0) + { + for (int i = width - 1; i >= 0; --i) + device[i] = SkToU16(color16 + SkAlphaMulRGB16(device[i], dst_scale)); + device = (U16*)((char*)device + deviceRB); + } + } +} + +/////////////////////////////////////////////////////////////////////// + +#define BLEND_32_TO_16(srcA, src, dst) \ + SkToU16(SkPixel32ToPixel16(src) + SkAlphaMulRGB16(dst, 256 - SkAlpha255To256(srcA))) + +SkRGB16_Shader_Blitter::SkRGB16_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device) +{ + SkASSERT(paint.getXfermode() == NULL); + + fShader = paint.getShader(); + SkASSERT(fShader); + fShader->ref(); + + SkAutoUnref autoUnref(fShader); + fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * sizeof(SkPMColor)); + (void)autoUnref.detach(); +} + +SkRGB16_Shader_Blitter::~SkRGB16_Shader_Blitter() +{ + fShader->unref(); + sk_free(fBuffer); +} + +void SkRGB16_Shader_Blitter::blitH(int x, int y, int width) +{ + SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width()); + + U16* device = fDevice.getAddr16(x, y); + U32 flags = fShader->getFlags(); + + if (SkShader::CanCallShadeSpanOpaque16(flags)) + { + fShader->shadeSpanOpaque16(x, y, device, width); + return; + } + + // If we get here, we know we need the 32bit answer from the shader + + SkPMColor* span = fBuffer; + + fShader->shadeSpan(x, y, span, width); + if (flags & SkShader::kOpaqueAlpha_Flag) + { + for (int i = width - 1; i >= 0; --i) + device[i] = SkPixel32ToPixel16_ToU16(span[i]); + } + else + { + for (int i = 0; i < width; i++) + { + U32 src = span[i]; + if (src) + { + unsigned srcA = SkGetPackedA32(src); + if (srcA == 0xFF) + device[i] = SkPixel32ToPixel16_ToU16(src); + else + device[i] = BLEND_32_TO_16(srcA, src, device[i]); + } + } + } +} + +static inline U16 aa_blendS32D16(U32 src, U16CPU dst, int aa) +{ + SkASSERT((unsigned)aa <= 255); + + int src_scale = SkAlpha255To256(aa); + int sa = SkGetPackedA32(src); + int dst_scale = SkAlpha255To256(255 - SkAlphaMul(sa, src_scale)); + + int dr = (SkPacked32ToR16(src) * src_scale + SkGetPackedR16(dst) * dst_scale) >> 8; + int dg = (SkPacked32ToG16(src) * src_scale + SkGetPackedG16(dst) * dst_scale) >> 8; + int db = (SkPacked32ToB16(src) * src_scale + SkGetPackedB16(dst) * dst_scale) >> 8; + + return SkPackRGB16(dr, dg, db); +} + +static inline int count_nonzero_span(const S16 runs[], const SkAlpha aa[]) +{ + int count = 0; + for (;;) + { + int n = *runs; + if (n == 0 || *aa == 0) + break; + runs += n; + aa += n; + count += n; + } + return count; +} + +void SkRGB16_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]) +{ +// aa_blendS32D16(0xd4d4d49c, 65526, 238); + + SkASSERT(x >= 0 && y >= 0 && x < (int)fDevice.width() && y < (int)fDevice.height()); + + SkShader* shader = fShader; + SkPMColor* span = fBuffer; + U16* device = fDevice.getAddr16(x, y); + U32 flags = fShader->getFlags(); + + if (SkShader::CanCallShadeSpanOpaque16(flags)) + { + U16* span16 = (U16*)span; + for (;;) + { + int count = *runs; + if (count == 0) + break; + + int aa = *antialias; + if (aa == 255) + shader->shadeSpanOpaque16(x, y, device, count); + else if (aa) + { + unsigned scale = SkAlpha255To256(aa); + shader->shadeSpanOpaque16(x, y, span16, count); + for (int i = 0; i < count; i++) + device[i] = SkToU16(SkBlendRGB16(span16[i], device[i], scale)); + } + device += count; + runs += count; + antialias += count; + x += count; + } + return; + } + + // If we get here, take the 32bit shadeSpan case + + int opaque = flags & SkShader::kOpaqueAlpha_Flag; + + for (;;) + { + int count = *runs; + if (count == 0) + break; + + int aa = *antialias; + if (aa == 0) + { + device += count; + runs += count; + antialias += count; + x += count; + continue; + } + + int nonZeroCount = count + count_nonzero_span(runs + count, antialias + count); + + shader->shadeSpan(x, y, span, nonZeroCount); + x += nonZeroCount; + SkPMColor* localSpan = span; + for (;;) + { + if (aa == 255) // no antialiasing + { + if (opaque) + { + for (int i = 0; i < count; i++) + device[i] = SkPixel32ToPixel16_ToU16(localSpan[i]); + } + else + { + for (int i = 0; i < count; i++) + { + U32 src = localSpan[i]; + if (src) + { + unsigned srcA = SkGetPackedA32(src); + if (srcA == 0xFF) + device[i] = SkPixel32ToPixel16_ToU16(src); + else + device[i] = BLEND_32_TO_16(srcA, src, device[i]); + } + } + } + } + else + { + for (int i = 0; i < count; i++) + { + if (localSpan[i]) + device[i] = aa_blendS32D16(localSpan[i], device[i], aa); + } + } + + device += count; + runs += count; + antialias += count; + nonZeroCount -= count; + if (nonZeroCount == 0) + break; + + localSpan += count; + SkASSERT(nonZeroCount > 0); + count = *runs; + SkASSERT(count > 0); + aa = *antialias; + } + } +} + +/////////////////////////////////////////////////////////////////////// + +SkRGB16_Shader_Xfermode_Blitter::SkRGB16_Shader_Xfermode_Blitter(const SkBitmap& device, const SkPaint& paint) : fDevice(device) +{ + fShader = paint.getShader(); + SkASSERT(fShader); + fShader->ref(); + + fXfermode = paint.getXfermode(); + SkASSERT(fXfermode); + fXfermode->ref(); + + int width = device.width(); + fBuffer = (SkPMColor*)sk_malloc_throw((width + (SkAlign4(width) >> 2)) * sizeof(SkPMColor)); + fAAExpand = (U8*)(fBuffer + width); +} + +SkRGB16_Shader_Xfermode_Blitter::~SkRGB16_Shader_Xfermode_Blitter() +{ + fXfermode->unref(); + fShader->unref(); + sk_free(fBuffer); +} + +void SkRGB16_Shader_Xfermode_Blitter::blitH(int x, int y, int width) +{ + SkASSERT(x >= 0 && y >= 0 && (unsigned)(x + width) <= fDevice.width()); + + U16* device = fDevice.getAddr16(x, y); + SkPMColor* span = fBuffer; + + fShader->shadeSpan(x, y, span, width); + fXfermode->xfer16(device, span, width, NULL); +} + +void SkRGB16_Shader_Xfermode_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const S16 runs[]) +{ + SkASSERT(x >= 0 && y >= 0 && x < (int)fDevice.width() && y < (int)fDevice.height()); + + SkShader* shader = fShader; + SkXfermode* mode = fXfermode; + SkPMColor* span = fBuffer; + U8* aaExpand = fAAExpand; + U16* device = fDevice.getAddr16(x, y); + + for (;;) + { + int count = *runs; + if (count == 0) + break; + + int aa = *antialias; + if (aa == 0) + { + device += count; + runs += count; + antialias += count; + x += count; + continue; + } + + int nonZeroCount = count + count_nonzero_span(runs + count, antialias + count); + + shader->shadeSpan(x, y, span, nonZeroCount); + x += nonZeroCount; + SkPMColor* localSpan = span; + for (;;) + { + if (aa == 0xFF) + mode->xfer16(device, localSpan, count, NULL); + else + { + SkASSERT(aa); + memset(aaExpand, aa, count); + mode->xfer16(device, localSpan, count, aaExpand); + } + device += count; + runs += count; + antialias += count; + nonZeroCount -= count; + if (nonZeroCount == 0) + break; + + localSpan += count; + SkASSERT(nonZeroCount > 0); + count = *runs; + SkASSERT(count > 0); + aa = *antialias; + } + } +} + + |