diff options
author | 2011-11-15 19:51:02 +0000 | |
---|---|---|
committer | 2011-11-15 19:51:02 +0000 | |
commit | 1750bf17635e788198200f971d9cb66f67399363 (patch) | |
tree | b397330b4f71c6cd08d161e9264396dbd17b99b3 /src | |
parent | f7b5c1ebfdad1a77d301d1676235e79f8006883e (diff) |
support blitMask+shader natively (1.75x faster for AA, and now we can support
LCD at all with a shader.)
git-svn-id: http://skia.googlecode.com/svn/trunk@2689 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkBlitMask.h | 18 | ||||
-rw-r--r-- | src/core/SkBlitMask_D32.cpp | 308 | ||||
-rw-r--r-- | src/core/SkBlitter_ARGB32.cpp | 62 | ||||
-rw-r--r-- | src/core/SkCoreBlitters.h | 1 | ||||
-rw-r--r-- | src/core/SkDevice.cpp | 13 | ||||
-rw-r--r-- | src/opts/SkBlitRow_opts_none.cpp | 15 | ||||
-rw-r--r-- | src/opts/opts_check_SSE2.cpp | 3 |
7 files changed, 401 insertions, 19 deletions
diff --git a/src/core/SkBlitMask.h b/src/core/SkBlitMask.h index 66687a9c29..299f6d1e5c 100644 --- a/src/core/SkBlitMask.h +++ b/src/core/SkBlitMask.h @@ -45,22 +45,26 @@ public: static ColorProc ColorFactory(SkBitmap::Config, SkMask::Format, SkColor); /** - * Public entry-point to return a blitmask RowProc. - * May return NULL if config or format are not supported. - */ - static RowProc RowFactory(SkBitmap::Config, SkMask::Format); - - /** * Return either platform specific optimized blitmask ColorProc, * or NULL if no optimized routine is available. */ static ColorProc PlatformColorProcs(SkBitmap::Config, SkMask::Format, SkColor); + + enum RowFlags { + kSrcIsOpaque_RowFlag = 1 << 0 + }; + + /** + * Public entry-point to return a blitmask RowProc. + * May return NULL if config or format are not supported. + */ + static RowProc RowFactory(SkBitmap::Config, SkMask::Format, RowFlags); /** * Return either platform specific optimized blitmask RowProc, * or NULL if no optimized routine is available. */ - static RowProc PlatformRowProcs(SkBitmap::Config, SkMask::Format); + static RowProc PlatformRowProcs(SkBitmap::Config, SkMask::Format, RowFlags); }; #endif diff --git a/src/core/SkBlitMask_D32.cpp b/src/core/SkBlitMask_D32.cpp index 356f285fec..81522ff591 100644 --- a/src/core/SkBlitMask_D32.cpp +++ b/src/core/SkBlitMask_D32.cpp @@ -359,4 +359,312 @@ bool SkBlitMask::BlitColor(const SkBitmap& device, const SkMask& mask, return false; } +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +static void BW_RowProc_Blend(SkPMColor* SK_RESTRICT dst, + const uint8_t* SK_RESTRICT mask, + const SkPMColor* SK_RESTRICT src, int count) { + int i, octuple = (count + 7) >> 3; + for (i = 0; i < octuple; ++i) { + int m = *mask++; + if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } + if (m & 0x40) { dst[1] = SkPMSrcOver(src[1], dst[1]); } + if (m & 0x20) { dst[2] = SkPMSrcOver(src[2], dst[2]); } + if (m & 0x10) { dst[3] = SkPMSrcOver(src[3], dst[3]); } + if (m & 0x08) { dst[4] = SkPMSrcOver(src[4], dst[4]); } + if (m & 0x04) { dst[5] = SkPMSrcOver(src[5], dst[5]); } + if (m & 0x02) { dst[6] = SkPMSrcOver(src[6], dst[6]); } + if (m & 0x01) { dst[7] = SkPMSrcOver(src[7], dst[7]); } + src += 8; + dst += 8; + } + count &= 7; + if (count > 0) { + int m = *mask; + do { + if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } + m <<= 1; + src += 1; + dst += 1; + } while (--count > 0); + } +} + +static void BW_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, + const uint8_t* SK_RESTRICT mask, + const SkPMColor* SK_RESTRICT src, int count) { + int i, octuple = (count + 7) >> 3; + for (i = 0; i < octuple; ++i) { + int m = *mask++; + if (m & 0x80) { dst[0] = src[0]; } + if (m & 0x40) { dst[1] = src[1]; } + if (m & 0x20) { dst[2] = src[2]; } + if (m & 0x10) { dst[3] = src[3]; } + if (m & 0x08) { dst[4] = src[4]; } + if (m & 0x04) { dst[5] = src[5]; } + if (m & 0x02) { dst[6] = src[6]; } + if (m & 0x01) { dst[7] = src[7]; } + src += 8; + dst += 8; + } + count &= 7; + if (count > 0) { + int m = *mask; + do { + if (m & 0x80) { dst[0] = SkPMSrcOver(src[0], dst[0]); } + m <<= 1; + src += 1; + dst += 1; + } while (--count > 0); + } +} + +static void A8_RowProc_Blend(SkPMColor* SK_RESTRICT dst, + const uint8_t* SK_RESTRICT mask, + const SkPMColor* SK_RESTRICT src, int count) { + for (int i = 0; i < count; ++i) { + if (mask[i]) { + dst[i] = SkBlendARGB32(src[i], dst[i], mask[i]); + } + } +} + +// expand the steps that SkAlphaMulQ performs, but this way we can +// exand.. add.. combine +// instead of +// expand..combine add expand..combine +// +#define EXPAND0(v, m, s) ((v) & (m)) * (s) +#define EXPAND1(v, m, s) (((v) >> 8) & (m)) * (s) +#define COMBINE(e0, e1, m) ((((e0) >> 8) & (m)) | ((e1) & ~(m))) + +static void A8_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, + const uint8_t* SK_RESTRICT mask, + const SkPMColor* SK_RESTRICT src, int count) { + const uint32_t rbmask = gMask_00FF00FF; + for (int i = 0; i < count; ++i) { + int m = mask[i]; + if (m) { + m += (m >> 7); +#if 0 + dst[i] = SkAlphaMulQ(src[i], m) + SkAlphaMulQ(dst[i], 256 - m); +#else + uint32_t v = src[i]; + uint32_t s0 = EXPAND0(v, rbmask, m); + uint32_t s1 = EXPAND1(v, rbmask, m); + v = dst[i]; + uint32_t d0 = EXPAND0(v, rbmask, m); + uint32_t d1 = EXPAND1(v, rbmask, m); + dst[i] = COMBINE(s0 + d0, s1 + d1, rbmask); +#endif + } + } +} + +static void LCD16_RowProc_Blend(SkPMColor* SK_RESTRICT dst, + const SkPMColor* SK_RESTRICT mask, + const SkPMColor* SK_RESTRICT src, int count) { + for (int i = 0; i < count; ++i) { + uint16_t m = mask[i]; + if (0 == m) { + continue; + } + + SkPMColor s = src[i]; + SkPMColor d = dst[i]; + + int srcA = SkGetPackedA32(s); + int srcR = SkGetPackedR32(s); + int srcG = SkGetPackedB32(s); + int srcB = SkGetPackedB32(s); + + /* We want all of these in 5bits, hence the shifts in case one of them + * (green) is 6bits. + */ + int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); + int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); + int maskB = SkGetPackedB16(m) >> (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 LCD16_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, + const SkPMColor* SK_RESTRICT mask, + const SkPMColor* SK_RESTRICT src, int count) { + for (int i = 0; i < count; ++i) { + uint16_t m = mask[i]; + if (0 == m) { + continue; + } + + SkPMColor s = src[i]; + SkPMColor d = dst[i]; + + int srcR = SkGetPackedR32(s); + int srcG = SkGetPackedB32(s); + int srcB = SkGetPackedB32(s); + + /* We want all of these in 5bits, hence the shifts in case one of them + * (green) is 6bits. + */ + int maskR = SkGetPackedR16(m) >> (SK_R16_BITS - 5); + int maskG = SkGetPackedG16(m) >> (SK_G16_BITS - 5); + int maskB = SkGetPackedB16(m) >> (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 LCD32_RowProc_Blend(SkPMColor* SK_RESTRICT dst, + const SkPMColor* SK_RESTRICT mask, + const SkPMColor* SK_RESTRICT src, int count) { + for (int i = 0; i < count; ++i) { + SkPMColor m = mask[i]; + if (0 == m) { + continue; + } + + SkPMColor s = src[i]; + int srcA = SkGetPackedA32(s); + int srcR = SkGetPackedR32(s); + int srcG = SkGetPackedB32(s); + int srcB = SkGetPackedB32(s); + + srcA = SkAlpha255To256(srcA); + + SkPMColor d = dst[i]; + + int maskR = SkGetPackedR32(m); + int maskG = SkGetPackedG32(m); + int maskB = SkGetPackedB32(m); + + // 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 LCD32_RowProc_Opaque(SkPMColor* SK_RESTRICT dst, + const SkPMColor* SK_RESTRICT mask, + const SkPMColor* SK_RESTRICT src, int count) { + for (int i = 0; i < count; ++i) { + SkPMColor m = mask[i]; + if (0 == m) { + continue; + } + + SkPMColor s = src[i]; + SkPMColor d = dst[i]; + + int maskR = SkGetPackedR32(m); + int maskG = SkGetPackedG32(m); + int maskB = SkGetPackedB32(m); + int srcR = SkGetPackedR32(s); + int srcG = SkGetPackedB32(s); + int srcB = SkGetPackedB32(s); + int dstR = SkGetPackedR32(d); + int dstG = SkGetPackedG32(d); + int dstB = SkGetPackedB32(d); + + // Now upscale them to 0..256, so we can use SkAlphaBlend + maskR = SkAlpha255To256(maskR); + maskG = SkAlpha255To256(maskG); + maskB = SkAlpha255To256(maskB); + + // 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)); + } +} + +SkBlitMask::RowProc SkBlitMask::RowFactory(SkBitmap::Config config, + SkMask::Format format, + RowFlags flags) { + RowProc proc = PlatformRowProcs(config, format, flags); + if (proc) { + return proc; + } + + static const RowProc gProcs[] = { + // need X coordinate to handle BW + NULL, NULL, //(RowProc)BW_RowProc_Blend, (RowProc)BW_RowProc_Opaque, + (RowProc)A8_RowProc_Blend, (RowProc)A8_RowProc_Opaque, + (RowProc)LCD16_RowProc_Blend, (RowProc)LCD16_RowProc_Opaque, + (RowProc)LCD32_RowProc_Blend, (RowProc)LCD32_RowProc_Opaque, + }; + + int index; + switch (config) { + case SkBitmap::kARGB_8888_Config: + switch (format) { + case SkMask::kBW_Format: index = 0; break; + case SkMask::kA8_Format: index = 2; break; + case SkMask::kLCD16_Format: index = 4; break; + case SkMask::kLCD32_Format: index = 6; break; + default: + return NULL; + } + if (flags & kSrcIsOpaque_RowFlag) { + index |= 1; + } + SkASSERT((size_t)index < SK_ARRAY_COUNT(gProcs)); + return gProcs[index]; + default: + break; + } + return NULL; +} diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp index 7fc9126b7d..24ab330769 100644 --- a/src/core/SkBlitter_ARGB32.cpp +++ b/src/core/SkBlitter_ARGB32.cpp @@ -256,7 +256,7 @@ void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], } } -////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) : INHERITED(device, paint) { @@ -298,8 +298,6 @@ void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) { } } -/////////////////////////////////////////////////////////////////////////////////////////////// - void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) { SkPMColor* span = fBuffer; @@ -373,3 +371,61 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], } } } + +void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) { + // we only handle kA8 with an xfermode + if (fXfermode && (SkMask::kA8_Format != mask.fFormat)) { + this->INHERITED::blitMask(mask, clip); + return; + } + + SkASSERT(mask.fBounds.contains(clip)); + + SkBlitMask::RowProc proc = NULL; + if (!fXfermode) { + unsigned flags = 0; + if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) { + flags |= SkBlitMask::kSrcIsOpaque_RowFlag; + } + proc = SkBlitMask::RowFactory(SkBitmap::kARGB_8888_Config, mask.fFormat, + (SkBlitMask::RowFlags)flags); + if (NULL == proc) { + this->INHERITED::blitMask(mask, clip); + return; + } + } + + const int x = clip.fLeft; + const int width = clip.width(); + int y = clip.fTop; + int height = clip.height(); + + char* dstRow = (char*)fDevice.getAddr32(x, y); + const size_t dstRB = fDevice.rowBytes(); + const uint8_t* maskRow = (const uint8_t*)mask.getAddr(x, y); + const size_t maskRB = mask.fRowBytes; + + SkShader* shader = fShader; + SkPMColor* span = fBuffer; + + if (fXfermode) { + SkASSERT(SkMask::kA8_Format == mask.fFormat); + SkXfermode* xfer = fXfermode; + do { + shader->shadeSpan(x, y, span, width); + xfer->xfer32((SkPMColor*)dstRow, span, width, maskRow); + dstRow += dstRB; + maskRow += maskRB; + y += 1; + } while (--height > 0); + } else { + do { + shader->shadeSpan(x, y, span, width); + proc(dstRow, maskRow, span, width); + dstRow += dstRB; + maskRow += maskRB; + y += 1; + } while (--height > 0); + } +} + diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h index 6993204f35..4947198bcd 100644 --- a/src/core/SkCoreBlitters.h +++ b/src/core/SkCoreBlitters.h @@ -130,6 +130,7 @@ public: virtual ~SkARGB32_Shader_Blitter(); virtual void blitH(int x, int y, int width); virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]); + virtual void blitMask(const SkMask&, const SkIRect&); private: SkXfermode* fXfermode; diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp index dd2301d578..a696def721 100644 --- a/src/core/SkDevice.cpp +++ b/src/core/SkDevice.cpp @@ -358,6 +358,14 @@ void SkDevice::drawDevice(const SkDraw& draw, SkDevice* device, /////////////////////////////////////////////////////////////////////////////// +static bool isSrcOver(SkXfermode* xfer) { + if (NULL == xfer) { + return true; + } + SkXfermode::Mode mode; + return xfer->asMode(&mode) && (SkXfermode::kSrcOver_Mode == mode); +} + bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { if (!paint.isLCDRenderText() || !paint.isAntiAlias()) { // we're cool with the paint as is @@ -365,11 +373,8 @@ bool SkDevice::filterTextFlags(const SkPaint& paint, TextFlags* flags) { } if (SkBitmap::kARGB_8888_Config != fBitmap.config() || - paint.getShader() || - paint.getXfermode() || // unless its srcover - paint.getMaskFilter() || + !isSrcOver(paint.getXfermode()) || paint.getRasterizer() || - paint.getColorFilter() || paint.getPathEffect() || paint.isFakeBoldText() || paint.getStyle() != SkPaint::kFill_Style) { diff --git a/src/opts/SkBlitRow_opts_none.cpp b/src/opts/SkBlitRow_opts_none.cpp index c42ba9f251..d58d2ea720 100644 --- a/src/opts/SkBlitRow_opts_none.cpp +++ b/src/opts/SkBlitRow_opts_none.cpp @@ -26,10 +26,17 @@ SkBlitRow::ColorProc SkBlitRow::PlatformColorProc() { return NULL; } +/////////////////////////////////////////////////////////////////////////////// -SkBlitMask::Proc SkBlitMask::PlatformProcs(SkBitmap::Config dstConfig, - SkMask::Format maskFormat, - SkColor color) -{ +SkBlitMask::ColorProc SkBlitMask::PlatformColorProcs(SkBitmap::Config dstConfig, + SkMask::Format maskFormat, + SkColor color) { return NULL; } + +SkBlitMask::RowProc SkBlitMask::PlatformRowProcs(SkBitmap::Config dstConfig, + SkMask::Format maskFormat, + RowFlags flags) { + return NULL; +} + diff --git a/src/opts/opts_check_SSE2.cpp b/src/opts/opts_check_SSE2.cpp index 9ad94ff54d..00497c9c77 100644 --- a/src/opts/opts_check_SSE2.cpp +++ b/src/opts/opts_check_SSE2.cpp @@ -127,7 +127,8 @@ SkBlitMask::ColorProc SkBlitMask::PlatformColorProcs(SkBitmap::Config dstConfig, } SkBlitMask::RowProc SkBlitMask::PlatformRowProcs(SkBitmap::Config dstConfig, - SkMask::Format maskFormat) { + SkMask::Format maskFormat, + RowFlags flags) { return NULL; } |