aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-11-15 19:51:02 +0000
committerGravatar reed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2011-11-15 19:51:02 +0000
commit1750bf17635e788198200f971d9cb66f67399363 (patch)
treeb397330b4f71c6cd08d161e9264396dbd17b99b3 /src
parentf7b5c1ebfdad1a77d301d1676235e79f8006883e (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.h18
-rw-r--r--src/core/SkBlitMask_D32.cpp308
-rw-r--r--src/core/SkBlitter_ARGB32.cpp62
-rw-r--r--src/core/SkCoreBlitters.h1
-rw-r--r--src/core/SkDevice.cpp13
-rw-r--r--src/opts/SkBlitRow_opts_none.cpp15
-rw-r--r--src/opts/opts_check_SSE2.cpp3
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;
}