From 13201e74f43b9c5fa173339eb36de515370e6973 Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Fri, 16 Nov 2012 13:20:41 +0000 Subject: [PATCH] fold kClear_Mode into kSrc_Mode, and make kSrc_Mode go faster Review URL: https://codereview.appspot.com/6851054 git-svn-id: http://skia.googlecode.com/svn/trunk@6451 2bbb7eff-a529-9590-31e7-b0007b416f81 --- src/core/SkBlitter.cpp | 15 +++ src/core/SkBlitter_ARGB32.cpp | 174 ++++++++++++++++++++++++++++++++-- src/core/SkCoreBlitters.h | 11 ++- 3 files changed, 191 insertions(+), 9 deletions(-) diff --git a/src/core/SkBlitter.cpp b/src/core/SkBlitter.cpp index cdb2b625a7..418665d711 100644 --- a/src/core/SkBlitter.cpp +++ b/src/core/SkBlitter.cpp @@ -871,6 +871,21 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device, } } +#ifndef SK_IGNORE_FAST_SRCMODE + /* + * If the xfermode is CLEAR, then we can completely ignore the installed + * color/shader/colorfilter, and just pretend we're SRC + color==0. This + * will fall into our optimizations for SRC mode. + */ + if (SkXfermode::IsMode(mode, SkXfermode::kClear_Mode)) { + SkPaint* p = paint.writable(); + shader = p->setShader(NULL); + cf = p->setColorFilter(NULL); + mode = p->setXfermodeMode(SkXfermode::kSrc_Mode); + p->setColor(0); + } +#endif + if (NULL == shader) { #ifdef SK_IGNORE_CF_OPTIMIZATION if (mode || cf) { diff --git a/src/core/SkBlitter_ARGB32.cpp b/src/core/SkBlitter_ARGB32.cpp index f944f44dc1..6ca88d7d1b 100644 --- a/src/core/SkBlitter_ARGB32.cpp +++ b/src/core/SkBlitter_ARGB32.cpp @@ -263,6 +263,19 @@ void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], /////////////////////////////////////////////////////////////////////////////// +#ifndef SK_IGNORE_FAST_SRCMODE +// Special version of SkBlitRow::Factory32 that knows we're in kSrc_Mode, +// instead of kSrcOver_Mode +static void blend_srcmode(SkPMColor* SK_RESTRICT device, + const SkPMColor* SK_RESTRICT span, + int count, U8CPU aa) { + int aa256 = SkAlpha255To256(aa); + for (int i = 0; i < count; ++i) { + device[i] = SkFourByteInterp256(span[i], device[i], aa256); + } +} +#endif + SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint) : INHERITED(device, paint) { fBuffer = (SkPMColor*)sk_malloc_throw(device.width() * (sizeof(SkPMColor))); @@ -278,6 +291,25 @@ SkARGB32_Shader_Blitter::SkARGB32_Shader_Blitter(const SkBitmap& device, fProc32 = SkBlitRow::Factory32(flags); // we call this on the output from the shader + alpha from the aa buffer fProc32Blend = SkBlitRow::Factory32(flags | SkBlitRow::kGlobalAlpha_Flag32); + + fShadeDirectlyIntoDevice = false; + if (fXfermode == NULL) { + if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) { + fShadeDirectlyIntoDevice = true; + } + } else { +#ifndef SK_IGNORE_FAST_SRCMODE + SkXfermode::Mode mode; + if (fXfermode->asMode(&mode)) { + if (SkXfermode::kSrc_Mode == mode) { + fShadeDirectlyIntoDevice = true; + fProc32Blend = blend_srcmode; + } + } +#endif + } + + fConstInY = SkToBool(fShader->getFlags() & SkShader::kConstInY32_Flag); } SkARGB32_Shader_Blitter::~SkARGB32_Shader_Blitter() { @@ -290,7 +322,7 @@ void SkARGB32_Shader_Blitter::blitH(int x, int y, int width) { uint32_t* device = fDevice.getAddr32(x, y); - if (fXfermode == NULL && (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { + if (fShadeDirectlyIntoDevice) { fShader->shadeSpan(x, y, device, width); } else { SkPMColor* span = fBuffer; @@ -310,8 +342,39 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) { uint32_t* device = fDevice.getAddr32(x, y); size_t deviceRB = fDevice.rowBytes(); SkShader* shader = fShader; + SkPMColor* span = fBuffer; - if (fXfermode == NULL && (shader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { + if (fConstInY) { + if (fShadeDirectlyIntoDevice) { + // shade the first row directly into the device + fShader->shadeSpan(x, y, device, width); + span = device; + while (--height > 0) { + device = (uint32_t*)((char*)device + deviceRB); + memcpy(device, span, width << 2); + } + } else { + fShader->shadeSpan(x, y, span, width); + SkXfermode* xfer = fXfermode; + if (xfer) { + do { + xfer->xfer32(device, span, width, NULL); + y += 1; + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } else { + SkBlitRow::Proc32 proc = fProc32; + do { + proc(device, span, width, 255); + y += 1; + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } + } + return; + } + + if (fShadeDirectlyIntoDevice) { void* ctx; SkShader::ShadeProc shadeProc = fShader->asAShadeProc(&ctx); if (shadeProc) { @@ -328,7 +391,6 @@ void SkARGB32_Shader_Blitter::blitRect(int x, int y, int width, int height) { } while (--height > 0); } } else { - SkPMColor* span = fBuffer; SkXfermode* xfer = fXfermode; if (xfer) { do { @@ -355,7 +417,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], uint32_t* device = fDevice.getAddr32(x, y); SkShader* shader = fShader; - if (fXfermode) { + if (fXfermode && !fShadeDirectlyIntoDevice) { for (;;) { SkXfermode* xfer = fXfermode; @@ -379,7 +441,8 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], antialias += count; x += count; } - } else if (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag) { + } else if (fShadeDirectlyIntoDevice || + (fShader->getFlags() & SkShader::kOpaqueAlpha_Flag)) { for (;;) { int count = *runs; if (count <= 0) { @@ -400,7 +463,7 @@ void SkARGB32_Shader_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[], antialias += count; x += count; } - } else { // no xfermode but the shader not opaque + } else { for (;;) { int count = *runs; if (count <= 0) { @@ -480,3 +543,102 @@ void SkARGB32_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) } } +#ifndef SK_IGNORE_FAST_SRCMODE +void SkARGB32_Shader_Blitter::blitV(int x, int y, int height, SkAlpha alpha) { + SkASSERT(x >= 0 && y >= 0 && y + height <= fDevice.height()); + + uint32_t* device = fDevice.getAddr32(x, y); + size_t deviceRB = fDevice.rowBytes(); + SkShader* shader = fShader; + + if (fConstInY) { + SkPMColor c; + fShader->shadeSpan(x, y, &c, 1); + + if (fShadeDirectlyIntoDevice) { + if (255 == alpha) { + do { + *device = c; + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } else { + do { + *device = SkFourByteInterp(c, *device, alpha); + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } + } else { + SkXfermode* xfer = fXfermode; + if (xfer) { + do { + xfer->xfer32(device, &c, 1, &alpha); + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } else { + SkBlitRow::Proc32 proc = fProc32; + do { + proc(device, &c, 1, alpha); + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } + } + return; + } + + if (fShadeDirectlyIntoDevice) { + void* ctx; + SkShader::ShadeProc shadeProc = fShader->asAShadeProc(&ctx); + if (255 == alpha) { + if (shadeProc) { + do { + shadeProc(ctx, x, y, device, 1); + y += 1; + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } else { + do { + shader->shadeSpan(x, y, device, 1); + y += 1; + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } + } else { // alpha < 255 + SkPMColor c; + if (shadeProc) { + do { + shadeProc(ctx, x, y, &c, 1); + *device = SkFourByteInterp(c, *device, alpha); + y += 1; + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } else { + do { + shader->shadeSpan(x, y, &c, 1); + *device = SkFourByteInterp(c, *device, alpha); + y += 1; + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } + } + } else { + SkPMColor* span = fBuffer; + SkXfermode* xfer = fXfermode; + if (xfer) { + do { + shader->shadeSpan(x, y, span, 1); + xfer->xfer32(device, span, 1, &alpha); + y += 1; + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } else { + // can't use fProc, since we need to use an unknown alpha + do { + shader->shadeSpan(x, y, span, 1); + *device = SkFourByteInterp(*span, *device, alpha); + y += 1; + device = (uint32_t*)((char*)device + deviceRB); + } while (--height > 0); + } + } +} +#endif diff --git a/src/core/SkCoreBlitters.h b/src/core/SkCoreBlitters.h index 48f85b0475..0a342e09a1 100644 --- a/src/core/SkCoreBlitters.h +++ b/src/core/SkCoreBlitters.h @@ -129,16 +129,21 @@ class SkARGB32_Shader_Blitter : public SkShaderBlitter { public: SkARGB32_Shader_Blitter(const SkBitmap& device, const SkPaint& paint); virtual ~SkARGB32_Shader_Blitter(); - virtual void blitH(int x, int y, int width); + virtual void blitH(int x, int y, int width) SK_OVERRIDE; +#ifndef SK_IGNORE_FAST_SRCMODE + virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE; +#endif virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE; - virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]); - virtual void blitMask(const SkMask&, const SkIRect&); + virtual void blitAntiH(int x, int y, const SkAlpha[], const int16_t[]) SK_OVERRIDE; + virtual void blitMask(const SkMask&, const SkIRect&) SK_OVERRIDE; private: SkXfermode* fXfermode; SkPMColor* fBuffer; SkBlitRow::Proc32 fProc32; SkBlitRow::Proc32 fProc32Blend; + bool fShadeDirectlyIntoDevice; + bool fConstInY; // illegal SkARGB32_Shader_Blitter& operator=(const SkARGB32_Shader_Blitter&);