Buffer four scanlines prior to blitting. We will eventually use this
authorkrajcevski <krajcevski@google.com>
Wed, 16 Jul 2014 20:31:41 +0000 (13:31 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 16 Jul 2014 20:31:41 +0000 (13:31 -0700)
to blit four scanlines in a row in order to aggressively compress alpha
masks as the information comes in. This CL is only to introduce the API
and to make sure that nothing breaks in the general case.

R=reed@google.com, robertphillips@google.com

Author: krajcevski@google.com

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

src/core/SkBlitter.h
src/core/SkScan_AntiPath.cpp

index a3a2196..0f1006f 100644 (file)
@@ -33,6 +33,7 @@ public:
     /// zero-terminated run-length encoding of spans of constant alpha values.
     virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
                            const int16_t runs[]);
+
     /// Blit a vertical run of pixels with a constant alpha value.
     virtual void blitV(int x, int y, int height, SkAlpha alpha);
     /// Blit a solid rectangle one or more pixels wide.
@@ -67,6 +68,14 @@ public:
     virtual bool resetShaderContext(const SkShader::ContextRec&);
     virtual SkShader::Context* getShaderContext() const;
 
+    /**
+     * Special methods for blitters that can blit more than one row at a time.
+     * This function returns the number of rows that this blitter could optimally
+     * process at a time. It is still required to support blitting one scanline
+     * at a time.
+     */
+    virtual int requestRowsPreserved() const { return 1; }
+
     ///@name non-virtual helpers
     void blitMaskRegion(const SkMask& mask, const SkRegion& clip);
     void blitRectRegion(const SkIRect& rect, const SkRegion& clip);
index e5c67a9..0943646 100644 (file)
@@ -108,7 +108,7 @@ public:
 
     virtual ~SuperBlitter() {
         this->flush();
-        sk_free(fRuns.fRuns);
+        sk_free(fRunsBuffer);
     }
 
     /// Once fRuns contains a complete supersampled row, flush() blits
@@ -123,31 +123,56 @@ public:
     virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
 
 private:
+    // The next three variables are used to track a circular buffer that
+    // contains the values used in SkAlphaRuns. These variables should only
+    // ever be updated in advanceRuns(), and fRuns should always point to
+    // a valid SkAlphaRuns...
+    int         fRunsToBuffer;
+    void*       fRunsBuffer;
+    int         fCurrentRun;
     SkAlphaRuns fRuns;
+
+    // extra one to store the zero at the end
+    int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof(int16_t); }
+
+    // This function updates the fRuns variable to point to the next buffer space
+    // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun
+    // and resets fRuns to point to an empty scanline.
+    void advanceRuns() {
+        const size_t kRunsSz = this->getRunsSz();
+        fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer;
+        fRuns.fRuns = reinterpret_cast<int16_t*>(
+            reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz);
+        fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1);
+        fRuns.reset(fWidth);
+    }
+
     int         fOffsetX;
 };
 
 SuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
                            const SkRegion& clip)
         : BaseSuperBlitter(realBlitter, ir, clip) {
-    const int width = fWidth;
+    fRunsToBuffer = realBlitter->requestRowsPreserved();
+    fRunsBuffer = sk_malloc_throw(fRunsToBuffer * this->getRunsSz());
+    fCurrentRun = -1;
 
-    // extra one to store the zero at the end
-    fRuns.fRuns = (int16_t*)sk_malloc_throw((width + 1 + (width + 2)/2) * sizeof(int16_t));
-    fRuns.fAlpha = (uint8_t*)(fRuns.fRuns + width + 1);
-    fRuns.reset(width);
+    this->advanceRuns();
 
     fOffsetX = 0;
 }
 
 void SuperBlitter::flush() {
     if (fCurrIY >= fTop) {
+
+        SkASSERT(fCurrentRun < fRunsToBuffer);
         if (!fRuns.empty()) {
-        //  SkDEBUGCODE(fRuns.dump();)
+            // SkDEBUGCODE(fRuns.dump();)
             fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
-            fRuns.reset(fWidth);
+            this->advanceRuns();
             fOffsetX = 0;
         }
+
         fCurrIY = fTop - 1;
         SkDEBUGCODE(fCurrX = -1;)
     }