Use SkFixedAllocator in SkLinearPipeline and remove the embedding of
the entire pipeline.

Adjust SkFixedAlloc to allow nesting of allocation.

BUG=skia:

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

Change-Id: Ieeb1b5deaae004b67cee933af9bc19bbfd5a7687
Reviewed-on: https://skia-review.googlesource.com/4987
Commit-Queue: Herb Derby <herb@google.com>
Reviewed-by: Mike Klein <mtklein@chromium.org>
diff --git a/bench/SkLinearBitmapPipelineBench.cpp b/bench/SkLinearBitmapPipelineBench.cpp
index d669ed9..8582ce9 100644
--- a/bench/SkLinearBitmapPipelineBench.cpp
+++ b/bench/SkLinearBitmapPipelineBench.cpp
@@ -6,13 +6,14 @@
  */
 
 #include <memory>
-#include "SkColor.h"
-#include "SkLinearBitmapPipeline.h"
-#include "SkBitmapProcShader.h"
-#include "SkPM4f.h"
 #include "Benchmark.h"
-#include "SkShader.h"
+#include "SkBitmapProcShader.h"
+#include "SkColor.h"
+#include "SkFixedAlloc.h"
 #include "SkImage.h"
+#include "SkLinearBitmapPipeline.h"
+#include "SkPM4f.h"
+#include "SkShader.h"
 
 struct CommonBitmapFPBenchmark : public Benchmark {
     CommonBitmapFPBenchmark(
@@ -146,8 +147,12 @@
 
         SkPixmap srcPixmap{fInfo, fBitmap.get(), static_cast<size_t>(4 * width)};
 
+
+        char storage[600];
+        SkFixedAlloc fixedAlloc{storage, sizeof(storage)};
+        SkFallbackAlloc allocator{&fixedAlloc};
         SkLinearBitmapPipeline pipeline{
-            fInvert, filterQuality, fXTile, fYTile, SK_ColorBLACK, srcPixmap};
+            fInvert, filterQuality, fXTile, fYTile, SK_ColorBLACK, srcPixmap, &allocator};
 
         int count = 100;
 
diff --git a/gm/SkLinearBitmapPipelineGM.cpp b/gm/SkLinearBitmapPipelineGM.cpp
index 13f6004..bde8ee8 100644
--- a/gm/SkLinearBitmapPipelineGM.cpp
+++ b/gm/SkLinearBitmapPipelineGM.cpp
@@ -115,9 +115,13 @@
     uint32_t flags = 0;
     auto procN = SkXfermode::GetD32Proc(SkBlendMode::kSrcOver, flags);
 
+    char storage[512];
+    SkFixedAlloc fixedAlloc{storage, sizeof(storage)};
+    SkFallbackAlloc allocator{&fixedAlloc};
     SkLinearBitmapPipeline pipeline{
             inv, filterQuality,
-            SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, SK_ColorBLACK, pmsrc};
+            SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode,
+            SK_ColorBLACK, pmsrc, &allocator};
 
     for (int y = 0; y < ir.height(); y++) {
         pipeline.shadeSpan4f(0, y, dstBits, ir.width());
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index b17d3e3..8ec1575 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -113,16 +113,15 @@
         // 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();
 
-        fShaderPipeline.init(
+        fShaderPipeline = fAllocator.make<SkLinearBitmapPipeline>(
             info->fRealInvMatrix, info->fFilterQuality,
             info->fTileModeX, info->fTileModeY,
             info->fPaintColor,
-            info->fPixmap);
+            info->fPixmap,
+            &fAllocator);
 
         // To implement the old shadeSpan entry-point, we need to efficiently convert our native
         // floats into SkPMColor. The SkXfermode::D32Procs do exactly that.
@@ -149,14 +148,13 @@
     }
 
     bool onChooseBlitProcs(const SkImageInfo& dstInfo, BlitState* state) override {
-        if (SkLinearBitmapPipeline::ClonePipelineForBlitting(
-            &fBlitterPipeline, *fShaderPipeline,
+        if ((fBlitterPipeline = SkLinearBitmapPipeline::ClonePipelineForBlitting(
+            *fShaderPipeline,
             fMatrixTypeMask,
-            fXMode, fYMode,
             fFilterQuality, fSrcPixmap,
-            fAlpha, state->fMode, dstInfo))
+            fAlpha, state->fMode, dstInfo, &fAllocator)))
         {
-            state->fStorage[0] = fBlitterPipeline.get();
+            state->fStorage[0] = fBlitterPipeline;
             state->fBlitBW = &LinearPipelineContext::ForwardToPipeline;
 
             return true;
@@ -172,15 +170,16 @@
     }
 
 private:
-    SkEmbeddableLinearPipeline fShaderPipeline;
-    SkEmbeddableLinearPipeline fBlitterPipeline;
-    SkXfermode::D32Proc        fSrcModeProc;
-    SkPixmap                   fSrcPixmap;
-    float                      fAlpha;
-    SkShader::TileMode         fXMode;
-    SkShader::TileMode         fYMode;
-    SkMatrix::TypeMask         fMatrixTypeMask;
-    SkFilterQuality            fFilterQuality;
+    char                    fStorage[512 + 96];
+    SkFixedAlloc            fFixedAlloc {fStorage, sizeof(fStorage)};
+    SkFallbackAlloc         fAllocator {&fFixedAlloc};
+    SkLinearBitmapPipeline* fShaderPipeline;
+    SkLinearBitmapPipeline* fBlitterPipeline;
+    SkXfermode::D32Proc     fSrcModeProc;
+    SkPixmap                fSrcPixmap;
+    float                   fAlpha;
+    SkMatrix::TypeMask      fMatrixTypeMask;
+    SkFilterQuality         fFilterQuality;
 
     typedef BitmapProcInfoContext INHERITED;
 };
diff --git a/src/core/SkFixedAlloc.h b/src/core/SkFixedAlloc.h
index d4e4d8f..8d55cc7 100644
--- a/src/core/SkFixedAlloc.h
+++ b/src/core/SkFixedAlloc.h
@@ -35,9 +35,8 @@
         // Skip ahead until our buffer is aligned for T.
         fUsed += skip;
 
-        // Create the T.
+        // Make space for T.
         auto ptr = (T*)(fBuffer+fUsed);
-        new (ptr) T(std::forward<Args>(args)...);
         fUsed += sizeof(T);
 
         // Stamp a footer after the T that we can use to clean it up.
@@ -45,7 +44,8 @@
         memcpy(fBuffer+fUsed, &footer, sizeof(Footer));
         fUsed += sizeof(Footer);
 
-        return ptr;
+        // Creating a T must be last for nesting to work.
+        return new (ptr) T(std::forward<Args>(args)...);
     }
 
     // Destroys the last object allocated and frees its space in the buffer.
@@ -78,9 +78,10 @@
                 return ptr;
             }
         }
-        auto ptr = new T(std::forward<Args>(args)...);
-        fHeapAllocs.push_back({[](void* ptr) { delete (T*)ptr; }, ptr});
-        return ptr;
+
+        char* ptr = new char[sizeof(T)];
+        fHeapAllocs.push_back({[](char* ptr) { ((T*)ptr)->~T(); delete [] ptr; }, ptr});
+        return new (ptr) T(std::forward<Args>(args)...);
     }
 
     // Destroys the last object allocated and frees any space it used in the SkFixedAlloc.
@@ -91,8 +92,8 @@
 
 private:
     struct HeapAlloc {
-        void (*deleter)(void*);
-        void* ptr;
+        void (*deleter)(char*);
+        char* ptr;
     };
 
     SkFixedAlloc*          fFixedAlloc;
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp
index b32ff2d..9e8b419 100644
--- a/src/core/SkLinearBitmapPipeline.cpp
+++ b/src/core/SkLinearBitmapPipeline.cpp
@@ -12,6 +12,7 @@
 #include <limits>
 #include <tuple>
 
+#include "SkFixedAlloc.h"
 #include "SkLinearBitmapPipeline_core.h"
 #include "SkLinearBitmapPipeline_matrix.h"
 #include "SkLinearBitmapPipeline_tile.h"
@@ -349,7 +350,8 @@
     SkFilterQuality filterQuality,
     SkShader::TileMode xTile, SkShader::TileMode yTile,
     SkColor paintColor,
-    const SkPixmap& srcPixmap)
+    const SkPixmap& srcPixmap,
+    SkFallbackAlloc* allocator)
 {
     SkISize dimensions = srcPixmap.info().dimensions();
     const SkImageInfo& srcImageInfo = srcPixmap.info();
@@ -377,55 +379,21 @@
     float postAlpha = SkColorGetA(paintColor) * (1.0f / 255.0f);
     // As the stages are built, the chooser function may skip a stage. For example, with the
     // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
-    auto blenderStage = this->chooseBlenderForShading(alphaType, postAlpha);
+    auto blenderStage = this->chooseBlenderForShading(alphaType, postAlpha, allocator);
     auto samplerStage = this->chooseSampler(
-        blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor);
+        blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor, allocator);
     auto tilerStage   = this->chooseTiler(
-        samplerStage, dimensions, xTile, yTile, filterQuality, dx);
-    fFirstStage       = this->chooseMatrix(tilerStage, adjustedInverse);
+        samplerStage, dimensions, xTile, yTile, filterQuality, dx, allocator);
+    fFirstStage       = this->chooseMatrix(tilerStage, adjustedInverse, allocator);
     fLastStage        = blenderStage;
 }
 
-bool SkLinearBitmapPipeline::ClonePipelineForBlitting(
-    SkEmbeddableLinearPipeline* pipelineStorage,
-    const SkLinearBitmapPipeline& pipeline,
-    SkMatrix::TypeMask matrixMask,
-    SkShader::TileMode xTileMode,
-    SkShader::TileMode yTileMode,
-    SkFilterQuality filterQuality,
-    const SkPixmap& srcPixmap,
-    float finalAlpha,
-    SkBlendMode blendMode,
-    const SkImageInfo& dstInfo)
-{
-    if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
-        blendMode = SkBlendMode::kSrc;
-    }
-
-    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().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) {
-        return false;
-    }
-
-    if (blendMode != SkBlendMode::kSrc && blendMode != SkBlendMode::kSrcOver) {
-        return false;
-    }
-
-    pipelineStorage->init(pipeline, srcPixmap, blendMode, dstInfo);
-
-    return true;
-}
-
 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
     const SkLinearBitmapPipeline& pipeline,
     const SkPixmap& srcPixmap,
     SkBlendMode mode,
-    const SkImageInfo& dstInfo)
+    const SkImageInfo& dstInfo,
+    SkFallbackAlloc* allocator)
 {
     SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
     SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
@@ -433,22 +401,54 @@
 
     SampleProcessorInterface* sampleStage;
     if (mode == SkBlendMode::kSrc) {
-        auto sampler = fMemory.createT<RGBA8888UnitRepeatSrc>(
+        auto sampler = allocator->make<RGBA8888UnitRepeatSrc>(
             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
         sampleStage = sampler;
         fLastStage = sampler;
     } else {
-        auto sampler = fMemory.createT<RGBA8888UnitRepeatSrcOver>(
+        auto sampler = allocator->make<RGBA8888UnitRepeatSrcOver>(
             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
         sampleStage = sampler;
         fLastStage = sampler;
     }
 
-    auto tilerStage = pipeline.fTileStageCloner(sampleStage, &fMemory);
-    auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, &fMemory);
+    auto tilerStage = pipeline.fTileStageCloner(sampleStage, allocator);
+    auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, allocator);
     fFirstStage = matrixStage;
 }
 
+SkLinearBitmapPipeline* SkLinearBitmapPipeline::ClonePipelineForBlitting(
+    const SkLinearBitmapPipeline& pipeline,
+    SkMatrix::TypeMask matrixMask,
+    SkFilterQuality filterQuality,
+    const SkPixmap& srcPixmap,
+    float finalAlpha,
+    SkBlendMode blendMode,
+    const SkImageInfo& dstInfo,
+    SkFallbackAlloc* allocator)
+{
+    if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
+        blendMode = SkBlendMode::kSrc;
+    }
+
+    if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return nullptr; }
+    if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return nullptr; }
+    if (finalAlpha != 1.0f) { return nullptr; }
+    if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType
+        || dstInfo.colorType() != kRGBA_8888_SkColorType) { return nullptr; }
+
+    if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) {
+        return nullptr;
+    }
+
+    if (blendMode != SkBlendMode::kSrc && blendMode != SkBlendMode::kSrcOver) {
+        return nullptr;
+    }
+
+    return allocator->make<SkLinearBitmapPipeline>(
+        pipeline, srcPixmap, blendMode, dstInfo, allocator);
+}
+
 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
     SkASSERT(count > 0);
     this->blitSpan(x, y, dst, count);
@@ -466,9 +466,13 @@
 }
 
 SkLinearBitmapPipeline::PointProcessorInterface*
-SkLinearBitmapPipeline::chooseMatrix(PointProcessorInterface* next, const SkMatrix& inverse) {
+SkLinearBitmapPipeline::chooseMatrix(
+    PointProcessorInterface* next,
+    const SkMatrix& inverse,
+    SkFallbackAlloc* allocator)
+{
     if (inverse.hasPerspective()) {
-        auto matrixStage = fMemory.createT<PerspectiveMatrix<>>(
+        auto matrixStage = allocator->make<PerspectiveMatrix<>>(
             next,
             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
             SkVector{inverse.getScaleX(), inverse.getScaleY()},
@@ -476,42 +480,42 @@
             SkVector{inverse.getPerspX(), inverse.getPerspY()},
             inverse.get(SkMatrix::kMPersp2));
         fMatrixStageCloner =
-            [matrixStage](PointProcessorInterface* cloneNext, MemoryAllocator* memory) {
-                return memory->createT<PerspectiveMatrix<>>(cloneNext, matrixStage);
+            [matrixStage](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
+                return memory->make<PerspectiveMatrix<>>(cloneNext, matrixStage);
             };
         return matrixStage;
     } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
-        auto matrixStage = fMemory.createT<AffineMatrix<>>(
+        auto matrixStage = allocator->make<AffineMatrix<>>(
             next,
             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
             SkVector{inverse.getScaleX(), inverse.getScaleY()},
             SkVector{inverse.getSkewX(), inverse.getSkewY()});
         fMatrixStageCloner =
-            [matrixStage](PointProcessorInterface* cloneNext, MemoryAllocator* memory) {
-                return memory->createT<AffineMatrix<>>(cloneNext, matrixStage);
+            [matrixStage](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
+                return memory->make<AffineMatrix<>>(cloneNext, matrixStage);
             };
         return matrixStage;
     } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
-        auto matrixStage = fMemory.createT<ScaleMatrix<>>(
+        auto matrixStage = allocator->make<ScaleMatrix<>>(
             next,
             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
             SkVector{inverse.getScaleX(), inverse.getScaleY()});
         fMatrixStageCloner =
-            [matrixStage](PointProcessorInterface* cloneNext, MemoryAllocator* memory) {
-                return memory->createT<ScaleMatrix<>>(cloneNext, matrixStage);
+            [matrixStage](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
+                return memory->make<ScaleMatrix<>>(cloneNext, matrixStage);
             };
         return matrixStage;
     } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
-        auto matrixStage = fMemory.createT<TranslateMatrix<>>(
+        auto matrixStage = allocator->make<TranslateMatrix<>>(
             next,
             SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
         fMatrixStageCloner =
-            [matrixStage](PointProcessorInterface* cloneNext, MemoryAllocator* memory) {
-                return memory->createT<TranslateMatrix<>>(cloneNext, matrixStage);
+            [matrixStage](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
+                return memory->make<TranslateMatrix<>>(cloneNext, matrixStage);
             };
         return matrixStage;
     } else {
-        fMatrixStageCloner = [](PointProcessorInterface* cloneNext, MemoryAllocator* memory) {
+        fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkFallbackAlloc* memory) {
             return cloneNext;
         };
         return next;
@@ -520,31 +524,38 @@
 
 template <typename Tiler>
 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler(
-    SampleProcessorInterface* next, SkISize dimensions) {
-    auto tilerStage = fMemory.createT<Tiler>(next, dimensions);
+    SampleProcessorInterface* next,
+    SkISize dimensions,
+    SkFallbackAlloc* allocator)
+{
+    auto tilerStage = allocator->make<Tiler>(next, dimensions);
     fTileStageCloner =
         [tilerStage](SampleProcessorInterface* cloneNext,
-                     MemoryAllocator* memory) -> PointProcessorInterface* {
-            return memory->createT<Tiler>(cloneNext, tilerStage);
+                     SkFallbackAlloc* memory) -> PointProcessorInterface* {
+            return memory->make<Tiler>(cloneNext, tilerStage);
         };
     return tilerStage;
 }
 
 template <typename XStrategy>
 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTilerYMode(
-    SampleProcessorInterface* next, SkShader::TileMode yMode, SkISize dimensions) {
+    SampleProcessorInterface* next,
+    SkShader::TileMode yMode,
+    SkISize dimensions,
+    SkFallbackAlloc* allocator)
+{
     switch (yMode) {
         case SkShader::kClamp_TileMode: {
             using Tiler = CombinedTileStage<XStrategy, YClampStrategy, SampleProcessorInterface>;
-            return this->createTiler<Tiler>(next, dimensions);
+            return this->createTiler<Tiler>(next, dimensions, allocator);
         }
         case SkShader::kRepeat_TileMode: {
             using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, SampleProcessorInterface>;
-            return this->createTiler<Tiler>(next, dimensions);
+            return this->createTiler<Tiler>(next, dimensions, allocator);
         }
         case SkShader::kMirror_TileMode: {
             using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, SampleProcessorInterface>;
-            return this->createTiler<Tiler>(next, dimensions);
+            return this->createTiler<Tiler>(next, dimensions, allocator);
         }
     }
 
@@ -559,19 +570,22 @@
     SkShader::TileMode xMode,
     SkShader::TileMode yMode,
     SkFilterQuality filterQuality,
-    SkScalar dx)
+    SkScalar dx,
+    SkFallbackAlloc* allocator)
 {
     switch (xMode) {
         case SkShader::kClamp_TileMode:
-            return this->chooseTilerYMode<XClampStrategy>(next, yMode, dimensions);
+            return this->chooseTilerYMode<XClampStrategy>(next, yMode, dimensions, allocator);
         case SkShader::kRepeat_TileMode:
             if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
-                return this->chooseTilerYMode<XRepeatUnitScaleStrategy>(next, yMode, dimensions);
+                return this->chooseTilerYMode<XRepeatUnitScaleStrategy>(
+                    next, yMode, dimensions, allocator);
             } else {
-                return this->chooseTilerYMode<XRepeatStrategy>(next, yMode, dimensions);
+                return this->chooseTilerYMode<XRepeatStrategy>(
+                    next, yMode, dimensions, allocator);
             }
         case SkShader::kMirror_TileMode:
-            return this->chooseTilerYMode<XMirrorStrategy>(next, yMode, dimensions);
+            return this->chooseTilerYMode<XMirrorStrategy>(next, yMode, dimensions, allocator);
     }
 
     // Should never get here.
@@ -582,43 +596,45 @@
 template <SkColorType colorType>
 SkLinearBitmapPipeline::PixelAccessorInterface*
     SkLinearBitmapPipeline::chooseSpecificAccessor(
-    const SkPixmap& srcPixmap)
+    const SkPixmap& srcPixmap,
+    SkFallbackAlloc* allocator)
 {
     if (srcPixmap.info().gammaCloseToSRGB()) {
         using Accessor = PixelAccessor<colorType, kSRGB_SkGammaType>;
-        return fMemory.createT<Accessor>(srcPixmap);
+        return allocator->make<Accessor>(srcPixmap);
     } else {
         using Accessor = PixelAccessor<colorType, kLinear_SkGammaType>;
-        return fMemory.createT<Accessor>(srcPixmap);
+        return allocator->make<Accessor>(srcPixmap);
     }
 }
 
 SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor(
     const SkPixmap& srcPixmap,
-    const SkColor A8TintColor)
+    const SkColor A8TintColor,
+    SkFallbackAlloc* allocator)
 {
     const SkImageInfo& imageInfo = srcPixmap.info();
 
     switch (imageInfo.colorType()) {
         case kAlpha_8_SkColorType: {
             using Accessor = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>;
-            return fMemory.createT<Accessor>(srcPixmap, A8TintColor);
+            return allocator->make<Accessor>(srcPixmap, A8TintColor);
         }
         case kARGB_4444_SkColorType:
-            return this->chooseSpecificAccessor<kARGB_4444_SkColorType>(srcPixmap);
+            return this->chooseSpecificAccessor<kARGB_4444_SkColorType>(srcPixmap, allocator);
         case kRGB_565_SkColorType:
-            return this->chooseSpecificAccessor<kRGB_565_SkColorType>(srcPixmap);
+            return this->chooseSpecificAccessor<kRGB_565_SkColorType>(srcPixmap, allocator);
         case kRGBA_8888_SkColorType:
-            return this->chooseSpecificAccessor<kRGBA_8888_SkColorType>(srcPixmap);
+            return this->chooseSpecificAccessor<kRGBA_8888_SkColorType>(srcPixmap, allocator);
         case kBGRA_8888_SkColorType:
-            return this->chooseSpecificAccessor<kBGRA_8888_SkColorType>(srcPixmap);
+            return this->chooseSpecificAccessor<kBGRA_8888_SkColorType>(srcPixmap, allocator);
         case kIndex_8_SkColorType:
-            return this->chooseSpecificAccessor<kIndex_8_SkColorType>(srcPixmap);
+            return this->chooseSpecificAccessor<kIndex_8_SkColorType>(srcPixmap, allocator);
         case kGray_8_SkColorType:
-            return this->chooseSpecificAccessor<kGray_8_SkColorType>(srcPixmap);
+            return this->chooseSpecificAccessor<kGray_8_SkColorType>(srcPixmap, allocator);
         case kRGBA_F16_SkColorType: {
             using Accessor = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
-            return fMemory.createT<Accessor>(srcPixmap);
+            return allocator->make<Accessor>(srcPixmap);
         }
         default:
             // Should never get here.
@@ -632,7 +648,8 @@
     SkFilterQuality filterQuality,
     SkShader::TileMode xTile, SkShader::TileMode yTile,
     const SkPixmap& srcPixmap,
-    const SkColor A8TintColor)
+    const SkColor A8TintColor,
+    SkFallbackAlloc* allocator)
 {
     const SkImageInfo& imageInfo = srcPixmap.info();
     SkISize dimensions = imageInfo.dimensions();
@@ -645,13 +662,13 @@
                     using Sampler =
                     NearestNeighborSampler<
                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
-                    return fMemory.createT<Sampler>(next, srcPixmap);
+                    return allocator->make<Sampler>(next, srcPixmap);
                 }
                 case kIndex_8_SkColorType: {
                     using Sampler =
                     NearestNeighborSampler<
                         PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
-                    return fMemory.createT<Sampler>(next, srcPixmap);
+                    return allocator->make<Sampler>(next, srcPixmap);
                 }
                 default:
                     break;
@@ -662,13 +679,13 @@
                     using Sampler =
                     BilerpSampler<
                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
-                    return fMemory.createT<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
+                    return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
                 }
                 case kIndex_8_SkColorType: {
                     using Sampler =
                     BilerpSampler<
                         PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
-                    return fMemory.createT<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
+                    return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
                 }
                 default:
                     break;
@@ -676,24 +693,26 @@
         }
     }
 
-    auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor);
+    auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor, allocator);
     // General cases.
     if (filterQuality == kNone_SkFilterQuality) {
         using Sampler = NearestNeighborSampler<PixelAccessorShim, Blender>;
-        return fMemory.createT<Sampler>(next, pixelAccessor);
+        return allocator->make<Sampler>(next, pixelAccessor);
     } else {
         using Sampler = BilerpSampler<PixelAccessorShim, Blender>;
-        return fMemory.createT<Sampler>(next, dimensions, xTile, yTile, pixelAccessor);
+        return allocator->make<Sampler>(next, dimensions, xTile, yTile, pixelAccessor);
     }
 }
 
 Blender* SkLinearBitmapPipeline::chooseBlenderForShading(
     SkAlphaType alphaType,
-    float postAlpha) {
+    float postAlpha,
+    SkFallbackAlloc* allocator)
+{
     if (alphaType == kUnpremul_SkAlphaType) {
-        return fMemory.createT<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
+        return allocator->make<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
     } else {
         // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
-        return fMemory.createT<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha);
+        return allocator->make<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha);
     }
 }
diff --git a/src/core/SkLinearBitmapPipeline.h b/src/core/SkLinearBitmapPipeline.h
index 472772e..62d2201 100644
--- a/src/core/SkLinearBitmapPipeline.h
+++ b/src/core/SkLinearBitmapPipeline.h
@@ -9,10 +9,10 @@
 #define SkLinearBitmapPipeline_DEFINED
 
 #include "SkColor.h"
+#include "SkFixedAlloc.h"
 #include "SkImageInfo.h"
 #include "SkMatrix.h"
 #include "SkShader.h"
-#include "SkSmallAllocator.h"
 
 class SkEmbeddableLinearPipeline;
 
@@ -33,25 +33,25 @@
         SkFilterQuality filterQuality,
         SkShader::TileMode xTile, SkShader::TileMode yTile,
         SkColor paintColor,
-        const SkPixmap& srcPixmap);
+        const SkPixmap& srcPixmap,
+        SkFallbackAlloc* allocator);
 
     SkLinearBitmapPipeline(
         const SkLinearBitmapPipeline& pipeline,
         const SkPixmap& srcPixmap,
         SkBlendMode,
-        const SkImageInfo& dstInfo);
+        const SkImageInfo& dstInfo,
+        SkFallbackAlloc* allocator);
 
-    static bool ClonePipelineForBlitting(
-        SkEmbeddableLinearPipeline* pipelineStorage,
+    static SkLinearBitmapPipeline* ClonePipelineForBlitting(
         const SkLinearBitmapPipeline& pipeline,
         SkMatrix::TypeMask matrixMask,
-        SkShader::TileMode xTileMode,
-        SkShader::TileMode yTileMode,
         SkFilterQuality filterQuality,
         const SkPixmap& srcPixmap,
         float finalAlpha,
         SkBlendMode,
-        const SkImageInfo& dstInfo);
+        const SkImageInfo& dstInfo,
+        SkFallbackAlloc* allocator);
 
     ~SkLinearBitmapPipeline();
 
@@ -64,82 +64,59 @@
     class DestinationInterface;
     class PixelAccessorInterface;
 
-private:
-    using MemoryAllocator = SkSmallAllocator<5, 256>;
     using MatrixCloner =
-        std::function<PointProcessorInterface* (PointProcessorInterface*, MemoryAllocator*)>;
+        std::function<PointProcessorInterface* (PointProcessorInterface*, SkFallbackAlloc*)>;
     using TilerCloner =
-        std::function<PointProcessorInterface* (SampleProcessorInterface*, MemoryAllocator*)>;
+        std::function<PointProcessorInterface* (SampleProcessorInterface*, SkFallbackAlloc*)>;
 
     PointProcessorInterface* chooseMatrix(
         PointProcessorInterface* next,
-        const SkMatrix& inverse);
+        const SkMatrix& inverse,
+        SkFallbackAlloc* allocator);
 
     template <typename Tiler>
-    PointProcessorInterface* createTiler(SampleProcessorInterface* next, SkISize dimensions);
+    PointProcessorInterface* createTiler(SampleProcessorInterface* next, SkISize dimensions,
+                                         SkFallbackAlloc* allocator);
 
     template <typename XStrategy>
     PointProcessorInterface* chooseTilerYMode(
-        SampleProcessorInterface* next, SkShader::TileMode yMode, SkISize dimensions);
+        SampleProcessorInterface* next, SkShader::TileMode yMode, SkISize dimensions,
+        SkFallbackAlloc* allocator);
 
     PointProcessorInterface* chooseTiler(
         SampleProcessorInterface* next,
         SkISize dimensions,
         SkShader::TileMode xMode, SkShader::TileMode yMode,
         SkFilterQuality filterQuality,
-        SkScalar dx);
+        SkScalar dx,
+        SkFallbackAlloc* allocator);
 
     template <SkColorType colorType>
-    PixelAccessorInterface* chooseSpecificAccessor(const SkPixmap& srcPixmap);
+    PixelAccessorInterface* chooseSpecificAccessor(const SkPixmap& srcPixmap,
+                                                   SkFallbackAlloc* allocator);
 
     PixelAccessorInterface* choosePixelAccessor(
         const SkPixmap& srcPixmap,
-        const SkColor A8TintColor);
+        const SkColor A8TintColor,
+        SkFallbackAlloc* allocator);
 
     SampleProcessorInterface* chooseSampler(
         BlendProcessorInterface* next,
         SkFilterQuality filterQuality,
         SkShader::TileMode xTile, SkShader::TileMode yTile,
         const SkPixmap& srcPixmap,
-        const SkColor A8TintColor);
+        const SkColor A8TintColor,
+        SkFallbackAlloc* allocator);
 
     BlendProcessorInterface* chooseBlenderForShading(
         SkAlphaType alphaType,
-        float postAlpha);
+        float postAlpha,
+        SkFallbackAlloc* allocator);
 
-    MemoryAllocator          fMemory;
     PointProcessorInterface* fFirstStage;
     MatrixCloner             fMatrixStageCloner;
     TilerCloner              fTileStageCloner;
     DestinationInterface*    fLastStage;
 };
 
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// SkEmbeddableLinearPipeline - manage stricter alignment needs for SkLinearBitmapPipeline.
-class SkEmbeddableLinearPipeline {
-public:
-    SkEmbeddableLinearPipeline() { }
-    ~SkEmbeddableLinearPipeline() {
-        if (fInitialized) {
-            get()->~SkLinearBitmapPipeline();
-        }
-    }
-
-    template <typename... Args>
-    void init(Args&&... args) {
-        new (fPipelineStorage) SkLinearBitmapPipeline{std::forward<Args>(args)...};
-        fInitialized = true;
-    }
-
-    SkLinearBitmapPipeline* get() const {
-        return reinterpret_cast<SkLinearBitmapPipeline*>(fPipelineStorage);
-    }
-    SkLinearBitmapPipeline& operator*()  const { return *this->get(); }
-    SkLinearBitmapPipeline* operator->() const { return  this->get(); }
-
-private:
-    alignas(SkLinearBitmapPipeline) mutable char fPipelineStorage[sizeof(SkLinearBitmapPipeline)];
-    bool                                         fInitialized {false};
-};
-
 #endif  // SkLinearBitmapPipeline_DEFINED