Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2016 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkLinearBitmapPipeline.h"
      9 
     10 #include <algorithm>
     11 #include <cmath>
     12 #include <limits>
     13 #include <tuple>
     14 
     15 #include "SkArenaAlloc.h"
     16 #include "SkLinearBitmapPipeline_core.h"
     17 #include "SkLinearBitmapPipeline_matrix.h"
     18 #include "SkLinearBitmapPipeline_tile.h"
     19 #include "SkLinearBitmapPipeline_sample.h"
     20 #include "SkNx.h"
     21 #include "SkOpts.h"
     22 #include "SkPM4f.h"
     23 
     24 namespace  {
     25 
     26 ////////////////////////////////////////////////////////////////////////////////////////////////////
     27 // Matrix Stage
     28 // PointProcessor uses a strategy to help complete the work of the different stages. The strategy
     29 // must implement the following methods:
     30 // * processPoints(xs, ys) - must mutate the xs and ys for the stage.
     31 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixels
     32 //   to work over.
     33 //   span - encapsulation of span.
     34 //   next - a pointer to the next stage.
     35 //   maybeProcessSpan - returns false if it can not process the span and needs to fallback to
     36 //                      point lists for processing.
     37 template<typename Strategy, typename Next>
     38 class MatrixStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
     39 public:
     40     template <typename... Args>
     41     MatrixStage(Next* next, Args&&... args)
     42         : fNext{next}
     43         , fStrategy{std::forward<Args>(args)...}{ }
     44 
     45     MatrixStage(Next* next, MatrixStage* stage)
     46         : fNext{next}
     47         , fStrategy{stage->fStrategy} { }
     48 
     49     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
     50         fStrategy.processPoints(&xs, &ys);
     51         fNext->pointListFew(n, xs, ys);
     52     }
     53 
     54     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
     55         fStrategy.processPoints(&xs, &ys);
     56         fNext->pointList4(xs, ys);
     57     }
     58 
     59     // The span you pass must not be empty.
     60     void pointSpan(Span span) override {
     61         SkASSERT(!span.isEmpty());
     62         if (!fStrategy.maybeProcessSpan(span, fNext)) {
     63             span_fallback(span, this);
     64         }
     65     }
     66 
     67 private:
     68     Next* const fNext;
     69     Strategy fStrategy;
     70 };
     71 
     72 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
     73 using TranslateMatrix = MatrixStage<TranslateMatrixStrategy, Next>;
     74 
     75 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
     76 using ScaleMatrix = MatrixStage<ScaleMatrixStrategy, Next>;
     77 
     78 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
     79 using AffineMatrix = MatrixStage<AffineMatrixStrategy, Next>;
     80 
     81 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
     82 using PerspectiveMatrix = MatrixStage<PerspectiveMatrixStrategy, Next>;
     83 
     84 
     85 ////////////////////////////////////////////////////////////////////////////////////////////////////
     86 // Tile Stage
     87 
     88 template<typename XStrategy, typename YStrategy, typename Next>
     89 class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
     90 public:
     91     CombinedTileStage(Next* next, SkISize dimensions)
     92         : fNext{next}
     93         , fXStrategy{dimensions.width()}
     94         , fYStrategy{dimensions.height()}{ }
     95 
     96     CombinedTileStage(Next* next, CombinedTileStage* stage)
     97         : fNext{next}
     98         , fXStrategy{stage->fXStrategy}
     99         , fYStrategy{stage->fYStrategy} { }
    100 
    101     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
    102         fXStrategy.tileXPoints(&xs);
    103         fYStrategy.tileYPoints(&ys);
    104         fNext->pointListFew(n, xs, ys);
    105     }
    106 
    107     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
    108         fXStrategy.tileXPoints(&xs);
    109         fYStrategy.tileYPoints(&ys);
    110         fNext->pointList4(xs, ys);
    111     }
    112 
    113     // The span you pass must not be empty.
    114     void pointSpan(Span span) override {
    115         SkASSERT(!span.isEmpty());
    116         SkPoint start; SkScalar length; int count;
    117         std::tie(start, length, count) = span;
    118 
    119         if (span.count() == 1) {
    120             // DANGER:
    121             // The explicit casts from float to Sk4f are not usually necessary, but are here to
    122             // work around an MSVC 2015u2 c++ code generation bug. This is tracked using skia bug
    123             // 5566.
    124             this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()});
    125             return;
    126         }
    127 
    128         SkScalar x = X(start);
    129         SkScalar y = fYStrategy.tileY(Y(start));
    130         Span yAdjustedSpan{{x, y}, length, count};
    131 
    132         if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
    133             span_fallback(span, this);
    134         }
    135     }
    136 
    137 private:
    138     Next* const fNext;
    139     XStrategy fXStrategy;
    140     YStrategy fYStrategy;
    141 };
    142 
    143 ////////////////////////////////////////////////////////////////////////////////////////////////////
    144 // Specialized Samplers
    145 
    146 // RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination
    147 // are the same format and do not need in transformations in pixel space. Therefore, there is no
    148 // need to convert them to HiFi pixel format.
    149 class RGBA8888UnitRepeatSrc final : public SkLinearBitmapPipeline::SampleProcessorInterface,
    150                                     public SkLinearBitmapPipeline::DestinationInterface {
    151 public:
    152     RGBA8888UnitRepeatSrc(const uint32_t* src, int32_t width)
    153         : fSrc{src}, fWidth{width} { }
    154 
    155     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
    156         SkASSERT(fDest + n <= fEnd);
    157         // At this point xs and ys should be >= 0, so trunc is the same as floor.
    158         Sk4i iXs = SkNx_cast<int>(xs);
    159         Sk4i iYs = SkNx_cast<int>(ys);
    160 
    161         if (n >= 1) *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
    162         if (n >= 2) *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
    163         if (n >= 3) *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
    164     }
    165 
    166     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
    167         SkASSERT(fDest + 4 <= fEnd);
    168         Sk4i iXs = SkNx_cast<int>(xs);
    169         Sk4i iYs = SkNx_cast<int>(ys);
    170         *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
    171         *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
    172         *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
    173         *fDest++ = *this->pixelAddress(iXs[3], iYs[3]);
    174     }
    175 
    176     void pointSpan(Span span) override {
    177         SkASSERT(fDest + span.count() <= fEnd);
    178         if (span.length() != 0.0f) {
    179             int32_t x = SkScalarTruncToInt(span.startX());
    180             int32_t y = SkScalarTruncToInt(span.startY());
    181             const uint32_t* src = this->pixelAddress(x, y);
    182             memmove(fDest, src, span.count() * sizeof(uint32_t));
    183             fDest += span.count();
    184         }
    185     }
    186 
    187     void repeatSpan(Span span, int32_t repeatCount) override {
    188         SkASSERT(fDest + span.count() * repeatCount <= fEnd);
    189 
    190         int32_t x = SkScalarTruncToInt(span.startX());
    191         int32_t y = SkScalarTruncToInt(span.startY());
    192         const uint32_t* src = this->pixelAddress(x, y);
    193         uint32_t* dest = fDest;
    194         while (repeatCount --> 0) {
    195             memmove(dest, src, span.count() * sizeof(uint32_t));
    196             dest += span.count();
    197         }
    198         fDest = dest;
    199     }
    200 
    201     void setDestination(void* dst, int count) override  {
    202         fDest = static_cast<uint32_t*>(dst);
    203         fEnd = fDest + count;
    204     }
    205 
    206 private:
    207     const uint32_t* pixelAddress(int32_t x, int32_t y) {
    208         return &fSrc[fWidth * y + x];
    209     }
    210     const uint32_t* const fSrc;
    211     const int32_t         fWidth;
    212     uint32_t*             fDest;
    213     uint32_t*             fEnd;
    214 };
    215 
    216 // RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination
    217 // are the same format and do not need in transformations in pixel space. Therefore, there is no
    218 // need to convert them to HiFi pixel format.
    219 class RGBA8888UnitRepeatSrcOver final : public SkLinearBitmapPipeline::SampleProcessorInterface,
    220                                         public SkLinearBitmapPipeline::DestinationInterface {
    221 public:
    222     RGBA8888UnitRepeatSrcOver(const uint32_t* src, int32_t width)
    223         : fSrc{src}, fWidth{width} { }
    224 
    225     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
    226         SkASSERT(fDest + n <= fEnd);
    227         // At this point xs and ys should be >= 0, so trunc is the same as floor.
    228         Sk4i iXs = SkNx_cast<int>(xs);
    229         Sk4i iYs = SkNx_cast<int>(ys);
    230 
    231         if (n >= 1) blendPixelAt(iXs[0], iYs[0]);
    232         if (n >= 2) blendPixelAt(iXs[1], iYs[1]);
    233         if (n >= 3) blendPixelAt(iXs[2], iYs[2]);
    234     }
    235 
    236     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
    237         SkASSERT(fDest + 4 <= fEnd);
    238         Sk4i iXs = SkNx_cast<int>(xs);
    239         Sk4i iYs = SkNx_cast<int>(ys);
    240         blendPixelAt(iXs[0], iYs[0]);
    241         blendPixelAt(iXs[1], iYs[1]);
    242         blendPixelAt(iXs[2], iYs[2]);
    243         blendPixelAt(iXs[3], iYs[3]);
    244     }
    245 
    246     void pointSpan(Span span) override {
    247         if (span.length() != 0.0f) {
    248             this->repeatSpan(span, 1);
    249         }
    250     }
    251 
    252     void repeatSpan(Span span, int32_t repeatCount) override {
    253         SkASSERT(fDest + span.count() * repeatCount <= fEnd);
    254         SkASSERT(span.count() > 0);
    255         SkASSERT(repeatCount > 0);
    256 
    257         int32_t x = (int32_t)span.startX();
    258         int32_t y = (int32_t)span.startY();
    259         const uint32_t* beginSpan = this->pixelAddress(x, y);
    260 
    261         SkOpts::srcover_srgb_srgb(fDest, beginSpan, span.count() * repeatCount, span.count());
    262 
    263         fDest += span.count() * repeatCount;
    264 
    265         SkASSERT(fDest <= fEnd);
    266     }
    267 
    268     void setDestination(void* dst, int count) override  {
    269         SkASSERT(count > 0);
    270         fDest = static_cast<uint32_t*>(dst);
    271         fEnd = fDest + count;
    272     }
    273 
    274 private:
    275     const uint32_t* pixelAddress(int32_t x, int32_t y) {
    276         return &fSrc[fWidth * y + x];
    277     }
    278 
    279     void blendPixelAt(int32_t x, int32_t y) {
    280         const uint32_t* src = this->pixelAddress(x, y);
    281         SkOpts::srcover_srgb_srgb(fDest, src, 1, 1);
    282         fDest += 1;
    283     }
    284 
    285     const uint32_t* const fSrc;
    286     const int32_t         fWidth;
    287     uint32_t*             fDest;
    288     uint32_t*             fEnd;
    289 };
    290 
    291 using Blender = SkLinearBitmapPipeline::BlendProcessorInterface;
    292 
    293 ////////////////////////////////////////////////////////////////////////////////////////////////////
    294 // Pixel Blender Stage
    295 template <SkAlphaType alphaType>
    296 class SrcFPPixel final : public Blender {
    297 public:
    298     SrcFPPixel(float postAlpha) : fPostAlpha{postAlpha} { }
    299     SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {}
    300     void SK_VECTORCALL blendPixel(Sk4f pixel) override {
    301         SkASSERT(fDst + 1 <= fEnd );
    302         this->srcPixel(fDst, pixel, 0);
    303         fDst += 1;
    304     }
    305 
    306     void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
    307         SkASSERT(fDst + 4 <= fEnd);
    308         SkPM4f* dst = fDst;
    309         this->srcPixel(dst, p0, 0);
    310         this->srcPixel(dst, p1, 1);
    311         this->srcPixel(dst, p2, 2);
    312         this->srcPixel(dst, p3, 3);
    313         fDst += 4;
    314     }
    315 
    316     void setDestination(void* dst, int count) override {
    317         fDst = static_cast<SkPM4f*>(dst);
    318         fEnd = fDst + count;
    319     }
    320 
    321 private:
    322     void SK_VECTORCALL srcPixel(SkPM4f* dst, Sk4f pixel, int index) {
    323         check_pixel(pixel);
    324 
    325         Sk4f newPixel = pixel;
    326         if (alphaType == kUnpremul_SkAlphaType) {
    327             newPixel = Premultiply(pixel);
    328         }
    329         newPixel = newPixel * fPostAlpha;
    330         newPixel.store(dst + index);
    331     }
    332     static Sk4f SK_VECTORCALL Premultiply(Sk4f pixel) {
    333         float alpha = pixel[3];
    334         return pixel * Sk4f{alpha, alpha, alpha, 1.0f};
    335     }
    336 
    337     SkPM4f* fDst;
    338     SkPM4f* fEnd;
    339     float   fPostAlpha;
    340 };
    341 
    342 }  // namespace
    343 
    344 ////////////////////////////////////////////////////////////////////////////////////////////////////
    345 // SkLinearBitmapPipeline
    346 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
    347 
    348 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
    349     const SkMatrix& inverse,
    350     SkFilterQuality filterQuality,
    351     SkShader::TileMode xTile, SkShader::TileMode yTile,
    352     SkColor paintColor,
    353     const SkPixmap& srcPixmap,
    354     SkArenaAlloc* allocator)
    355 {
    356     SkISize dimensions = srcPixmap.info().dimensions();
    357     const SkImageInfo& srcImageInfo = srcPixmap.info();
    358 
    359     SkMatrix adjustedInverse = inverse;
    360     if (filterQuality == kNone_SkFilterQuality) {
    361         if (inverse.getScaleX() >= 0.0f) {
    362             adjustedInverse.setTranslateX(
    363                 nextafterf(inverse.getTranslateX(), std::floor(inverse.getTranslateX())));
    364         }
    365         if (inverse.getScaleY() >= 0.0f) {
    366             adjustedInverse.setTranslateY(
    367                 nextafterf(inverse.getTranslateY(), std::floor(inverse.getTranslateY())));
    368         }
    369     }
    370 
    371     SkScalar dx = adjustedInverse.getScaleX();
    372 
    373     // If it is an index 8 color type, the sampler converts to unpremul for better fidelity.
    374     SkAlphaType alphaType = srcImageInfo.alphaType();
    375     if (srcPixmap.colorType() == kIndex_8_SkColorType) {
    376         alphaType = kUnpremul_SkAlphaType;
    377     }
    378 
    379     float postAlpha = SkColorGetA(paintColor) * (1.0f / 255.0f);
    380     // As the stages are built, the chooser function may skip a stage. For example, with the
    381     // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
    382     auto blenderStage = this->chooseBlenderForShading(alphaType, postAlpha, allocator);
    383     auto samplerStage = this->chooseSampler(
    384         blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor, allocator);
    385     auto tilerStage   = this->chooseTiler(
    386         samplerStage, dimensions, xTile, yTile, filterQuality, dx, allocator);
    387     fFirstStage       = this->chooseMatrix(tilerStage, adjustedInverse, allocator);
    388     fLastStage        = blenderStage;
    389 }
    390 
    391 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
    392     const SkLinearBitmapPipeline& pipeline,
    393     const SkPixmap& srcPixmap,
    394     SkBlendMode mode,
    395     const SkImageInfo& dstInfo,
    396     SkArenaAlloc* allocator)
    397 {
    398     SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
    399     SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
    400              && srcPixmap.info().colorType() == kRGBA_8888_SkColorType);
    401 
    402     SampleProcessorInterface* sampleStage;
    403     if (mode == SkBlendMode::kSrc) {
    404         auto sampler = allocator->make<RGBA8888UnitRepeatSrc>(
    405             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
    406         sampleStage = sampler;
    407         fLastStage = sampler;
    408     } else {
    409         auto sampler = allocator->make<RGBA8888UnitRepeatSrcOver>(
    410             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
    411         sampleStage = sampler;
    412         fLastStage = sampler;
    413     }
    414 
    415     auto tilerStage = pipeline.fTileStageCloner(sampleStage, allocator);
    416     auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, allocator);
    417     fFirstStage = matrixStage;
    418 }
    419 
    420 SkLinearBitmapPipeline* SkLinearBitmapPipeline::ClonePipelineForBlitting(
    421     const SkLinearBitmapPipeline& pipeline,
    422     SkMatrix::TypeMask matrixMask,
    423     SkFilterQuality filterQuality,
    424     const SkPixmap& srcPixmap,
    425     float finalAlpha,
    426     SkBlendMode blendMode,
    427     const SkImageInfo& dstInfo,
    428     SkArenaAlloc* allocator)
    429 {
    430     if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
    431         blendMode = SkBlendMode::kSrc;
    432     }
    433 
    434     if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return nullptr; }
    435     if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return nullptr; }
    436     if (finalAlpha != 1.0f) { return nullptr; }
    437     if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType
    438         || dstInfo.colorType() != kRGBA_8888_SkColorType) { return nullptr; }
    439 
    440     if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) {
    441         return nullptr;
    442     }
    443 
    444     if (blendMode != SkBlendMode::kSrc && blendMode != SkBlendMode::kSrcOver) {
    445         return nullptr;
    446     }
    447 
    448     return allocator->make<SkLinearBitmapPipeline>(
    449         pipeline, srcPixmap, blendMode, dstInfo, allocator);
    450 }
    451 
    452 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
    453     SkASSERT(count > 0);
    454     this->blitSpan(x, y, dst, count);
    455 }
    456 
    457 void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) {
    458     SkASSERT(count > 0);
    459     fLastStage->setDestination(dst, count);
    460 
    461     // The count and length arguments start out in a precise relation in order to keep the
    462     // math correct through the different stages. Count is the number of pixel to produce.
    463     // Since the code samples at pixel centers, length is the distance from the center of the
    464     // first pixel to the center of the last pixel. This implies that length is count-1.
    465     fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count});
    466 }
    467 
    468 SkLinearBitmapPipeline::PointProcessorInterface*
    469 SkLinearBitmapPipeline::chooseMatrix(
    470     PointProcessorInterface* next,
    471     const SkMatrix& inverse,
    472     SkArenaAlloc* allocator)
    473 {
    474     if (inverse.hasPerspective()) {
    475         auto matrixStage = allocator->make<PerspectiveMatrix<>>(
    476             next,
    477             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
    478             SkVector{inverse.getScaleX(), inverse.getScaleY()},
    479             SkVector{inverse.getSkewX(), inverse.getSkewY()},
    480             SkVector{inverse.getPerspX(), inverse.getPerspY()},
    481             inverse.get(SkMatrix::kMPersp2));
    482         fMatrixStageCloner =
    483             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
    484                 return memory->make<PerspectiveMatrix<>>(cloneNext, matrixStage);
    485             };
    486         return matrixStage;
    487     } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
    488         auto matrixStage = allocator->make<AffineMatrix<>>(
    489             next,
    490             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
    491             SkVector{inverse.getScaleX(), inverse.getScaleY()},
    492             SkVector{inverse.getSkewX(), inverse.getSkewY()});
    493         fMatrixStageCloner =
    494             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
    495                 return memory->make<AffineMatrix<>>(cloneNext, matrixStage);
    496             };
    497         return matrixStage;
    498     } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
    499         auto matrixStage = allocator->make<ScaleMatrix<>>(
    500             next,
    501             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
    502             SkVector{inverse.getScaleX(), inverse.getScaleY()});
    503         fMatrixStageCloner =
    504             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
    505                 return memory->make<ScaleMatrix<>>(cloneNext, matrixStage);
    506             };
    507         return matrixStage;
    508     } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
    509         auto matrixStage = allocator->make<TranslateMatrix<>>(
    510             next,
    511             SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
    512         fMatrixStageCloner =
    513             [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
    514                 return memory->make<TranslateMatrix<>>(cloneNext, matrixStage);
    515             };
    516         return matrixStage;
    517     } else {
    518         fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
    519             return cloneNext;
    520         };
    521         return next;
    522     }
    523 }
    524 
    525 template <typename Tiler>
    526 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler(
    527     SampleProcessorInterface* next,
    528     SkISize dimensions,
    529     SkArenaAlloc* allocator)
    530 {
    531     auto tilerStage = allocator->make<Tiler>(next, dimensions);
    532     fTileStageCloner =
    533         [tilerStage](SampleProcessorInterface* cloneNext,
    534                      SkArenaAlloc* memory) -> PointProcessorInterface* {
    535             return memory->make<Tiler>(cloneNext, tilerStage);
    536         };
    537     return tilerStage;
    538 }
    539 
    540 template <typename XStrategy>
    541 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTilerYMode(
    542     SampleProcessorInterface* next,
    543     SkShader::TileMode yMode,
    544     SkISize dimensions,
    545     SkArenaAlloc* allocator)
    546 {
    547     switch (yMode) {
    548         case SkShader::kClamp_TileMode: {
    549             using Tiler = CombinedTileStage<XStrategy, YClampStrategy, SampleProcessorInterface>;
    550             return this->createTiler<Tiler>(next, dimensions, allocator);
    551         }
    552         case SkShader::kRepeat_TileMode: {
    553             using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, SampleProcessorInterface>;
    554             return this->createTiler<Tiler>(next, dimensions, allocator);
    555         }
    556         case SkShader::kMirror_TileMode: {
    557             using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, SampleProcessorInterface>;
    558             return this->createTiler<Tiler>(next, dimensions, allocator);
    559         }
    560     }
    561 
    562     // Should never get here.
    563     SkFAIL("Not all Y tile cases covered.");
    564     return nullptr;
    565 }
    566 
    567 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTiler(
    568     SampleProcessorInterface* next,
    569     SkISize dimensions,
    570     SkShader::TileMode xMode,
    571     SkShader::TileMode yMode,
    572     SkFilterQuality filterQuality,
    573     SkScalar dx,
    574     SkArenaAlloc* allocator)
    575 {
    576     switch (xMode) {
    577         case SkShader::kClamp_TileMode:
    578             return this->chooseTilerYMode<XClampStrategy>(next, yMode, dimensions, allocator);
    579         case SkShader::kRepeat_TileMode:
    580             if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
    581                 return this->chooseTilerYMode<XRepeatUnitScaleStrategy>(
    582                     next, yMode, dimensions, allocator);
    583             } else {
    584                 return this->chooseTilerYMode<XRepeatStrategy>(
    585                     next, yMode, dimensions, allocator);
    586             }
    587         case SkShader::kMirror_TileMode:
    588             return this->chooseTilerYMode<XMirrorStrategy>(next, yMode, dimensions, allocator);
    589     }
    590 
    591     // Should never get here.
    592     SkFAIL("Not all X tile cases covered.");
    593     return nullptr;
    594 }
    595 
    596 template <SkColorType colorType>
    597 SkLinearBitmapPipeline::PixelAccessorInterface*
    598     SkLinearBitmapPipeline::chooseSpecificAccessor(
    599     const SkPixmap& srcPixmap,
    600     SkArenaAlloc* allocator)
    601 {
    602     if (srcPixmap.info().gammaCloseToSRGB()) {
    603         using Accessor = PixelAccessor<colorType, kSRGB_SkGammaType>;
    604         return allocator->make<Accessor>(srcPixmap);
    605     } else {
    606         using Accessor = PixelAccessor<colorType, kLinear_SkGammaType>;
    607         return allocator->make<Accessor>(srcPixmap);
    608     }
    609 }
    610 
    611 SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor(
    612     const SkPixmap& srcPixmap,
    613     const SkColor A8TintColor,
    614     SkArenaAlloc* allocator)
    615 {
    616     const SkImageInfo& imageInfo = srcPixmap.info();
    617 
    618     switch (imageInfo.colorType()) {
    619         case kAlpha_8_SkColorType: {
    620             using Accessor = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>;
    621             return allocator->make<Accessor>(srcPixmap, A8TintColor);
    622         }
    623         case kARGB_4444_SkColorType:
    624             return this->chooseSpecificAccessor<kARGB_4444_SkColorType>(srcPixmap, allocator);
    625         case kRGB_565_SkColorType:
    626             return this->chooseSpecificAccessor<kRGB_565_SkColorType>(srcPixmap, allocator);
    627         case kRGBA_8888_SkColorType:
    628             return this->chooseSpecificAccessor<kRGBA_8888_SkColorType>(srcPixmap, allocator);
    629         case kBGRA_8888_SkColorType:
    630             return this->chooseSpecificAccessor<kBGRA_8888_SkColorType>(srcPixmap, allocator);
    631         case kIndex_8_SkColorType:
    632             return this->chooseSpecificAccessor<kIndex_8_SkColorType>(srcPixmap, allocator);
    633         case kGray_8_SkColorType:
    634             return this->chooseSpecificAccessor<kGray_8_SkColorType>(srcPixmap, allocator);
    635         case kRGBA_F16_SkColorType: {
    636             using Accessor = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
    637             return allocator->make<Accessor>(srcPixmap);
    638         }
    639         default:
    640             // Should never get here.
    641             SkFAIL("Pixel source not supported.");
    642             return nullptr;
    643     }
    644 }
    645 
    646 SkLinearBitmapPipeline::SampleProcessorInterface* SkLinearBitmapPipeline::chooseSampler(
    647     Blender* next,
    648     SkFilterQuality filterQuality,
    649     SkShader::TileMode xTile, SkShader::TileMode yTile,
    650     const SkPixmap& srcPixmap,
    651     const SkColor A8TintColor,
    652     SkArenaAlloc* allocator)
    653 {
    654     const SkImageInfo& imageInfo = srcPixmap.info();
    655     SkISize dimensions = imageInfo.dimensions();
    656 
    657     // Special case samplers with fully expanded templates
    658     if (imageInfo.gammaCloseToSRGB()) {
    659         if (filterQuality == kNone_SkFilterQuality) {
    660             switch (imageInfo.colorType()) {
    661                 case kN32_SkColorType: {
    662                     using Sampler =
    663                     NearestNeighborSampler<
    664                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
    665                     return allocator->make<Sampler>(next, srcPixmap);
    666                 }
    667                 case kIndex_8_SkColorType: {
    668                     using Sampler =
    669                     NearestNeighborSampler<
    670                         PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
    671                     return allocator->make<Sampler>(next, srcPixmap);
    672                 }
    673                 default:
    674                     break;
    675             }
    676         } else {
    677             switch (imageInfo.colorType()) {
    678                 case kN32_SkColorType: {
    679                     using Sampler =
    680                     BilerpSampler<
    681                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
    682                     return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
    683                 }
    684                 case kIndex_8_SkColorType: {
    685                     using Sampler =
    686                     BilerpSampler<
    687                         PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
    688                     return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
    689                 }
    690                 default:
    691                     break;
    692             }
    693         }
    694     }
    695 
    696     auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor, allocator);
    697     // General cases.
    698     if (filterQuality == kNone_SkFilterQuality) {
    699         using Sampler = NearestNeighborSampler<PixelAccessorShim, Blender>;
    700         return allocator->make<Sampler>(next, pixelAccessor);
    701     } else {
    702         using Sampler = BilerpSampler<PixelAccessorShim, Blender>;
    703         return allocator->make<Sampler>(next, dimensions, xTile, yTile, pixelAccessor);
    704     }
    705 }
    706 
    707 Blender* SkLinearBitmapPipeline::chooseBlenderForShading(
    708     SkAlphaType alphaType,
    709     float postAlpha,
    710     SkArenaAlloc* allocator)
    711 {
    712     if (alphaType == kUnpremul_SkAlphaType) {
    713         return allocator->make<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
    714     } else {
    715         // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
    716         return allocator->make<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha);
    717     }
    718 }
    719