Blitter for repeat RGBA8888->RGBA8888.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1852613002

Review URL: https://codereview.chromium.org/1852613002
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index c9df4ce..3b90704 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -121,12 +121,19 @@
                           SkBitmapProcInfo* info)
         : INHERITED(shader, rec, info)
     {
+        // Save things off in case we need to build a blitter pipeline.
+        fSrcPixmap = info->fPixmap;
+        fAlpha = SkColorGetA(info->fPaintColor) / 255.0f;
+        fXMode = info->fTileModeX;
+        fYMode = info->fTileModeY;
+        fFilterQuality = info->fFilterQuality;
+        fMatrixTypeMask = info->fRealInvMatrix.getType();
+
         // Need to ensure that our pipeline is created at a 16byte aligned address
-        fPipeline = (SkLinearBitmapPipeline*)SkAlign16((intptr_t)fStorage);
-        float alpha = SkColorGetA(info->fPaintColor) / 255.0f;
-        new (fPipeline) SkLinearBitmapPipeline(info->fRealInvMatrix, info->fFilterQuality,
+        fShaderPipeline = (SkLinearBitmapPipeline*)SkAlign16((intptr_t)fShaderStorage);
+        new (fShaderPipeline) SkLinearBitmapPipeline(info->fRealInvMatrix, info->fFilterQuality,
                                                info->fTileModeX, info->fTileModeY,
-                                               alpha,
+                                               fAlpha,
                                                info->fPixmap);
 
         // To implement the old shadeSpan entry-point, we need to efficiently convert our native
@@ -138,11 +145,14 @@
 
     ~LinearPipelineContext() override {
         // since we did a manual new, we need to manually destroy as well.
-        fPipeline->~SkLinearBitmapPipeline();
+        fShaderPipeline->~SkLinearBitmapPipeline();
+        if (fBlitterPipeline != nullptr) {
+            fBlitterPipeline->~SkLinearBitmapPipeline();
+        }
     }
 
     void shadeSpan4f(int x, int y, SkPM4f dstC[], int count) override {
-        fPipeline->shadeSpan4f(x, y, dstC, count);
+        fShaderPipeline->shadeSpan4f(x, y, dstC, count);
     }
 
     void shadeSpan(int x, int y, SkPMColor dstC[], int count) override {
@@ -151,7 +161,7 @@
 
         while (count > 0) {
             const int n = SkTMin(count, N);
-            fPipeline->shadeSpan4f(x, y, tmp, n);
+            fShaderPipeline->shadeSpan4f(x, y, tmp, n);
             fXferProc(nullptr, dstC, tmp, n, nullptr);
             dstC += n;
             x += n;
@@ -159,14 +169,53 @@
         }
     }
 
+    bool onChooseBlitProcs(const SkImageInfo& dstInfo, BlitState* state) override {
+        SkXfermode::Mode mode;
+        if (!SkXfermode::AsMode(state->fXfer, &mode)) { return false; }
+
+        // Need to ensure that our pipeline is created at a 16byte aligned address
+        fBlitterPipeline = (SkLinearBitmapPipeline*)SkAlign16((intptr_t)fBlitterStorage);
+        if (SkLinearBitmapPipeline::ClonePipelineForBlitting(
+            fBlitterPipeline, *fShaderPipeline,
+            fMatrixTypeMask,
+            fXMode, fYMode,
+            fFilterQuality, fSrcPixmap,
+            fAlpha, mode, dstInfo)) {
+
+            state->fStorage[0] = fBlitterPipeline;
+            state->fBlitBW = &LinearPipelineContext::ForwardToPipeline;
+
+            return true;
+        }
+
+        // Did not successfully create a pipeline so don't destruct it.
+        fBlitterPipeline = nullptr;
+        return false;
+    }
+
+    static void ForwardToPipeline(BlitState* state, int x, int y, const SkPixmap& dst, int count) {
+        SkLinearBitmapPipeline* pipeline = static_cast<SkLinearBitmapPipeline*>(state->fStorage[0]);
+        void* addr = dst.writable_addr32(x, y);
+        pipeline->blitSpan(x, y, addr, count);
+    }
+
+
 private:
     enum {
         kActualSize = sizeof(SkLinearBitmapPipeline),
         kPaddedSize = SkAlignPtr(kActualSize + 12),
     };
-    void* fStorage[kPaddedSize / sizeof(void*)];
-    SkLinearBitmapPipeline* fPipeline;
+    void* fShaderStorage[kPaddedSize / sizeof(void*)];
+    SkLinearBitmapPipeline* fShaderPipeline;
+    void* fBlitterStorage[kPaddedSize / sizeof(void*)];
+    SkLinearBitmapPipeline* fBlitterPipeline{nullptr};
     SkXfermode::D32Proc     fXferProc;
+    SkPixmap                fSrcPixmap;
+    float                   fAlpha;
+    SkShader::TileMode      fXMode;
+    SkShader::TileMode      fYMode;
+    SkMatrix::TypeMask      fMatrixTypeMask;
+    SkFilterQuality         fFilterQuality;
 
     typedef BitmapProcInfoContext INHERITED;
 };
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h
index 4df2614..f6492f1 100644
--- a/src/core/SkBitmapProcShader.h
+++ b/src/core/SkBitmapProcShader.h
@@ -50,7 +50,7 @@
     typedef SkShader INHERITED;
 };
 
-enum {kSkBlitterContextSize = 2400};
+enum {kSkBlitterContextSize = 3100};
 
 // Commonly used allocator. It currently is only used to allocate up to 3 objects. The total
 // bytes requested is calculated using one of our large shaders, its context size plus the size of
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp
index 539547a..cf69e97 100644
--- a/src/core/SkLinearBitmapPipeline.cpp
+++ b/src/core/SkLinearBitmapPipeline.cpp
@@ -776,8 +776,69 @@
     fLastStage        = blenderStage;
 }
 
+bool SkLinearBitmapPipeline::ClonePipelineForBlitting(
+    void* blitterStorage,
+    const SkLinearBitmapPipeline& pipeline,
+    SkMatrix::TypeMask matrixMask,
+    SkShader::TileMode xTileMode,
+    SkShader::TileMode yTileMode,
+    SkFilterQuality filterQuality,
+    const SkPixmap& srcPixmap,
+    float finalAlpha,
+    SkXfermode::Mode xferMode,
+    const SkImageInfo& dstInfo)
+{
+    if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return false; }
+    if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return false; }
+    if (finalAlpha != 1.0f) { return false; }
+    if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType
+        || dstInfo.colorType() != kRGBA_8888_SkColorType) { return false; }
+
+    if (srcPixmap.info().profileType() != dstInfo.profileType()) { return false; }
+
+    if (xTileMode != SkShader::kRepeat_TileMode || yTileMode != SkShader::kRepeat_TileMode) {
+        return false;
+    }
+
+    if (xferMode == SkXfermode::kSrcOver_Mode
+        && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
+        xferMode = SkXfermode::kSrc_Mode;
+    }
+
+    if (xferMode != SkXfermode::kSrc_Mode) { return false; }
+
+    new (blitterStorage) SkLinearBitmapPipeline(pipeline, srcPixmap, xferMode, dstInfo);
+
+    return true;
+}
+
+SkLinearBitmapPipeline::SkLinearBitmapPipeline(
+    const SkLinearBitmapPipeline& pipeline,
+    const SkPixmap& srcPixmap,
+    SkXfermode::Mode mode,
+    const SkImageInfo& dstInfo)
+{
+    SkASSERT(mode == SkXfermode::kSrc_Mode);
+    SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
+             && srcPixmap.info().colorType() == kRGBA_8888_SkColorType);
+
+    fSampleStage.initSink<RGBA8888UnitRepeat>(srcPixmap.writable_addr32(0, 0), srcPixmap.width());
+    auto sampleStage = fSampleStage.get();
+    auto tilerStage = pipeline.fTileStage.cloneStageTo(sampleStage, &fTileStage);
+    tilerStage = (tilerStage != nullptr) ? tilerStage : sampleStage;
+    auto matrixStage = pipeline.fMatrixStage.cloneStageTo(tilerStage, &fMatrixStage);
+    matrixStage = (matrixStage != nullptr) ? matrixStage : tilerStage;
+    fFirstStage = matrixStage;
+    fLastStage = fSampleStage.getInterface<DestinationInterface, RGBA8888UnitRepeat>();
+}
+
 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
     SkASSERT(count > 0);
+    this->blitSpan(x, y, dst, count);
+}
+
+void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) {
+    SkASSERT(count > 0);
     fLastStage->setDestination(dst, count);
 
     // The count and length arguments start out in a precise relation in order to keep the
diff --git a/src/core/SkLinearBitmapPipeline.h b/src/core/SkLinearBitmapPipeline.h
index 548302e..a6a84b5 100644
--- a/src/core/SkLinearBitmapPipeline.h
+++ b/src/core/SkLinearBitmapPipeline.h
@@ -21,9 +21,25 @@
         SkShader::TileMode xTile, SkShader::TileMode yTile,
         float postAlpha,
         const SkPixmap& srcPixmap);
+
+
+
+    static bool ClonePipelineForBlitting(
+        void* blitterStorage,
+        const SkLinearBitmapPipeline& pipeline,
+        SkMatrix::TypeMask matrixMask,
+        SkShader::TileMode xTileMode,
+        SkShader::TileMode yTileMode,
+        SkFilterQuality filterQuality,
+        const SkPixmap& srcPixmap,
+        float finalAlpha,
+        SkXfermode::Mode xferMode,
+        const SkImageInfo& dstInfo);
+
     ~SkLinearBitmapPipeline();
 
     void shadeSpan4f(int x, int y, SkPM4f* dst, int count);
+    void blitSpan(int32_t x, int32_t y, void* dst, int count);
 
     template<typename Base, size_t kSize, typename Next = void>
     class Stage {
@@ -65,12 +81,18 @@
     class DestinationInterface;
 
     // These values were generated by the assert above in Stage::init{Sink|Stage}.
-    using MatrixStage  = Stage<PointProcessorInterface, 160, PointProcessorInterface>;
-    using TileStage    = Stage<PointProcessorInterface, 160, SampleProcessorInterface>;
+    using MatrixStage  = Stage<PointProcessorInterface,  160, PointProcessorInterface>;
+    using TileStage    = Stage<PointProcessorInterface,  160, SampleProcessorInterface>;
     using SampleStage  = Stage<SampleProcessorInterface, 100, BlendProcessorInterface>;
-    using BlenderStage = Stage<BlendProcessorInterface, 80>;
+    using BlenderStage = Stage<BlendProcessorInterface,   40>;
 
 private:
+    SkLinearBitmapPipeline(
+        const SkLinearBitmapPipeline& pipeline,
+        const SkPixmap& srcPixmap,
+        SkXfermode::Mode xferMode,
+        const SkImageInfo& dstInfo);
+
     PointProcessorInterface* fFirstStage;
     MatrixStage              fMatrixStage;
     TileStage                fTileStage;