support blitMask+shader natively (1.75x faster for AA, and now we can support
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 15 Nov 2011 19:51:02 +0000 (19:51 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Tue, 15 Nov 2011 19:51:02 +0000 (19:51 +0000)
LCD at all with a shader.)

git-svn-id: http://skia.googlecode.com/svn/trunk@2689 2bbb7eff-a529-9590-31e7-b0007b416f81

src/core/SkBlitMask.h
src/core/SkBlitMask_D32.cpp
src/core/SkBlitter_ARGB32.cpp
src/core/SkCoreBlitters.h
src/core/SkDevice.cpp
src/opts/SkBlitRow_opts_none.cpp
src/opts/opts_check_SSE2.cpp

index 66687a9c29303a23c33932185b685faa5069729a..299f6d1e5c38ba6efa5f41f90b09df65a097a3b4 100644 (file)
@@ -44,23 +44,27 @@ 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
index 356f285fecc57d153d744692ea8fed08b8a9de23..81522ff5917b252a7c355bcdacf9b0c9051ce2bc 100644 (file)
@@ -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;
+}
 
index 7fc9126b7d96751217cad98a617c47b588ac200e..24ab330769adfe129572ea3792f87216c87d4de5 100644 (file)
@@ -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);
+    }
+}
+
index 6993204f354100d8e1d266b2d4e7d470164f8ef3..4947198bcd54fd49270ddbf95ffca3031b87a101 100644 (file)
@@ -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;
index dd2301d5784f74b8874ad8721ec14efaf6019852..a696def721f69ffaa2ca96aa2f2cb5e17bb62a47 100644 (file)
@@ -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) {
index c42ba9f2510007b383a0808d1f02cecfd774131f..d58d2ea7203d1cc28a9b9783f948bea3ebdbf841 100644 (file)
@@ -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;
+}
+
index 9ad94ff54dec546e7da7377df868ef00f59cd424..00497c9c7778049013d085c33c821701ccbe2b2d 100644 (file)
@@ -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;
 }