Use SkSmallAllocator for SamplerStage and Accessor.


BUG=skia:

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

Change-Id: Id67d7c1cefa2aadfc706c56dd02d086120f99be3
Reviewed-on: https://skia-review.googlesource.com/4917
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 dae6985..c9b71b9 100644
--- a/src/core/SkLinearBitmapPipeline.cpp
+++ b/src/core/SkLinearBitmapPipeline.cpp
@@ -36,9 +36,6 @@
               "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace));
 
     new (&fSpace) Variant(next, std::forward<Args>(args)...);
-    fStageCloner = [this](Next* nextClone, void* addr) {
-        new (addr) Variant(nextClone, (const Variant&)*this->get());
-    };
     fIsInitialized = true;
 };
 
@@ -51,22 +48,6 @@
     fIsInitialized = true;
 };
 
-template<typename Base, size_t kSize, typename Next>
-template <typename To, typename From>
-To* SkLinearBitmapPipeline::Stage<Base, kSize, Next>::getInterface() {
-    From* down = static_cast<From*>(this->get());
-    return static_cast<To*>(down);
-}
-
-template<typename Base, size_t kSize, typename Next>
-Base* SkLinearBitmapPipeline::Stage<Base, kSize, Next>::cloneStageTo(
-    Next* next, Stage* cloneToStage) const
-{
-    if (!fIsInitialized) return nullptr;
-    fStageCloner(next, &cloneToStage->fSpace);
-    return cloneToStage->get();
-}
-
 namespace  {
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -336,138 +317,10 @@
 
 using Blender = SkLinearBitmapPipeline::BlendProcessorInterface;
 
-template <SkColorType colorType>
-static SkLinearBitmapPipeline::PixelAccessorInterface* choose_specific_accessor(
-    const SkPixmap& srcPixmap, SkLinearBitmapPipeline::Accessor* accessor)
-{
-    if (srcPixmap.info().gammaCloseToSRGB()) {
-        using PA = PixelAccessor<colorType, kSRGB_SkGammaType>;
-        accessor->init<PA>(srcPixmap);
-        return accessor->get();
-    } else {
-        using PA = PixelAccessor<colorType, kLinear_SkGammaType>;
-        accessor->init<PA>(srcPixmap);
-        return accessor->get();
-    }
-}
-
-static SkLinearBitmapPipeline::PixelAccessorInterface* choose_pixel_accessor(
-    const SkPixmap& srcPixmap,
-    const SkColor A8TintColor,
-    SkLinearBitmapPipeline::Accessor* accessor)
-{
-    const SkImageInfo& imageInfo = srcPixmap.info();
-
-    SkLinearBitmapPipeline::PixelAccessorInterface* pixelAccessor = nullptr;
-    switch (imageInfo.colorType()) {
-        case kAlpha_8_SkColorType: {
-                using PA = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>;
-                accessor->init<PA>(srcPixmap, A8TintColor);
-                pixelAccessor = accessor->get();
-            }
-            break;
-        case kARGB_4444_SkColorType:
-            pixelAccessor = choose_specific_accessor<kARGB_4444_SkColorType>(srcPixmap, accessor);
-            break;
-        case kRGB_565_SkColorType:
-            pixelAccessor = choose_specific_accessor<kRGB_565_SkColorType>(srcPixmap, accessor);
-            break;
-        case kRGBA_8888_SkColorType:
-            pixelAccessor = choose_specific_accessor<kRGBA_8888_SkColorType>(srcPixmap, accessor);
-            break;
-        case kBGRA_8888_SkColorType:
-            pixelAccessor = choose_specific_accessor<kBGRA_8888_SkColorType>(srcPixmap, accessor);
-            break;
-        case kIndex_8_SkColorType:
-            pixelAccessor = choose_specific_accessor<kIndex_8_SkColorType>(srcPixmap, accessor);
-            break;
-        case kGray_8_SkColorType:
-            pixelAccessor = choose_specific_accessor<kGray_8_SkColorType>(srcPixmap, accessor);
-            break;
-        case kRGBA_F16_SkColorType: {
-                using PA = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
-                accessor->init<PA>(srcPixmap);
-                pixelAccessor = accessor->get();
-            }
-            break;
-        default:
-            SkFAIL("Not implemented. Unsupported src");
-            break;
-    }
-
-    return pixelAccessor;
-}
-
-SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler(
-    Blender* next,
-    SkFilterQuality filterQuality,
-    SkShader::TileMode xTile, SkShader::TileMode yTile,
-    const SkPixmap& srcPixmap,
-    const SkColor A8TintColor,
-    SkLinearBitmapPipeline::SampleStage* sampleStage,
-    SkLinearBitmapPipeline::Accessor* accessor) {
-    const SkImageInfo& imageInfo = srcPixmap.info();
-    SkISize dimensions = imageInfo.dimensions();
-
-    // Special case samplers with fully expanded templates
-    if (imageInfo.gammaCloseToSRGB()) {
-        if (filterQuality == kNone_SkFilterQuality) {
-            switch (imageInfo.colorType()) {
-                case kN32_SkColorType: {
-                    using S =
-                    NearestNeighborSampler<
-                        PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
-                    sampleStage->initStage<S>(next, srcPixmap);
-                    return sampleStage->get();
-                }
-                case kIndex_8_SkColorType: {
-                    using S =
-                    NearestNeighborSampler<
-                        PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
-                    sampleStage->initStage<S>(next, srcPixmap);
-                    return sampleStage->get();
-                }
-                default:
-                    break;
-            }
-        } else {
-            switch (imageInfo.colorType()) {
-                case kN32_SkColorType: {
-                    using S =
-                    BilerpSampler<
-                        PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
-                    sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
-                    return sampleStage->get();
-                }
-                case kIndex_8_SkColorType: {
-                    using S =
-                    BilerpSampler<
-                        PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
-                    sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
-                    return sampleStage->get();
-                }
-                default:
-                    break;
-            }
-        }
-    }
-
-    auto pixelAccessor = choose_pixel_accessor(srcPixmap, A8TintColor, accessor);
-    // General cases.
-    if (filterQuality == kNone_SkFilterQuality) {
-        using S = NearestNeighborSampler<PixelAccessorShim, Blender>;
-        sampleStage->initStage<S>(next, pixelAccessor);
-    } else {
-        using S = BilerpSampler<PixelAccessorShim, Blender>;
-        sampleStage->initStage<S>(next, dimensions, xTile, yTile, pixelAccessor);
-    }
-    return sampleStage->get();
-}
-
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // Pixel Blender Stage
 template <SkAlphaType alphaType>
-class SrcFPPixel final : public SkLinearBitmapPipeline::BlendProcessorInterface {
+class SrcFPPixel final : public Blender {
 public:
     SrcFPPixel(float postAlpha) : fPostAlpha{postAlpha} { }
     SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {}
@@ -566,9 +419,8 @@
     // 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 = choose_blender_for_shading(alphaType, postAlpha, &fBlenderStage);
-    auto samplerStage = choose_pixel_sampler(
-        blenderStage, filterQuality, xTile, yTile,
-        srcPixmap, paintColor, &fSampleStage, &fAccessor);
+    auto samplerStage = this->chooseSampler(
+        blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor);
     auto tilerStage   = this->chooseTiler(
         samplerStage, dimensions, xTile, yTile, filterQuality, dx);
     fFirstStage       = this->chooseMatrix(tilerStage, adjustedInverse);
@@ -620,17 +472,19 @@
     SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
              && srcPixmap.info().colorType() == kRGBA_8888_SkColorType);
 
+    SampleProcessorInterface* sampleStage;
     if (mode == SkBlendMode::kSrc) {
-        fSampleStage.initSink<RGBA8888UnitRepeatSrc>(
+        auto sampler = fMemory.createT<RGBA8888UnitRepeatSrc>(
             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
-        fLastStage = fSampleStage.getInterface<DestinationInterface, RGBA8888UnitRepeatSrc>();
+        sampleStage = sampler;
+        fLastStage = sampler;
     } else {
-        fSampleStage.initSink<RGBA8888UnitRepeatSrcOver>(
+        auto sampler = fMemory.createT<RGBA8888UnitRepeatSrcOver>(
             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
-        fLastStage = fSampleStage.getInterface<DestinationInterface, RGBA8888UnitRepeatSrcOver>();
+        sampleStage = sampler;
+        fLastStage = sampler;
     }
 
-    auto sampleStage = fSampleStage.get();
     auto tilerStage = pipeline.fTileStageCloner(sampleStage, &fMemory);
     auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, &fMemory);
     fFirstStage = matrixStage;
@@ -765,3 +619,111 @@
     SkFAIL("Not all X tile cases covered.");
     return nullptr;
 }
+
+template <SkColorType colorType>
+SkLinearBitmapPipeline::PixelAccessorInterface*
+    SkLinearBitmapPipeline::chooseSpecificAccessor(
+    const SkPixmap& srcPixmap)
+{
+    if (srcPixmap.info().gammaCloseToSRGB()) {
+        using Accessor = PixelAccessor<colorType, kSRGB_SkGammaType>;
+        return fMemory.createT<Accessor>(srcPixmap);
+    } else {
+        using Accessor = PixelAccessor<colorType, kLinear_SkGammaType>;
+        return fMemory.createT<Accessor>(srcPixmap);
+    }
+}
+
+SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor(
+    const SkPixmap& srcPixmap,
+    const SkColor A8TintColor)
+{
+    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);
+        }
+        case kARGB_4444_SkColorType:
+            return this->chooseSpecificAccessor<kARGB_4444_SkColorType>(srcPixmap);
+        case kRGB_565_SkColorType:
+            return this->chooseSpecificAccessor<kRGB_565_SkColorType>(srcPixmap);
+        case kRGBA_8888_SkColorType:
+            return this->chooseSpecificAccessor<kRGBA_8888_SkColorType>(srcPixmap);
+        case kBGRA_8888_SkColorType:
+            return this->chooseSpecificAccessor<kBGRA_8888_SkColorType>(srcPixmap);
+        case kIndex_8_SkColorType:
+            return this->chooseSpecificAccessor<kIndex_8_SkColorType>(srcPixmap);
+        case kGray_8_SkColorType:
+            return this->chooseSpecificAccessor<kGray_8_SkColorType>(srcPixmap);
+        case kRGBA_F16_SkColorType: {
+            using Accessor = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
+            return fMemory.createT<Accessor>(srcPixmap);
+        }
+        default:
+            // Should never get here.
+            SkFAIL("Pixel source not supported.");
+            return nullptr;
+    }
+}
+
+SkLinearBitmapPipeline::SampleProcessorInterface* SkLinearBitmapPipeline::chooseSampler(
+    Blender* next,
+    SkFilterQuality filterQuality,
+    SkShader::TileMode xTile, SkShader::TileMode yTile,
+    const SkPixmap& srcPixmap,
+    const SkColor A8TintColor)
+{
+    const SkImageInfo& imageInfo = srcPixmap.info();
+    SkISize dimensions = imageInfo.dimensions();
+
+    // Special case samplers with fully expanded templates
+    if (imageInfo.gammaCloseToSRGB()) {
+        if (filterQuality == kNone_SkFilterQuality) {
+            switch (imageInfo.colorType()) {
+                case kN32_SkColorType: {
+                    using Sampler =
+                    NearestNeighborSampler<
+                        PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
+                    return fMemory.createT<Sampler>(next, srcPixmap);
+                }
+                case kIndex_8_SkColorType: {
+                    using Sampler =
+                    NearestNeighborSampler<
+                        PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
+                    return fMemory.createT<Sampler>(next, srcPixmap);
+                }
+                default:
+                    break;
+            }
+        } else {
+            switch (imageInfo.colorType()) {
+                case kN32_SkColorType: {
+                    using Sampler =
+                    BilerpSampler<
+                        PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
+                    return fMemory.createT<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);
+                }
+                default:
+                    break;
+            }
+        }
+    }
+
+    auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor);
+    // General cases.
+    if (filterQuality == kNone_SkFilterQuality) {
+        using Sampler = NearestNeighborSampler<PixelAccessorShim, Blender>;
+        return fMemory.createT<Sampler>(next, pixelAccessor);
+    } else {
+        using Sampler = BilerpSampler<PixelAccessorShim, Blender>;
+        return fMemory.createT<Sampler>(next, dimensions, xTile, yTile, pixelAccessor);
+    }
+}
diff --git a/src/core/SkLinearBitmapPipeline.h b/src/core/SkLinearBitmapPipeline.h
index d5c43d9..f936ffd 100644
--- a/src/core/SkLinearBitmapPipeline.h
+++ b/src/core/SkLinearBitmapPipeline.h
@@ -70,55 +70,15 @@
         template<typename Variant, typename... Args>
         void initSink(Args&& ... args);
 
-        template <typename To, typename From>
-        To* getInterface();
-
-        // Copy this stage to `cloneToStage` with `next` as its next stage
-        // (not necessarily the same as our next, you see), returning `cloneToStage`.
-        // Note: There is no cloneSinkTo method because the code usually places the top part of
-        // the pipeline on a new sampler.
-        Base* cloneStageTo(Next* next, Stage* cloneToStage) const;
-
         Base* get() const { return reinterpret_cast<Base*>(fSpace); }
         Base* operator->() const { return this->get(); }
         Base& operator*() const { return *(this->get()); }
 
     private:
-        std::function<void (Next*, void*)> fStageCloner;
         mutable char                       fSpace[kSize];
         bool                               fIsInitialized;
     };
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PolyMemory
-    template <typename Base, size_t kSize>
-    class PolyMemory {
-    public:
-        PolyMemory() : fIsInitialized{false} { }
-        ~PolyMemory() {
-            if (fIsInitialized) {
-                this->get()->~Base();
-            }
-        }
-        template<typename Variant, typename... Args>
-        void init(Args&& ... args) {
-            SkASSERTF(sizeof(Variant) <= sizeof(fSpace),
-                      "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace));
-
-            new (&fSpace) Variant(std::forward<Args>(args)...);
-            fIsInitialized = true;
-        }
-
-        Base* get() const { return reinterpret_cast<Base*>(fSpace); }
-        Base* operator->() const { return this->get(); }
-        Base& operator*() const { return *(this->get()); }
-
-    private:
-        mutable char fSpace[kSize];
-        bool         fIsInitialized;
-
-    };
-
     class PointProcessorInterface;
     class SampleProcessorInterface;
     class BlendProcessorInterface;
@@ -128,10 +88,9 @@
     // These values were generated by the assert above in Stage::init{Sink|Stage}.
     using SampleStage  = Stage<SampleProcessorInterface,   160, BlendProcessorInterface>;
     using BlenderStage = Stage<BlendProcessorInterface,     48>;
-    using Accessor     = PolyMemory<PixelAccessorInterface, 64>;
 
 private:
-    using MemoryAllocator = SkSmallAllocator<128, 2>;
+    using MemoryAllocator = SkSmallAllocator<128, 4>;
     using MatrixCloner =
         std::function<PointProcessorInterface* (PointProcessorInterface*, MemoryAllocator*)>;
     using TilerCloner =
@@ -151,19 +110,30 @@
     PointProcessorInterface* chooseTiler(
         SampleProcessorInterface* next,
         SkISize dimensions,
-        SkShader::TileMode xMode,
-        SkShader::TileMode yMode,
+        SkShader::TileMode xMode, SkShader::TileMode yMode,
         SkFilterQuality filterQuality,
         SkScalar dx);
 
+    template <SkColorType colorType>
+    PixelAccessorInterface* chooseSpecificAccessor(const SkPixmap& srcPixmap);
+
+    PixelAccessorInterface* choosePixelAccessor(
+        const SkPixmap& srcPixmap,
+        const SkColor A8TintColor);
+
+    SampleProcessorInterface* chooseSampler(
+        BlendProcessorInterface* next,
+        SkFilterQuality filterQuality,
+        SkShader::TileMode xTile, SkShader::TileMode yTile,
+        const SkPixmap& srcPixmap,
+        const SkColor A8TintColor);
+
     MemoryAllocator          fMemory;
     PointProcessorInterface* fFirstStage;
     MatrixCloner             fMatrixStageCloner;
     TilerCloner              fTileStageCloner;
-    SampleStage              fSampleStage;
     BlenderStage             fBlenderStage;
     DestinationInterface*    fLastStage;
-    Accessor                 fAccessor;
 };
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////