add new blit2 methods in support of antialiased hairlines
authorreed <reed@google.com>
Wed, 15 Apr 2015 01:39:57 +0000 (18:39 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 15 Apr 2015 01:39:57 +0000 (18:39 -0700)
before:
   9M 1 528µs 530µs 539µs 607µs 5% ▁▁▁▁▁▁▁▁█▂ 8888 path_hairline_small_AA_quad

after:
   9M 1 355µs 356µs 358µs 375µs 2% ▂▁▁▁▁▁▁▁▁█ 8888 path_hairline_small_AA_quad

BUG=skia:

does require new baselines (bug chrome is guarded)

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

src/core/SkBlitter.h
src/core/SkBlitter_ARGB32.cpp
src/core/SkCoreBlitters.h
src/core/SkScan_Antihair.cpp

index 9447bf1..51d60a4 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright 2006 The Android Open Source Project
  *
@@ -6,10 +5,15 @@
  * found in the LICENSE file.
  */
 
-
 #ifndef SkBlitter_DEFINED
 #define SkBlitter_DEFINED
 
+#ifdef SK_SUPPORT_LEGACY_BLITANTIH2V2
+    #define SK_BLITANTIH2V2_VIRTUAL
+#else
+    #define SK_BLITANTIH2V2_VIRTUAL virtual
+#endif
+
 #include "SkBitmap.h"
 #include "SkBitmapProcShader.h"
 #include "SkMask.h"
@@ -55,6 +59,35 @@ public:
     */
     virtual const SkBitmap* justAnOpaqueColor(uint32_t* value);
 
+    // (x, y), (x + 1, y)
+    SK_BLITANTIH2V2_VIRTUAL void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
+        int16_t runs[3];
+        uint8_t  aa[2];
+        
+        runs[0] = 1;
+        runs[1] = 1;
+        runs[2] = 0;
+        aa[0] = SkToU8(a0);
+        aa[1] = SkToU8(a1);
+        this->blitAntiH(x, y, aa, runs);
+    }
+
+    // (x, y), (x, y + 1)
+    SK_BLITANTIH2V2_VIRTUAL void blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
+        int16_t runs[2];
+        uint8_t  aa[1];
+        
+        runs[0] = 1;
+        runs[1] = 0;
+        aa[0] = SkToU8(a0);
+        this->blitAntiH(x, y, aa, runs);
+        // reset in case the clipping blitter modified runs
+        runs[0] = 1;
+        runs[1] = 0;
+        aa[0] = SkToU8(a1);
+        this->blitAntiH(x, y + 1, aa, runs);
+    }
+    
     /**
      *  Special method just to identify the null blitter, which is returned
      *  from Choose() if the request cannot be fulfilled. Default impl
index bbad6c7..caf85dd 100644 (file)
@@ -106,6 +106,25 @@ void SkARGB32_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
     }
 }
 
+#ifndef SK_SUPPORT_LEGACY_BLITANTIH2V2
+void SkARGB32_Blitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
+    uint32_t* device = fDevice.getAddr32(x, y);
+    SkDEBUGCODE((void)fDevice.getAddr32(x + 1, y);)
+    
+    device[0] = SkBlendARGB32(fPMColor, device[0], a0);
+    device[1] = SkBlendARGB32(fPMColor, device[1], a1);
+}
+
+void SkARGB32_Blitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
+    uint32_t* device = fDevice.getAddr32(x, y);
+    SkDEBUGCODE((void)fDevice.getAddr32(x, y + 1);)
+    
+    device[0] = SkBlendARGB32(fPMColor, device[0], a0);
+    device = (uint32_t*)((char*)device + fDevice.rowBytes());
+    device[0] = SkBlendARGB32(fPMColor, device[0], a1);
+}
+#endif
+
 //////////////////////////////////////////////////////////////////////////////////////
 
 #define solid_8_pixels(mask, dst, color)    \
@@ -180,6 +199,25 @@ void SkARGB32_Opaque_Blitter::blitMask(const SkMask& mask,
     }
 }
 
+#ifndef SK_SUPPORT_LEGACY_BLITANTIH2V2
+void SkARGB32_Opaque_Blitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
+    uint32_t* device = fDevice.getAddr32(x, y);
+    SkDEBUGCODE((void)fDevice.getAddr32(x + 1, y);)
+
+    device[0] = SkFastFourByteInterp(fPMColor, device[0], a0);
+    device[1] = SkFastFourByteInterp(fPMColor, device[1], a1);
+}
+
+void SkARGB32_Opaque_Blitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
+    uint32_t* device = fDevice.getAddr32(x, y);
+    SkDEBUGCODE((void)fDevice.getAddr32(x, y + 1);)
+
+    device[0] = SkFastFourByteInterp(fPMColor, device[0], a0);
+    device = (uint32_t*)((char*)device + fDevice.rowBytes());
+    device[0] = SkFastFourByteInterp(fPMColor, device[0], a1);
+}
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 
 void SkARGB32_Blitter::blitV(int x, int y, int height, SkAlpha alpha) {
@@ -256,6 +294,25 @@ void SkARGB32_Black_Blitter::blitAntiH(int x, int y, const SkAlpha antialias[],
     }
 }
 
+#ifndef SK_SUPPORT_LEGACY_BLITANTIH2V2
+void SkARGB32_Black_Blitter::blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) {
+    uint32_t* device = fDevice.getAddr32(x, y);
+    SkDEBUGCODE((void)fDevice.getAddr32(x + 1, y);)
+
+    device[0] = (a0 << SK_A32_SHIFT) + SkAlphaMulQ(device[0], 256 - a0);
+    device[1] = (a1 << SK_A32_SHIFT) + SkAlphaMulQ(device[1], 256 - a1);
+}
+
+void SkARGB32_Black_Blitter::blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) {
+    uint32_t* device = fDevice.getAddr32(x, y);
+    SkDEBUGCODE((void)fDevice.getAddr32(x, y + 1);)
+    
+    device[0] = (a0 << SK_A32_SHIFT) + SkAlphaMulQ(device[0], 256 - a0);
+    device = (uint32_t*)((char*)device + fDevice.rowBytes());
+    device[0] = (a1 << SK_A32_SHIFT) + SkAlphaMulQ(device[0], 256 - a1);
+}
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 
 // Special version of SkBlitRow::Factory32 that knows we're in kSrc_Mode,
index f4a5d6f..acc18fe 100644 (file)
@@ -120,6 +120,10 @@ public:
     virtual void blitRect(int x, int y, int width, int height);
     virtual void blitMask(const SkMask&, const SkIRect&);
     virtual const SkBitmap* justAnOpaqueColor(uint32_t*);
+#ifndef SK_SUPPORT_LEGACY_BLITANTIH2V2
+    void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) override;
+    void blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) override;
+#endif
 
 protected:
     SkColor                fColor;
@@ -140,6 +144,10 @@ public:
     SkARGB32_Opaque_Blitter(const SkBitmap& device, const SkPaint& paint)
         : INHERITED(device, paint) { SkASSERT(paint.getAlpha() == 0xFF); }
     virtual void blitMask(const SkMask&, const SkIRect&);
+#ifndef SK_SUPPORT_LEGACY_BLITANTIH2V2
+    void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) override;
+    void blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) override;
+#endif
 
 private:
     typedef SkARGB32_Blitter INHERITED;
@@ -150,6 +158,10 @@ public:
     SkARGB32_Black_Blitter(const SkBitmap& device, const SkPaint& paint)
         : INHERITED(device, paint) {}
     virtual void blitAntiH(int x, int y, const SkAlpha antialias[], const int16_t runs[]);
+#ifndef SK_SUPPORT_LEGACY_BLITANTIH2V2
+    void blitAntiH2(int x, int y, U8CPU a0, U8CPU a1) override;
+    void blitAntiV2(int x, int y, U8CPU a0, U8CPU a1) override;
+#endif
 
 private:
     typedef SkARGB32_Opaque_Blitter INHERITED;
index 3073434..546ced0 100644 (file)
@@ -154,70 +154,29 @@ public:
 class Horish_SkAntiHairBlitter : public SkAntiHairBlitter {
 public:
     SkFixed drawCap(int x, SkFixed fy, SkFixed dy, int mod64) override {
-        int16_t runs[2];
-        uint8_t  aa[1];
-
-        runs[0] = 1;
-        runs[1] = 0;
-
         fy += SK_Fixed1/2;
-        SkBlitter* blitter = this->getBlitter();
-
+        
         int lower_y = fy >> 16;
         uint8_t  a = (uint8_t)(fy >> 8);
-        unsigned ma = SmallDot6Scale(a, mod64);
-        if (ma) {
-            aa[0] = ApplyGamma(gamma, ma);
-            blitter->blitAntiH(x, lower_y, aa, runs);
-            // the clipping blitters might edit runs, but should not affect us
-            SkASSERT(runs[0] == 1);
-            SkASSERT(runs[1] == 0);
-        }
-        ma = SmallDot6Scale(255 - a, mod64);
-        if (ma) {
-            aa[0] = ApplyGamma(gamma, ma);
-            blitter->blitAntiH(x, lower_y - 1, aa, runs);
-            // the clipping blitters might edit runs, but should not affect us
-            SkASSERT(runs[0] == 1);
-            SkASSERT(runs[1] == 0);
-        }
-        fy += dy;
-
-        return fy - SK_Fixed1/2;
+        unsigned a0 = SmallDot6Scale(255 - a, mod64);
+        unsigned a1 = SmallDot6Scale(a, mod64);
+        this->getBlitter()->blitAntiV2(x, lower_y - 1, a0, a1);
+        
+        return fy + dy - SK_Fixed1/2;
     }
-
+    
     SkFixed drawLine(int x, int stopx, SkFixed fy, SkFixed dy) override {
         SkASSERT(x < stopx);
-
-        int16_t runs[2];
-        uint8_t  aa[1];
-
-        runs[0] = 1;
-        runs[1] = 0;
-
+        
         fy += SK_Fixed1/2;
         SkBlitter* blitter = this->getBlitter();
         do {
             int lower_y = fy >> 16;
             uint8_t  a = (uint8_t)(fy >> 8);
-            if (a) {
-                aa[0] = a;
-                blitter->blitAntiH(x, lower_y, aa, runs);
-                // the clipping blitters might edit runs, but should not affect us
-                SkASSERT(runs[0] == 1);
-                SkASSERT(runs[1] == 0);
-            }
-            a = 255 - a;
-            if (a) {
-                aa[0] = a;
-                blitter->blitAntiH(x, lower_y - 1, aa, runs);
-                // the clipping blitters might edit runs, but should not affect us
-                SkASSERT(runs[0] == 1);
-                SkASSERT(runs[1] == 0);
-            }
+            blitter->blitAntiV2(x, lower_y - 1, 255 - a, a);
             fy += dy;
         } while (++x < stopx);
-
+        
         return fy - SK_Fixed1/2;
     }
 };
@@ -266,53 +225,26 @@ public:
 class Vertish_SkAntiHairBlitter : public SkAntiHairBlitter {
 public:
     SkFixed drawCap(int y, SkFixed fx, SkFixed dx, int mod64) override {
-        int16_t runs[3];
-        uint8_t  aa[2];
-
-        runs[0] = 1;
-        runs[2] = 0;
-
         fx += SK_Fixed1/2;
+        
         int x = fx >> 16;
-        uint8_t  a = (uint8_t)(fx >> 8);
-
-        aa[0] = SmallDot6Scale(255 - a, mod64);
-        aa[1] = SmallDot6Scale(a, mod64);
-        // the clippng blitters might overwrite this guy, so we have to reset it each time
-        runs[1] = 1;
-        this->getBlitter()->blitAntiH(x - 1, y, aa, runs);
-        // the clipping blitters might edit runs, but should not affect us
-        SkASSERT(runs[0] == 1);
-        SkASSERT(runs[2] == 0);
-        fx += dx;
-
-        return fx - SK_Fixed1/2;
+        uint8_t a = (uint8_t)(fx >> 8);
+        this->getBlitter()->blitAntiH2(x - 1, y,
+                                       SmallDot6Scale(255 - a, mod64), SmallDot6Scale(a, mod64));
+        
+        return fx + dx - SK_Fixed1/2;
     }
-
+    
     SkFixed drawLine(int y, int stopy, SkFixed fx, SkFixed dx) override {
         SkASSERT(y < stopy);
-        int16_t runs[3];
-        uint8_t  aa[2];
-
-        runs[0] = 1;
-        runs[2] = 0;
-
         fx += SK_Fixed1/2;
         do {
             int x = fx >> 16;
-            uint8_t  a = (uint8_t)(fx >> 8);
-
-            aa[0] = 255 - a;
-            aa[1] = a;
-            // the clippng blitters might overwrite this guy, so we have to reset it each time
-            runs[1] = 1;
-            this->getBlitter()->blitAntiH(x - 1, y, aa, runs);
-            // the clipping blitters might edit runs, but should not affect us
-            SkASSERT(runs[0] == 1);
-            SkASSERT(runs[2] == 0);
+            uint8_t a = (uint8_t)(fx >> 8);
+            this->getBlitter()->blitAntiH2(x - 1, y, 255 - a, a);
             fx += dx;
         } while (++y < stopy);
-
+        
         return fx - SK_Fixed1/2;
     }
 };