Revert "Revert "speed up A8 by creating a new entry-point in SkDraw that blits the...
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 7 Nov 2013 16:06:53 +0000 (16:06 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 7 Nov 2013 16:06:53 +0000 (16:06 +0000)
This reverts commit 3c77887b3eb2d32ab668ab4e5f2f9e79103956e8.

BUG=

Review URL: https://codereview.chromium.org/50673005

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

bench/CoverageBench.cpp [new file with mode: 0644]
gyp/bench.gypi
include/core/SkDraw.h
include/core/SkRect.h
src/core/SkBlitter.cpp
src/core/SkBlitter.h
src/core/SkBlitter_A8.cpp
src/core/SkCoreBlitters.h
src/core/SkDraw.cpp
src/gpu/GrSWMaskHelper.cpp

diff --git a/bench/CoverageBench.cpp b/bench/CoverageBench.cpp
new file mode 100644 (file)
index 0000000..de09733
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBenchmark.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkDraw.h"
+#include "SkMatrix.h"
+#include "SkPath.h"
+#include "SkRasterClip.h"
+
+class DrawPathBench : public SkBenchmark {
+    SkPaint     fPaint;
+    SkString    fName;
+    SkPath      fPath;
+    SkRasterClip fRC;
+    SkBitmap    fBitmap;
+    SkMatrix    fIdentity;
+    SkDraw      fDraw;
+    bool        fDrawCoverage;
+public:
+    DrawPathBench(bool drawCoverage) : fDrawCoverage(drawCoverage) {
+        fPaint.setAntiAlias(true);
+        fName.printf("draw_coverage_%s", drawCoverage ? "true" : "false");
+
+        fPath.moveTo(0, 0);
+        fPath.quadTo(500, 0, 500, 500);
+        fPath.quadTo(250, 0, 0, 500);
+
+        fBitmap.setConfig(SkBitmap::kA8_Config, 500, 500);
+        fBitmap.allocPixels();
+
+        fIdentity.setIdentity();
+        fRC.setRect(fPath.getBounds().round());
+
+        fDraw.fBitmap   = &fBitmap;
+        fDraw.fMatrix   = &fIdentity;
+        fDraw.fClip     = &fRC.bwRgn();
+        fDraw.fRC       = &fRC;
+    }
+    
+protected:
+    virtual const char* onGetName() SK_OVERRIDE {
+        return fName.c_str();
+    }
+    
+    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+        if (fDrawCoverage) {
+            for (int i = 0; i < this->getLoops(); ++i) {
+                fDraw.drawPathCoverage(fPath, fPaint);
+            }
+        } else {
+            for (int i = 0; i < this->getLoops(); ++i) {
+                fDraw.drawPath(fPath, fPaint);
+            }
+        }
+    }
+    
+private:
+    typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+DEF_BENCH( return new DrawPathBench(false) )
+DEF_BENCH( return new DrawPathBench(true) )
index de1d861bdf526b5a21a23d9a3895df6caff2c19a..0274176a1c7be2e47311b0c395e918da0b96f839 100644 (file)
@@ -19,6 +19,7 @@
     '../bench/ChromeBench.cpp',
     '../bench/CmapBench.cpp',
     '../bench/ColorFilterBench.cpp',
+    '../bench/CoverageBench.cpp',
     '../bench/DashBench.cpp',
     '../bench/DecodeBench.cpp',
     '../bench/DeferredCanvasBench.cpp',
index 772e11e00d7a4de2e1cca94e6a75856051835abb..91830946791823b66736e99b8000176314e045ca 100644 (file)
@@ -43,8 +43,15 @@ public:
      *  affect the geometry/rasterization, then the pre matrix can just be
      *  pre-concated with the current matrix.
      */
-    void    drawPath(const SkPath& srcPath, const SkPaint&,
-                     const SkMatrix* prePathMatrix, bool pathIsMutable) const;
+    void    drawPath(const SkPath& path, const SkPaint& paint,
+                     const SkMatrix* prePathMatrix, bool pathIsMutable) const {
+        this->drawPath(path, paint, prePathMatrix, pathIsMutable, false);
+    }
+
+    void drawPath(const SkPath& path, const SkPaint& paint) const {
+        this->drawPath(path, paint, NULL, false, false);
+    }
+
     void    drawBitmap(const SkBitmap&, const SkMatrix&, const SkPaint&) const;
     void    drawSprite(const SkBitmap&, int x, int y, const SkPaint&) const;
     void    drawText(const char text[], size_t byteLength, SkScalar x,
@@ -65,8 +72,14 @@ public:
                          const uint16_t indices[], int ptCount,
                          const SkPaint& paint) const;
 
-    void drawPath(const SkPath& src, const SkPaint& paint) const {
-        this->drawPath(src, paint, NULL, false);
+    /**
+     *  Overwrite the target with the path's coverage (i.e. its mask).
+     *  Will overwrite the entire device, so it need not be zero'd first.
+     *
+     *  Only device A8 is supported right now.
+     */
+    void drawPathCoverage(const SkPath& src, const SkPaint& paint) const {
+        this->drawPath(src, paint, NULL, false, true);
     }
 
     /** Helper function that creates a mask from a path and an optional maskfilter.
@@ -107,6 +120,9 @@ private:
     void    drawDevMask(const SkMask& mask, const SkPaint&) const;
     void    drawBitmapAsMask(const SkBitmap&, const SkPaint&) const;
 
+    void    drawPath(const SkPath&, const SkPaint&, const SkMatrix* preMatrix,
+                     bool pathIsMutable, bool drawCoverage) const;
+
     /**
      *  Return the current clip bounds, in local coordinates, with slop to account
      *  for antialiasing or hairlines (i.e. device-bounds outset by 1, and then
index 98acb1cda31731a407bfe3db63d23ccdd284a458..8bfa57a8f9f0d71b3a4b6e5fa69cb5e9571fa0d6 100644 (file)
@@ -730,7 +730,7 @@ struct SK_API SkRect {
 
     /**
      *  Set the dst rectangle by rounding this rectangle's coordinates to their
-     *  nearest integer values using SkScalarRound.
+     *  nearest integer values using SkScalarRoundToInt.
      */
     void round(SkIRect* dst) const {
         SkASSERT(dst);
@@ -772,6 +772,15 @@ struct SK_API SkRect {
                  SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
     }
 
+    /**
+     *  Return a new SkIRect which is contains the rounded coordinates of this
+     *  rect using SkScalarRoundToInt.
+     */
+    SkIRect round() const {
+        SkIRect ir;
+        this->round(&ir);
+        return ir;
+    }
 
     /**
      *  Swap top/bottom or left/right if there are flipped (i.e. if width()
index f4e1a37c80b5177cda0acc7975efbc7ec23ebd4e..f46db357d47d87505fafe279e4b1dfcd798725f0 100644 (file)
@@ -850,14 +850,16 @@ static XferInterp interpret_xfermode(const SkPaint& paint, SkXfermode* xfer,
 SkBlitter* SkBlitter::Choose(const SkBitmap& device,
                              const SkMatrix& matrix,
                              const SkPaint& origPaint,
-                             void* storage, size_t storageSize) {
+                             void* storage, size_t storageSize,
+                             bool drawCoverage) {
     SkASSERT(storageSize == 0 || storage != NULL);
 
     SkBlitter*  blitter = NULL;
 
     // which check, in case we're being called by a client with a dummy device
     // (e.g. they have a bounder that always aborts the draw)
-    if (SkBitmap::kNo_Config == device.config()) {
+    if (SkBitmap::kNo_Config == device.config() ||
+            (drawCoverage && (SkBitmap::kA8_Config != device.config()))) {
         SK_PLACEMENT_NEW(blitter, SkNullBlitter, storage, storageSize);
         return blitter;
     }
@@ -940,6 +942,7 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
         return blitter;
     }
 
+    
     switch (device.config()) {
         case SkBitmap::kA1_Config:
             SK_PLACEMENT_NEW_ARGS(blitter, SkA1_Blitter,
@@ -947,7 +950,12 @@ SkBlitter* SkBlitter::Choose(const SkBitmap& device,
             break;
 
         case SkBitmap::kA8_Config:
-            if (shader) {
+            if (drawCoverage) {
+                SkASSERT(NULL == shader);
+                SkASSERT(NULL == paint->getXfermode());
+                SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Coverage_Blitter,
+                                      storage, storageSize, (device, *paint));
+            } else if (shader) {
                 SK_PLACEMENT_NEW_ARGS(blitter, SkA8_Shader_Blitter,
                                       storage, storageSize, (device, *paint));
             } else {
index 0a075f89adf229d55dfe42f620283582e18fb9f5..b659fe473581635d8475068a9c680747cb2059ff 100644 (file)
@@ -76,7 +76,8 @@ public:
     static SkBlitter* Choose(const SkBitmap& device,
                              const SkMatrix& matrix,
                              const SkPaint& paint,
-                             void* storage, size_t storageSize);
+                             void* storage, size_t storageSize,
+                             bool drawCoverage = false);
 
     static SkBlitter* ChooseSprite(const SkBitmap& device,
                                    const SkPaint&,
index 7fca29ecf5d0c2e31c12b0fe9b01bdceba74d8e6..1df033f54bce314060a435973836eb5a51f28a07 100644 (file)
@@ -347,3 +347,93 @@ void SkA8_Shader_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
         alpha += mask.fRowBytes;
     }
 }
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define SK_A8_COVERAGE_BLIT_SKIP_ZEROS
+
+SkA8_Coverage_Blitter::SkA8_Coverage_Blitter(const SkBitmap& device,
+                             const SkPaint& paint) : SkRasterBlitter(device) {
+    SkASSERT(NULL == paint.getShader());
+    SkASSERT(NULL == paint.getXfermode());
+    SkASSERT(NULL == paint.getColorFilter());
+}
+
+void SkA8_Coverage_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
+                                      const int16_t runs[]) {
+    SkASSERT(0 == x);
+
+    uint8_t* device = fDevice.getAddr8(x, y);
+    SkDEBUGCODE(int totalCount = 0;)
+    
+    for (;;) {
+        int count = runs[0];
+        SkASSERT(count >= 0);
+        if (count == 0) {
+            return;
+        }
+#ifdef SK_A8_COVERAGE_BLIT_SKIP_ZEROS
+        if (antialias[0])
+#endif
+        {
+            memset(device, antialias[0], count);
+        }
+        runs += count;
+        antialias += count;
+        device += count;
+
+        SkDEBUGCODE(totalCount += count;)
+    }
+    SkASSERT(fDevice.width() == totalCount);
+}
+
+void SkA8_Coverage_Blitter::blitH(int x, int y, int width) {
+    memset(fDevice.getAddr8(x, y), 0xFF, width);
+}
+
+void SkA8_Coverage_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
+#ifdef SK_A8_COVERAGE_BLIT_SKIP_ZEROS
+    if (0 == alpha) {
+        return;
+    }
+#endif
+    uint8_t* dst = fDevice.getAddr8(x, y);
+    const size_t dstRB = fDevice.rowBytes();
+    while (--height >= 0) {
+        *dst = alpha;
+        dst += dstRB;
+    }
+}
+
+void SkA8_Coverage_Blitter::blitRect(int x, int y, int width, int height) {
+    uint8_t* dst = fDevice.getAddr8(x, y);
+    const size_t dstRB = fDevice.rowBytes();
+    while (--height >= 0) {
+        memset(dst, 0xFF, width);
+        dst += dstRB;
+    }
+}
+
+void SkA8_Coverage_Blitter::blitMask(const SkMask& mask, const SkIRect& clip) {
+    SkASSERT(SkMask::kA8_Format == mask.fFormat);
+
+    int x = clip.fLeft;
+    int y = clip.fTop;
+    int width = clip.width();
+    int height = clip.height();
+
+    uint8_t* dst = fDevice.getAddr8(x, y);
+    const uint8_t* src = mask.getAddr8(x, y);
+    const size_t srcRB = mask.fRowBytes;
+    const size_t dstRB = fDevice.rowBytes();
+    
+    while (--height >= 0) {
+        memcpy(dst, src, width);
+        dst += dstRB;
+        src += srcRB;
+    }
+}
+
+const SkBitmap* SkA8_Coverage_Blitter::justAnOpaqueColor(uint32_t*) {
+    return NULL;
+}
index 9455509c483de68684056f4f8ed035bbff54c4fe..673b8745456061f85e37dfafcb05b0d4e68c73dc 100644 (file)
@@ -40,6 +40,17 @@ private:
 
 ///////////////////////////////////////////////////////////////////////////////
 
+class SkA8_Coverage_Blitter : public SkRasterBlitter {
+public:
+    SkA8_Coverage_Blitter(const SkBitmap& device, const SkPaint& paint);
+    virtual void blitH(int x, int y, int width) SK_OVERRIDE;
+    virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]) SK_OVERRIDE;
+    virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE;
+    virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
+    virtual void blitMask(const SkMask&, const SkIRect&) SK_OVERRIDE;
+    virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE;
+};
+
 class SkA8_Blitter : public SkRasterBlitter {
 public:
     SkA8_Blitter(const SkBitmap& device, const SkPaint& paint);
index df73f7ae3795829c09e40349a8671d805dd19d6c..af4f1ca0474fdecee56f137092f606cf31317133 100644 (file)
@@ -59,9 +59,9 @@ public:
         fBlitter = NULL;
     }
     SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix,
-                        const SkPaint& paint) {
+                        const SkPaint& paint, bool drawCoverage = false) {
         fBlitter = SkBlitter::Choose(device, matrix, paint,
-                                     fStorage, sizeof(fStorage));
+                                     fStorage, sizeof(fStorage), drawCoverage);
     }
 
     ~SkAutoBlitterChoose();
@@ -1023,7 +1023,8 @@ bool SkDrawTreatAsHairline(const SkPaint& paint, const SkMatrix& matrix,
 }
 
 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
-                      const SkMatrix* prePathMatrix, bool pathIsMutable) const {
+                      const SkMatrix* prePathMatrix, bool pathIsMutable,
+                      bool drawCoverage) const {
     SkDEBUGCODE(this->validate();)
 
     // nothing to draw
@@ -1112,7 +1113,7 @@ void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
     // transform the path into device space
     pathPtr->transform(*matrix, devPathPtr);
 
-    SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, *paint);
+    SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, *paint, drawCoverage);
 
     if (paint->getMaskFilter()) {
         SkPaint::Style style = doFill ? SkPaint::kFill_Style :
index 5fb944bac4bcf20b2fc645079ea8c6a0e8ee00ae..eefc951e7e4482c58103389fe113a10e5a1ddf8f 100644 (file)
@@ -73,16 +73,16 @@ void GrSWMaskHelper::draw(const SkPath& path, const SkStrokeRec& stroke, SkRegio
             paint.setStrokeWidth(stroke.getWidth());
         }
     }
-
-    SkXfermode* mode = SkXfermode::Create(op_to_mode(op));
-
-    paint.setXfermode(mode);
     paint.setAntiAlias(antiAlias);
-    paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
 
-    fDraw.drawPath(path, paint);
-
-    SkSafeUnref(mode);
+    if (SkRegion::kReplace_Op == op && 0xFF == alpha) {
+        SkASSERT(0xFF == paint.getAlpha());
+        fDraw.drawPathCoverage(path, paint);
+    } else {
+        paint.setXfermodeMode(op_to_mode(op));
+        paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
+        fDraw.drawPath(path, paint);
+    }
 }
 
 bool GrSWMaskHelper::init(const SkIRect& resultBounds,