Use SkSmallAllocator for tiling.

BUG=skia:

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

Change-Id: If401ea43454b46591d6f39492e7761b16a7e7a29
Reviewed-on: https://skia-review.googlesource.com/4904
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp
index ca42e02..dae6985 100644
--- a/src/core/SkLinearBitmapPipeline.cpp
+++ b/src/core/SkLinearBitmapPipeline.cpp
@@ -139,10 +139,10 @@
         , fXStrategy{dimensions.width()}
         , fYStrategy{dimensions.height()}{ }
 
-    CombinedTileStage(Next* next, const CombinedTileStage& stage)
+    CombinedTileStage(Next* next, CombinedTileStage* stage)
         : fNext{next}
-        , fXStrategy{stage.fXStrategy}
-        , fYStrategy{stage.fYStrategy} { }
+        , fXStrategy{stage->fXStrategy}
+        , fYStrategy{stage->fYStrategy} { }
 
     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
         fXStrategy.tileXPoints(&xs);
@@ -186,60 +186,6 @@
     YStrategy fYStrategy;
 };
 
-template <typename XStrategy, typename Next>
-void choose_tiler_ymode(
-    SkShader::TileMode yMode, SkFilterQuality filterQuality, SkISize dimensions,
-    Next* next,
-    SkLinearBitmapPipeline::TileStage* tileStage) {
-    switch (yMode) {
-        case SkShader::kClamp_TileMode: {
-            using Tiler = CombinedTileStage<XStrategy, YClampStrategy, Next>;
-            tileStage->initStage<Tiler>(next, dimensions);
-            break;
-        }
-        case SkShader::kRepeat_TileMode: {
-            using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, Next>;
-            tileStage->initStage<Tiler>(next, dimensions);
-            break;
-        }
-        case SkShader::kMirror_TileMode: {
-            using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, Next>;
-            tileStage->initStage<Tiler>(next, dimensions);
-            break;
-        }
-    }
-};
-
-static SkLinearBitmapPipeline::PointProcessorInterface* choose_tiler(
-    SkLinearBitmapPipeline::SampleProcessorInterface* next,
-    SkISize dimensions,
-    SkShader::TileMode xMode,
-    SkShader::TileMode yMode,
-    SkFilterQuality filterQuality,
-    SkScalar dx,
-    SkLinearBitmapPipeline::TileStage* tileStage)
-{
-    switch (xMode) {
-        case SkShader::kClamp_TileMode:
-            choose_tiler_ymode<XClampStrategy>(yMode, filterQuality, dimensions, next, tileStage);
-            break;
-        case SkShader::kRepeat_TileMode:
-            if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
-                choose_tiler_ymode<XRepeatUnitScaleStrategy>(
-                    yMode, kNone_SkFilterQuality, dimensions, next, tileStage);
-            } else {
-                choose_tiler_ymode<XRepeatStrategy>(
-                    yMode, filterQuality, dimensions, next, tileStage);
-            }
-            break;
-        case SkShader::kMirror_TileMode:
-            choose_tiler_ymode<XMirrorStrategy>(yMode, filterQuality, dimensions, next, tileStage);
-            break;
-    }
-
-    return tileStage->get();
-}
-
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Specialized Samplers
 
@@ -623,9 +569,9 @@
     auto samplerStage = choose_pixel_sampler(
         blenderStage, filterQuality, xTile, yTile,
         srcPixmap, paintColor, &fSampleStage, &fAccessor);
-    auto tilerStage   = choose_tiler(samplerStage, dimensions, xTile, yTile,
-                                     filterQuality, dx, &fTileStage);
-    fFirstStage       = ChooseMatrix(tilerStage, adjustedInverse);
+    auto tilerStage   = this->chooseTiler(
+        samplerStage, dimensions, xTile, yTile, filterQuality, dx);
+    fFirstStage       = this->chooseMatrix(tilerStage, adjustedInverse);
     fLastStage        = blenderStage;
 }
 
@@ -685,8 +631,7 @@
     }
 
     auto sampleStage = fSampleStage.get();
-    auto tilerStage = pipeline.fTileStage.cloneStageTo(sampleStage, &fTileStage);
-    tilerStage = (tilerStage != nullptr) ? tilerStage : sampleStage;
+    auto tilerStage = pipeline.fTileStageCloner(sampleStage, &fMemory);
     auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, &fMemory);
     fFirstStage = matrixStage;
 }
@@ -708,7 +653,7 @@
 }
 
 SkLinearBitmapPipeline::PointProcessorInterface*
-SkLinearBitmapPipeline::ChooseMatrix(PointProcessorInterface* next, const SkMatrix& inverse) {
+SkLinearBitmapPipeline::chooseMatrix(PointProcessorInterface* next, const SkMatrix& inverse) {
     if (inverse.hasPerspective()) {
         auto matrixStage = fMemory.createT<PerspectiveMatrix<>>(
             next,
@@ -759,3 +704,64 @@
         return next;
     }
 }
+
+template <typename Tiler>
+SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler(
+    SampleProcessorInterface* next, SkISize dimensions) {
+    auto tilerStage = fMemory.createT<Tiler>(next, dimensions);
+    fTileStageCloner =
+        [tilerStage](SampleProcessorInterface* cloneNext,
+                     MemoryAllocator* memory) -> PointProcessorInterface* {
+            return memory->createT<Tiler>(cloneNext, tilerStage);
+        };
+    return tilerStage;
+}
+
+template <typename XStrategy>
+SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTilerYMode(
+    SampleProcessorInterface* next, SkShader::TileMode yMode, SkISize dimensions) {
+    switch (yMode) {
+        case SkShader::kClamp_TileMode: {
+            using Tiler = CombinedTileStage<XStrategy, YClampStrategy, SampleProcessorInterface>;
+            return this->createTiler<Tiler>(next, dimensions);
+        }
+        case SkShader::kRepeat_TileMode: {
+            using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, SampleProcessorInterface>;
+            return this->createTiler<Tiler>(next, dimensions);
+        }
+        case SkShader::kMirror_TileMode: {
+            using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, SampleProcessorInterface>;
+            return this->createTiler<Tiler>(next, dimensions);
+        }
+    }
+
+    // Should never get here.
+    SkFAIL("Not all Y tile cases covered.");
+    return nullptr;
+}
+
+SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTiler(
+    SampleProcessorInterface* next,
+    SkISize dimensions,
+    SkShader::TileMode xMode,
+    SkShader::TileMode yMode,
+    SkFilterQuality filterQuality,
+    SkScalar dx)
+{
+    switch (xMode) {
+        case SkShader::kClamp_TileMode:
+            return this->chooseTilerYMode<XClampStrategy>(next, yMode, dimensions);
+        case SkShader::kRepeat_TileMode:
+            if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
+                return this->chooseTilerYMode<XRepeatUnitScaleStrategy>(next, yMode, dimensions);
+            } else {
+                return this->chooseTilerYMode<XRepeatStrategy>(next, yMode, dimensions);
+            }
+        case SkShader::kMirror_TileMode:
+            return this->chooseTilerYMode<XMirrorStrategy>(next, yMode, dimensions);
+    }
+
+    // Should never get here.
+    SkFAIL("Not all X tile cases covered.");
+    return nullptr;
+}
diff --git a/src/core/SkLinearBitmapPipeline.h b/src/core/SkLinearBitmapPipeline.h
index 3e7be5c..d5c43d9 100644
--- a/src/core/SkLinearBitmapPipeline.h
+++ b/src/core/SkLinearBitmapPipeline.h
@@ -126,24 +126,40 @@
     class PixelAccessorInterface;
 
     // These values were generated by the assert above in Stage::init{Sink|Stage}.
-    using TileStage    = Stage<PointProcessorInterface,     48, SampleProcessorInterface>;
     using SampleStage  = Stage<SampleProcessorInterface,   160, BlendProcessorInterface>;
     using BlenderStage = Stage<BlendProcessorInterface,     48>;
     using Accessor     = PolyMemory<PixelAccessorInterface, 64>;
 
 private:
-    PointProcessorInterface* ChooseMatrix(
+    using MemoryAllocator = SkSmallAllocator<128, 2>;
+    using MatrixCloner =
+        std::function<PointProcessorInterface* (PointProcessorInterface*, MemoryAllocator*)>;
+    using TilerCloner =
+        std::function<PointProcessorInterface* (SampleProcessorInterface*, MemoryAllocator*)>;
+
+    PointProcessorInterface* chooseMatrix(
         PointProcessorInterface* next,
         const SkMatrix& inverse);
 
-    using MemoryAllocator = SkSmallAllocator<64, 1>;
-    using MatrixCloner =
-        std::function<PointProcessorInterface* (PointProcessorInterface*, MemoryAllocator*)>;
+    template <typename Tiler>
+    PointProcessorInterface* createTiler(SampleProcessorInterface* next, SkISize dimensions);
+
+    template <typename XStrategy>
+    PointProcessorInterface* chooseTilerYMode(
+        SampleProcessorInterface* next, SkShader::TileMode yMode, SkISize dimensions);
+
+    PointProcessorInterface* chooseTiler(
+        SampleProcessorInterface* next,
+        SkISize dimensions,
+        SkShader::TileMode xMode,
+        SkShader::TileMode yMode,
+        SkFilterQuality filterQuality,
+        SkScalar dx);
 
     MemoryAllocator          fMemory;
     PointProcessorInterface* fFirstStage;
     MatrixCloner             fMatrixStageCloner;
-    TileStage                fTileStage;
+    TilerCloner              fTileStageCloner;
     SampleStage              fSampleStage;
     BlenderStage             fBlenderStage;
     DestinationInterface*    fLastStage;