diff options
author | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-10-18 13:56:50 +0000 |
---|---|---|
committer | reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2011-10-18 13:56:50 +0000 |
commit | edb606cb999887d54629f361bcbf57c5fede1bb0 (patch) | |
tree | 60ec20fa1b2814dc1d292b6de9f1f299399e1de5 /src/core/SkBlitMask_D32.cpp | |
parent | 095186a466f92b871c8ef8385246405426a67adb (diff) |
move LCD blits into opts, so they can have assembly versions
git-svn-id: http://skia.googlecode.com/svn/trunk@2484 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkBlitMask_D32.cpp')
-rw-r--r-- | src/core/SkBlitMask_D32.cpp | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/src/core/SkBlitMask_D32.cpp b/src/core/SkBlitMask_D32.cpp new file mode 100644 index 0000000000..45d2d119a9 --- /dev/null +++ b/src/core/SkBlitMask_D32.cpp @@ -0,0 +1,384 @@ +#include "SkBlitMask.h" +#include "SkColor.h" +#include "SkColorPriv.h" + +static void D32_A8_Color(void* SK_RESTRICT dst, size_t dstRB, + const void* SK_RESTRICT maskPtr, size_t maskRB, + SkColor color, int width, int height) { + SkPMColor pmc = SkPreMultiplyColor(color); + size_t dstOffset = dstRB - (width << 2); + size_t maskOffset = maskRB - width; + SkPMColor* SK_RESTRICT device = (SkPMColor *)dst; + const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr; + + do { + int w = width; + do { + unsigned aa = *mask++; + *device = SkBlendARGB32(pmc, *device, aa); + device += 1; + } while (--w != 0); + device = (uint32_t*)((char*)device + dstOffset); + mask += maskOffset; + } while (--height != 0); +} + +static void D32_A8_Opaque(void* SK_RESTRICT dst, size_t dstRB, + const void* SK_RESTRICT maskPtr, size_t maskRB, + SkColor color, int width, int height) { + SkPMColor pmc = SkPreMultiplyColor(color); + SkPMColor* SK_RESTRICT device = (SkPMColor*)dst; + const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr; + + maskRB -= width; + dstRB -= (width << 2); + do { + int w = width; + do { + unsigned aa = *mask++; + *device = SkAlphaMulQ(pmc, SkAlpha255To256(aa)) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); + device += 1; + } while (--w != 0); + device = (uint32_t*)((char*)device + dstRB); + mask += maskRB; + } while (--height != 0); +} + +static void D32_A8_Black(void* SK_RESTRICT dst, size_t dstRB, + const void* SK_RESTRICT maskPtr, size_t maskRB, + SkColor, int width, int height) { + SkPMColor* SK_RESTRICT device = (SkPMColor*)dst; + const uint8_t* SK_RESTRICT mask = (const uint8_t*)maskPtr; + + maskRB -= width; + dstRB -= (width << 2); + do { + int w = width; + do { + unsigned aa = *mask++; + *device = (aa << SK_A32_SHIFT) + SkAlphaMulQ(*device, SkAlpha255To256(255 - aa)); + device += 1; + } while (--w != 0); + device = (uint32_t*)((char*)device + dstRB); + mask += maskRB; + } while (--height != 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +static inline int upscale31To32(int value) { + SkASSERT((unsigned)value <= 31); + return value + (value >> 4); +} + +static inline int blend32(int src, int dst, int scale) { + SkASSERT((unsigned)src <= 0xFF); + SkASSERT((unsigned)dst <= 0xFF); + SkASSERT((unsigned)scale <= 32); + return dst + ((src - dst) * scale >> 5); +} + +static void blit_lcd16_row(SkPMColor dst[], const uint16_t src[], + SkColor color, int width, SkPMColor) { + int srcA = SkColorGetA(color); + int srcR = SkColorGetR(color); + int srcG = SkColorGetG(color); + int srcB = SkColorGetB(color); + + srcA = SkAlpha255To256(srcA); + + for (int i = 0; i < width; i++) { + uint16_t mask = src[i]; + if (0 == mask) { + continue; + } + + SkPMColor d = dst[i]; + + /* We want all of these in 5bits, hence the shifts in case one of them + * (green) is 6bits. + */ + int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5); + int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5); + int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5); + + // Now upscale them to 0..32, so we can use blend32 + maskR = upscale31To32(maskR); + maskG = upscale31To32(maskG); + maskB = upscale31To32(maskB); + + maskR = maskR * srcA >> 8; + maskG = maskG * srcA >> 8; + maskB = maskB * srcA >> 8; + + int dstR = SkGetPackedR32(d); + int dstG = SkGetPackedG32(d); + int dstB = SkGetPackedB32(d); + + // LCD blitting is only supported if the dst is known/required\ + // to be opaque + dst[i] = SkPackARGB32(0xFF, + blend32(srcR, dstR, maskR), + blend32(srcG, dstG, maskG), + blend32(srcB, dstB, maskB)); + } +} + +static void blit_lcd16_opaque_row(SkPMColor dst[], const uint16_t src[], + SkColor color, int width, SkPMColor opaqueDst) { + int srcR = SkColorGetR(color); + int srcG = SkColorGetG(color); + int srcB = SkColorGetB(color); + + for (int i = 0; i < width; i++) { + uint16_t mask = src[i]; + if (0 == mask) { + continue; + } + if (0xFFFF == mask) { + dst[i] = opaqueDst; + continue; + } + + SkPMColor d = dst[i]; + + /* We want all of these in 5bits, hence the shifts in case one of them + * (green) is 6bits. + */ + int maskR = SkGetPackedR16(mask) >> (SK_R16_BITS - 5); + int maskG = SkGetPackedG16(mask) >> (SK_G16_BITS - 5); + int maskB = SkGetPackedB16(mask) >> (SK_B16_BITS - 5); + + // Now upscale them to 0..32, so we can use blend32 + maskR = upscale31To32(maskR); + maskG = upscale31To32(maskG); + maskB = upscale31To32(maskB); + + int dstR = SkGetPackedR32(d); + int dstG = SkGetPackedG32(d); + int dstB = SkGetPackedB32(d); + + // LCD blitting is only supported if the dst is known/required + // to be opaque + dst[i] = SkPackARGB32(0xFF, + blend32(srcR, dstR, maskR), + blend32(srcG, dstG, maskG), + blend32(srcB, dstB, maskB)); + } +} + +static void D32_LCD16_Proc(void* SK_RESTRICT dst, size_t dstRB, + const void* SK_RESTRICT mask, size_t maskRB, + SkColor color, int width, int height) { + + SkPMColor* dstRow = (SkPMColor*)dst; + const uint16_t* srcRow = (const uint16_t*)mask; + SkPMColor opaqueDst; + + void (*proc)(SkPMColor dst[], const uint16_t src[], + SkColor color, int width, SkPMColor); + if (0xFF == SkColorGetA(color)) { + proc = blit_lcd16_opaque_row; + opaqueDst = SkPreMultiplyColor(color); + } else { + proc = blit_lcd16_row; + opaqueDst = 0; // ignored + } + + do { + proc(dstRow, srcRow, color, width, opaqueDst); + dstRow = (SkPMColor*)((char*)dstRow + dstRB); + srcRow = (const uint16_t*)((const char*)srcRow + maskRB); + } while (--height != 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +static void blit_lcd32_opaque_row(SkPMColor* SK_RESTRICT dst, + const SkPMColor* SK_RESTRICT src, + SkColor color, int width) { + int srcR = SkColorGetR(color); + int srcG = SkColorGetG(color); + int srcB = SkColorGetB(color); + + for (int i = 0; i < width; i++) { + SkPMColor mask = src[i]; + if (0 == mask) { + continue; + } + + SkPMColor d = dst[i]; + + int maskR = SkGetPackedR32(mask); + int maskG = SkGetPackedG32(mask); + int maskB = SkGetPackedB32(mask); + + // Now upscale them to 0..256, so we can use SkAlphaBlend + maskR = SkAlpha255To256(maskR); + maskG = SkAlpha255To256(maskG); + maskB = SkAlpha255To256(maskB); + + int dstR = SkGetPackedR32(d); + int dstG = SkGetPackedG32(d); + int dstB = SkGetPackedB32(d); + + // LCD blitting is only supported if the dst is known/required + // to be opaque + dst[i] = SkPackARGB32(0xFF, + SkAlphaBlend(srcR, dstR, maskR), + SkAlphaBlend(srcG, dstG, maskG), + SkAlphaBlend(srcB, dstB, maskB)); + } +} + +static void blit_lcd32_row(SkPMColor* SK_RESTRICT dst, + const SkPMColor* SK_RESTRICT src, + SkColor color, int width) { + int srcA = SkColorGetA(color); + int srcR = SkColorGetR(color); + int srcG = SkColorGetG(color); + int srcB = SkColorGetB(color); + + srcA = SkAlpha255To256(srcA); + + for (int i = 0; i < width; i++) { + SkPMColor mask = src[i]; + if (0 == mask) { + continue; + } + + SkPMColor d = dst[i]; + + int maskR = SkGetPackedR32(mask); + int maskG = SkGetPackedG32(mask); + int maskB = SkGetPackedB32(mask); + + // Now upscale them to 0..256, so we can use SkAlphaBlend + maskR = SkAlpha255To256(maskR); + maskG = SkAlpha255To256(maskG); + maskB = SkAlpha255To256(maskB); + + maskR = maskR * srcA >> 8; + maskG = maskG * srcA >> 8; + maskB = maskB * srcA >> 8; + + int dstR = SkGetPackedR32(d); + int dstG = SkGetPackedG32(d); + int dstB = SkGetPackedB32(d); + + // LCD blitting is only supported if the dst is known/required + // to be opaque + dst[i] = SkPackARGB32(0xFF, + SkAlphaBlend(srcR, dstR, maskR), + SkAlphaBlend(srcG, dstG, maskG), + SkAlphaBlend(srcB, dstB, maskB)); + } +} + +static void D32_LCD32_Blend(void* SK_RESTRICT dst, size_t dstRB, + const void* SK_RESTRICT mask, size_t maskRB, + SkColor color, int width, int height) { + SkASSERT(height > 0); + SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst; + const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask; + + do { + blit_lcd32_row(dstRow, srcRow, color, width); + dstRow = (SkPMColor*)((char*)dstRow + dstRB); + srcRow = (const SkPMColor*)((const char*)srcRow + maskRB); + } while (--height != 0); +} + +static void D32_LCD32_Opaque(void* SK_RESTRICT dst, size_t dstRB, + const void* SK_RESTRICT mask, size_t maskRB, + SkColor color, int width, int height) { + SkASSERT(height > 0); + SkPMColor* SK_RESTRICT dstRow = (SkPMColor*)dst; + const SkPMColor* SK_RESTRICT srcRow = (const SkPMColor*)mask; + + do { + blit_lcd32_opaque_row(dstRow, srcRow, color, width); + dstRow = (SkPMColor*)((char*)dstRow + dstRB); + srcRow = (const SkPMColor*)((const char*)srcRow + maskRB); + } while (--height != 0); +} + +/////////////////////////////////////////////////////////////////////////////// + +static SkBlitMask::Proc D32_A8_Factory(SkColor color) { + if (SK_ColorBLACK == color) { + return D32_A8_Black; + } else if (0xFF == SkColorGetA(color)) { + return D32_A8_Opaque; + } else { + return D32_A8_Color; + } +} + +static SkBlitMask::Proc D32_LCD32_Factory(SkColor color) { + return (0xFF == SkColorGetA(color)) ? D32_LCD32_Opaque : D32_LCD32_Blend; +} + +SkBlitMask::Proc SkBlitMask::Factory(SkBitmap::Config config, + SkMask::Format format, SkColor color) { + SkBlitMask::Proc proc = PlatformProcs(config, format, color); + if (proc) { + return proc; + } + + switch (config) { + case SkBitmap::kARGB_8888_Config: + switch (format) { + case SkMask::kA8_Format: + return D32_A8_Factory(color); + case SkMask::kLCD16_Format: + return D32_LCD16_Proc; + case SkMask::kLCD32_Format: + return D32_LCD32_Factory(color); + } + break; + default: + break; + } + return NULL; +} + +static const int gMaskFormatToShift[] = { + ~0, // BW + 0, // A8 + 0, // 3D + 2, // ARGB32 + 1, // LCD16 + 2 // LCD32 +}; + +static int maskFormatToShift(SkMask::Format format) { + SkASSERT((unsigned)format < SK_ARRAY_COUNT(gMaskFormatToShift)); + SkASSERT(SkMask::kBW_Format != format); + return gMaskFormatToShift[format]; +} + +static const void* getAddr(const SkMask& mask, int x, int y) { + SkASSERT(mask.fBounds.contains(x, y)); + SkASSERT(mask.fImage); + + const char* addr = (const char*)mask.fImage; + addr += (y - mask.fBounds.fTop) * mask.fRowBytes; + addr += (x - mask.fBounds.fLeft) << maskFormatToShift(mask.fFormat); + return addr; +} + +bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask, + const SkIRect& clip, SkColor color) { + Proc proc = Factory(device.config(), mask.fFormat, color); + if (proc) { + int x = clip.fLeft; + int y = clip.fTop; + proc(device.getAddr32(x, y), device.rowBytes(), getAddr(mask, x, y), + mask.fRowBytes, color, clip.width(), clip.height()); + return true; + } + return false; +} + + |