Convert SkRasterPipeline loads and stores to indirect.

This allows us to change the underlying pointer without rebuilding the pipeline, e.g. when moving the blitter from scanline to scanline.

The extra overhead when not needed is measurable but small, <2%.  We can always add back direct stages later for cases where we know the context pointer will not change.

BUG=skia:

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=3943

Change-Id: I827d7e6e4e67d02dd2802610f898f98c5f36f8cb
Reviewed-on: https://skia-review.googlesource.com/3943
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/src/core/SkRasterPipelineBlitter.cpp b/src/core/SkRasterPipelineBlitter.cpp
index ec634c8..51c2fc1 100644
--- a/src/core/SkRasterPipelineBlitter.cpp
+++ b/src/core/SkRasterPipelineBlitter.cpp
@@ -47,6 +47,18 @@
     SkRasterPipeline fShader, fColorFilter, fXfermode;
     SkPM4f           fPaintColor;
 
+    // These functions are compiled lazily when first used.
+    std::function<void(size_t, size_t)> fBlitH         = nullptr,
+                                        fBlitAntiH     = nullptr,
+                                        fBlitMaskA8    = nullptr,
+                                        fBlitMaskLCD16 = nullptr;
+
+    // These values are pointed to by the compiled blit functions
+    // above, which allows us to adjust them from call to call.
+    void*       fDstPtr           = nullptr;
+    const void* fMaskPtr          = nullptr;
+    float       fConstantCoverage = 0.0f;
+
     typedef SkBlitter INHERITED;
 };
 
@@ -152,33 +164,36 @@
 // TODO: Figure out how to cache some of the compiled pipelines.
 
 void SkRasterPipelineBlitter::blitH(int x, int y, int w) {
-    auto dst = fDst.writable_addr(0,y);
+    if (!fBlitH) {
+        SkRasterPipeline p;
+        p.extend(fShader);
+        p.extend(fColorFilter);
+        this->append_load_d(&p, &fDstPtr);
+        p.extend(fXfermode);
+        this->append_store(&p, &fDstPtr);
+        fBlitH = p.compile();
+    }
 
-    SkRasterPipeline p;
-    p.extend(fShader);
-    p.extend(fColorFilter);
-    this->append_load_d(&p, dst);
-    p.extend(fXfermode);
-    this->append_store(&p, dst);
-
-    p.compile()(x,w);
+    fDstPtr = fDst.writable_addr(0,y);
+    fBlitH(x,w);
 }
 
 void SkRasterPipelineBlitter::blitAntiH(int x, int y, const SkAlpha aa[], const int16_t runs[]) {
-    auto dst = fDst.writable_addr(0,y);
-    float coverage;
+    if (!fBlitAntiH) {
+        SkRasterPipeline p;
+        p.extend(fShader);
+        p.extend(fColorFilter);
+        this->append_load_d(&p, &fDstPtr);
+        p.extend(fXfermode);
+        p.append(SkRasterPipeline::lerp_constant_float, &fConstantCoverage);
+        this->append_store(&p, &fDstPtr);
+        fBlitAntiH = p.compile();
+    }
 
-    SkRasterPipeline p;
-    p.extend(fShader);
-    p.extend(fColorFilter);
-    this->append_load_d(&p, dst);
-    p.extend(fXfermode);
-    p.append(SkRasterPipeline::lerp_constant_float, &coverage);
-    this->append_store(&p, dst);
-
+    fDstPtr = fDst.writable_addr(0,y);
     for (int16_t run = *runs; run > 0; run = *runs) {
-        coverage = *aa * (1/255.0f);
-        p.compile()(x, run);
+        fConstantCoverage = *aa * (1/255.0f);
+        fBlitAntiH(x, run);
 
         x    += run;
         runs += run;
@@ -192,26 +207,44 @@
         return INHERITED::blitMask(mask, clip);
     }
 
-    int x = clip.left();
-    for (int y = clip.top(); y < clip.bottom(); y++) {
-        auto dst = fDst.writable_addr(0,y);
-
+    if (mask.fFormat == SkMask::kA8_Format && !fBlitMaskA8) {
         SkRasterPipeline p;
         p.extend(fShader);
         p.extend(fColorFilter);
-        this->append_load_d(&p, dst);
+        this->append_load_d(&p, &fDstPtr);
         p.extend(fXfermode);
+        p.append(SkRasterPipeline::lerp_u8, &fMaskPtr);
+        this->append_store(&p, &fDstPtr);
+        fBlitMaskA8 = p.compile();
+    }
+
+    if (mask.fFormat == SkMask::kLCD16_Format && !fBlitMaskLCD16) {
+        SkRasterPipeline p;
+        p.extend(fShader);
+        p.extend(fColorFilter);
+        this->append_load_d(&p, &fDstPtr);
+        p.extend(fXfermode);
+        p.append(SkRasterPipeline::lerp_565, &fMaskPtr);
+        this->append_store(&p, &fDstPtr);
+        fBlitMaskLCD16 = p.compile();
+    }
+
+    int x = clip.left();
+    for (int y = clip.top(); y < clip.bottom(); y++) {
+        fDstPtr = fDst.writable_addr(0,y);
+
         switch (mask.fFormat) {
             case SkMask::kA8_Format:
-                p.append(SkRasterPipeline::lerp_u8, mask.getAddr8(x,y)-x);
+                fMaskPtr = mask.getAddr8(x,y)-x;
+                fBlitMaskA8(x, clip.width());
                 break;
             case SkMask::kLCD16_Format:
-                p.append(SkRasterPipeline::lerp_565, mask.getAddrLCD16(x,y)-x);
+                fMaskPtr = mask.getAddrLCD16(x,y)-x;
+                fBlitMaskLCD16(x, clip.width());
                 break;
-            default: break;
+            default:
+                // TODO
+                break;
         }
-        this->append_store(&p, dst);
-
-        p.compile()(x, clip.width());
     }
 }