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 #include "SkPM4f.h"
     10 
     11 #include <algorithm>
     12 #include <cmath>
     13 #include <limits>
     14 #include "SkColor.h"
     15 #include "SkSize.h"
     16 
     17 // Tweak ABI of functions that pass Sk4f by value to pass them via registers.
     18 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
     19      #define VECTORCALL __vectorcall
     20  #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON)
     21      #define VECTORCALL __attribute__((pcs("aapcs-vfp")))
     22  #else
     23      #define VECTORCALL
     24  #endif
     25 
     26 class SkLinearBitmapPipeline::PointProcessorInterface {
     27 public:
     28     virtual ~PointProcessorInterface() { }
     29     virtual void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) = 0;
     30     virtual void VECTORCALL pointList4(Sk4f xs, Sk4f ys) = 0;
     31 
     32     // The pointSpan method efficiently process horizontal spans of pixels.
     33     // * start - the point where to start the span.
     34     // * length - the number of pixels to traverse in source space.
     35     // * count - the number of pixels to produce in destination space.
     36     // Both start and length are mapped through the inversion matrix to produce values in source
     37     // space. After the matrix operation, the tilers may break the spans up into smaller spans.
     38     // The tilers can produce spans that seem nonsensical.
     39     // * The clamp tiler can create spans with length of 0. This indicates to copy an edge pixel out
     40     //   to the edge of the destination scan.
     41     // * The mirror tiler can produce spans with negative length. This indicates that the source
     42     //   should be traversed in the opposite direction to the destination pixels.
     43     virtual void pointSpan(SkPoint start, SkScalar length, int count) = 0;
     44 };
     45 
     46 class SkLinearBitmapPipeline::BilerpProcessorInterface
     47     : public SkLinearBitmapPipeline::PointProcessorInterface {
     48 public:
     49     // The x's and y's are setup in the following order:
     50     // +--------+--------+
     51     // |        |        |
     52     // |  px00  |  px10  |
     53     // |    0   |    1   |
     54     // +--------+--------+
     55     // |        |        |
     56     // |  px01  |  px11  |
     57     // |    2   |    3   |
     58     // +--------+--------+
     59     // These pixels coordinates are arranged in the following order in xs and ys:
     60     // px00  px10  px01  px11
     61     virtual void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) = 0;
     62 };
     63 
     64 class SkLinearBitmapPipeline::PixelPlacerInterface {
     65 public:
     66     virtual ~PixelPlacerInterface() { }
     67     virtual void setDestination(SkPM4f* dst) = 0;
     68     virtual void VECTORCALL placePixel(Sk4f pixel0) = 0;
     69     virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0;
     70 };
     71 
     72 namespace  {
     73 
     74 struct X {
     75     explicit X(SkScalar val) : fVal{val} { }
     76     explicit X(SkPoint pt)   : fVal{pt.fX} { }
     77     explicit X(SkSize s)     : fVal{s.fWidth} { }
     78     explicit X(SkISize s)    : fVal(s.fWidth) { }
     79     operator float () const {return fVal;}
     80 private:
     81     float fVal;
     82 };
     83 
     84 struct Y {
     85     explicit Y(SkScalar val) : fVal{val} { }
     86     explicit Y(SkPoint pt)   : fVal{pt.fY} { }
     87     explicit Y(SkSize s)     : fVal{s.fHeight} { }
     88     explicit Y(SkISize s)    : fVal(s.fHeight) { }
     89     operator float () const {return fVal;}
     90 private:
     91     float fVal;
     92 };
     93 
     94 template <typename Stage>
     95 void span_fallback(SkPoint start, SkScalar length, int count, Stage* stage) {
     96     // If count == 1 use PointListFew instead.
     97     SkASSERT(count > 1);
     98 
     99     float dx = length / (count - 1);
    100     Sk4f Xs = Sk4f(X(start)) + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * Sk4f{dx};
    101     Sk4f Ys{Y(start)};
    102     Sk4f fourDx = {4.0f * dx};
    103 
    104     while (count >= 4) {
    105         stage->pointList4(Xs, Ys);
    106         Xs = Xs + fourDx;
    107         count -= 4;
    108     }
    109     if (count > 0) {
    110         stage->pointListFew(count, Xs, Ys);
    111     }
    112 }
    113 
    114 // PointProcessor uses a strategy to help complete the work of the different stages. The strategy
    115 // must implement the following methods:
    116 // * processPoints(xs, ys) - must mutate the xs and ys for the stage.
    117 // * maybeProcessSpan(start, length, count) - This represents a horizontal series of pixels
    118 //   to work over.
    119 //   start - is the starting pixel. This is in destination space before the matrix stage, and in
    120 //           source space after the matrix stage.
    121 //   length - is this distance between the first pixel center and the last pixel center. Like start,
    122 //           this is in destination space before the matrix stage, and in source space after.
    123 //   count - the number of pixels in source space to produce.
    124 //   next - a pointer to the next stage.
    125 //   maybeProcessSpan - returns false if it can not process the span and needs to fallback to
    126 //                      point lists for processing.
    127 template<typename Strategy, typename Next>
    128 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterface {
    129 public:
    130     template <typename... Args>
    131     PointProcessor(Next* next, Args&&... args)
    132         : fNext{next}
    133         , fStrategy{std::forward<Args>(args)...}{ }
    134 
    135     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
    136         fStrategy.processPoints(&xs, &ys);
    137         fNext->pointListFew(n, xs, ys);
    138     }
    139 
    140     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
    141         fStrategy.processPoints(&xs, &ys);
    142         fNext->pointList4(xs, ys);
    143     }
    144 
    145     void pointSpan(SkPoint start, SkScalar length, int count) override {
    146         if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) {
    147             span_fallback(start, length, count, this);
    148         }
    149     }
    150 
    151 private:
    152     Next* const fNext;
    153     Strategy fStrategy;
    154 };
    155 
    156 // See PointProcessor for responsibilities of Strategy.
    157 template<typename Strategy, typename Next>
    158 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInterface  {
    159 public:
    160     template <typename... Args>
    161     BilerpProcessor(Next* next, Args&&... args)
    162         : fNext{next}
    163         , fStrategy{std::forward<Args>(args)...}{ }
    164 
    165     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
    166         fStrategy.processPoints(&xs, &ys);
    167         fNext->pointListFew(n, xs, ys);
    168     }
    169 
    170     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
    171         fStrategy.processPoints(&xs, &ys);
    172         fNext->pointList4(xs, ys);
    173     }
    174 
    175     void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override {
    176         fStrategy.processPoints(&xs, &ys);
    177         fNext->bilerpList(xs, ys);
    178     }
    179 
    180     void pointSpan(SkPoint start, SkScalar length, int count) override {
    181         if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) {
    182             span_fallback(start, length, count, this);
    183         }
    184     }
    185 
    186 private:
    187     Next* const fNext;
    188     Strategy fStrategy;
    189 };
    190 
    191 class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterface {
    192     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
    193         SkFAIL("Skipped stage.");
    194     }
    195     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
    196         SkFAIL("Skipped stage.");
    197     }
    198     void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override {
    199         SkFAIL("Skipped stage.");
    200     }
    201     void pointSpan(SkPoint start, SkScalar length, int count) override {
    202         SkFAIL("Skipped stage.");
    203     }
    204 };
    205 
    206 class TranslateMatrixStrategy {
    207 public:
    208     TranslateMatrixStrategy(SkVector offset)
    209         : fXOffset{X(offset)}
    210         , fYOffset{Y(offset)} { }
    211 
    212     void processPoints(Sk4f* xs, Sk4f* ys) {
    213         *xs = *xs + fXOffset;
    214         *ys = *ys + fYOffset;
    215     }
    216 
    217     template <typename Next>
    218     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
    219         next->pointSpan(start + SkPoint{fXOffset[0], fYOffset[0]}, length, count);
    220         return true;
    221     }
    222 
    223 private:
    224     const Sk4f fXOffset, fYOffset;
    225 };
    226 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
    227 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>;
    228 
    229 class ScaleMatrixStrategy {
    230 public:
    231     ScaleMatrixStrategy(SkVector offset, SkVector scale)
    232         : fXOffset{X(offset)}, fYOffset{Y(offset)}
    233         ,  fXScale{X(scale)},   fYScale{Y(scale)} { }
    234     void processPoints(Sk4f* xs, Sk4f* ys) {
    235         *xs = *xs * fXScale + fXOffset;
    236         *ys = *ys * fYScale + fYOffset;
    237     }
    238 
    239     template <typename Next>
    240     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
    241         SkPoint newStart =
    242             SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] + fYOffset[0]};
    243         SkScalar newLength = length * fXScale[0];
    244         next->pointSpan(newStart, newLength, count);
    245         return true;
    246     }
    247 
    248 private:
    249     const Sk4f fXOffset, fYOffset;
    250     const Sk4f fXScale, fYScale;
    251 };
    252 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
    253 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>;
    254 
    255 class AffineMatrixStrategy {
    256 public:
    257     AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew)
    258         : fXOffset{X(offset)}, fYOffset{Y(offset)}
    259         , fXScale{X(scale)},   fYScale{Y(scale)}
    260         , fXSkew{X(skew)},     fYSkew{Y(skew)} { }
    261     void processPoints(Sk4f* xs, Sk4f* ys) {
    262         Sk4f newXs = fXScale * *xs +  fXSkew * *ys + fXOffset;
    263         Sk4f newYs =  fYSkew * *xs + fYScale * *ys + fYOffset;
    264 
    265         *xs = newXs;
    266         *ys = newYs;
    267     }
    268 
    269     template <typename Next>
    270     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
    271         return false;
    272     }
    273 
    274 private:
    275     const Sk4f fXOffset, fYOffset;
    276     const Sk4f fXScale,  fYScale;
    277     const Sk4f fXSkew,   fYSkew;
    278 };
    279 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
    280 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>;
    281 
    282 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix(
    283     SkLinearBitmapPipeline::PointProcessorInterface* next,
    284     const SkMatrix& inverse,
    285     SkLinearBitmapPipeline::MatrixStage* matrixProc) {
    286     if (inverse.hasPerspective()) {
    287         SkFAIL("Not implemented.");
    288     } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
    289         matrixProc->Initialize<AffineMatrix<>>(
    290             next,
    291             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
    292             SkVector{inverse.getScaleX(), inverse.getScaleY()},
    293             SkVector{inverse.getSkewX(), inverse.getSkewY()});
    294     } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
    295         matrixProc->Initialize<ScaleMatrix<>>(
    296             next,
    297             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
    298             SkVector{inverse.getScaleX(), inverse.getScaleY()});
    299     } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
    300         matrixProc->Initialize<TranslateMatrix<>>(
    301             next,
    302             SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
    303     } else {
    304         matrixProc->Initialize<SkippedStage>();
    305         return next;
    306     }
    307     return matrixProc->get();
    308 }
    309 
    310 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
    311 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterface {
    312 public:
    313     ExpandBilerp(Next* next) : fNext{next} { }
    314 
    315     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
    316         SkASSERT(0 < n && n < 4);
    317         //                    px00   px10   px01  px11
    318         const Sk4f kXOffsets{-0.5f,  0.5f, -0.5f, 0.5f},
    319                    kYOffsets{-0.5f, -0.5f,  0.5f, 0.5f};
    320         if (n >= 1) fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets);
    321         if (n >= 2) fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets);
    322         if (n >= 3) fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets);
    323     }
    324 
    325     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
    326         //                    px00   px10   px01  px11
    327         const Sk4f kXOffsets{-0.5f,  0.5f, -0.5f, 0.5f},
    328                    kYOffsets{-0.5f, -0.5f,  0.5f, 0.5f};
    329         fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets);
    330         fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets);
    331         fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets);
    332         fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYOffsets);
    333     }
    334 
    335     void pointSpan(SkPoint start, SkScalar length, int count) override {
    336         span_fallback(start, length, count, this);
    337     }
    338 
    339 private:
    340     Next* const fNext;
    341 };
    342 
    343 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter(
    344     SkLinearBitmapPipeline::BilerpProcessorInterface* next,
    345     SkFilterQuality filterQuailty,
    346     SkLinearBitmapPipeline::FilterStage* filterProc) {
    347     if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) {
    348         filterProc->Initialize<SkippedStage>();
    349         return next;
    350     } else {
    351         filterProc->Initialize<ExpandBilerp<>>(next);
    352         return filterProc->get();
    353     }
    354 }
    355 
    356 class ClampStrategy {
    357 public:
    358     ClampStrategy(X max)
    359         : fXMin{0.0f}
    360         , fXMax{max - 1.0f} { }
    361     ClampStrategy(Y max)
    362         : fYMin{0.0f}
    363         , fYMax{max - 1.0f} { }
    364     ClampStrategy(SkSize max)
    365         : fXMin{0.0f}
    366         , fYMin{0.0f}
    367         , fXMax{X(max) - 1.0f}
    368         , fYMax{Y(max) - 1.0f} { }
    369 
    370     void processPoints(Sk4f* xs, Sk4f* ys) {
    371         *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax);
    372         *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax);
    373     }
    374 
    375     template <typename Next>
    376     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
    377         return false;
    378     }
    379 
    380 private:
    381     const Sk4f fXMin{SK_FloatNegativeInfinity};
    382     const Sk4f fYMin{SK_FloatNegativeInfinity};
    383     const Sk4f fXMax{SK_FloatInfinity};
    384     const Sk4f fYMax{SK_FloatInfinity};
    385 };
    386 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
    387 using Clamp = BilerpProcessor<ClampStrategy, Next>;
    388 
    389 class RepeatStrategy {
    390 public:
    391     RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { }
    392     RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { }
    393     RepeatStrategy(SkSize max)
    394         : fXMax{X(max)}
    395         , fXInvMax{1.0f / X(max)}
    396         , fYMax{Y(max)}
    397         , fYInvMax{1.0f / Y(max)} { }
    398 
    399     void processPoints(Sk4f* xs, Sk4f* ys) {
    400         Sk4f divX = (*xs * fXInvMax).floor();
    401         Sk4f divY = (*ys * fYInvMax).floor();
    402         Sk4f baseX = (divX * fXMax);
    403         Sk4f baseY = (divY * fYMax);
    404         *xs = *xs - baseX;
    405         *ys = *ys - baseY;
    406     }
    407 
    408     template <typename Next>
    409     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
    410         return false;
    411     }
    412 
    413 private:
    414     const Sk4f fXMax{0.0f};
    415     const Sk4f fXInvMax{0.0f};
    416     const Sk4f fYMax{0.0f};
    417     const Sk4f fYInvMax{0.0f};
    418 };
    419 
    420 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
    421 using Repeat = BilerpProcessor<RepeatStrategy, Next>;
    422 
    423 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler(
    424     SkLinearBitmapPipeline::BilerpProcessorInterface* next,
    425     SkSize dimensions,
    426     SkShader::TileMode xMode,
    427     SkShader::TileMode yMode,
    428     SkLinearBitmapPipeline::TileStage* tileProcXOrBoth,
    429     SkLinearBitmapPipeline::TileStage* tileProcY) {
    430     if (xMode == yMode) {
    431         switch (xMode) {
    432             case SkShader::kClamp_TileMode:
    433                 tileProcXOrBoth->Initialize<Clamp<>>(next, dimensions);
    434                 break;
    435             case SkShader::kRepeat_TileMode:
    436                 tileProcXOrBoth->Initialize<Repeat<>>(next, dimensions);
    437                 break;
    438             case SkShader::kMirror_TileMode:
    439                 SkFAIL("Not implemented.");
    440                 break;
    441         }
    442         tileProcY->Initialize<SkippedStage>();
    443     } else {
    444         switch (yMode) {
    445             case SkShader::kClamp_TileMode:
    446                 tileProcY->Initialize<Clamp<>>(next, Y(dimensions));
    447                 break;
    448             case SkShader::kRepeat_TileMode:
    449                 tileProcY->Initialize<Repeat<>>(next, Y(dimensions));
    450                 break;
    451             case SkShader::kMirror_TileMode:
    452                 SkFAIL("Not implemented.");
    453                 break;
    454         }
    455         switch (xMode) {
    456             case SkShader::kClamp_TileMode:
    457                 tileProcXOrBoth->Initialize<Clamp<>>(tileProcY->get(), X(dimensions));
    458                 break;
    459             case SkShader::kRepeat_TileMode:
    460                 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimensions));
    461                 break;
    462             case SkShader::kMirror_TileMode:
    463                 SkFAIL("Not implemented.");
    464                 break;
    465         }
    466     }
    467     return tileProcXOrBoth->get();
    468 }
    469 
    470 class sRGBFast {
    471 public:
    472     static Sk4f VECTORCALL sRGBToLinear(Sk4f pixel) {
    473         Sk4f l = pixel * pixel;
    474         return Sk4f{l[0], l[1], l[2], pixel[3]};
    475     }
    476 };
    477 
    478 template <SkColorProfileType colorProfile>
    479 class Passthrough8888 {
    480 public:
    481     Passthrough8888(int width, const uint32_t* src)
    482         : fSrc{src}, fWidth{width}{ }
    483 
    484     void VECTORCALL getFewPixels(int n, Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) {
    485         Sk4i XIs = SkNx_cast<int, float>(xs);
    486         Sk4i YIs = SkNx_cast<int, float>(ys);
    487         Sk4i bufferLoc = YIs * fWidth + XIs;
    488         switch (n) {
    489             case 3:
    490                 *px2 = getPixel(fSrc, bufferLoc[2]);
    491             case 2:
    492                 *px1 = getPixel(fSrc, bufferLoc[1]);
    493             case 1:
    494                 *px0 = getPixel(fSrc, bufferLoc[0]);
    495             default:
    496                 break;
    497         }
    498     }
    499 
    500     void VECTORCALL get4Pixels(Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) {
    501         Sk4i XIs = SkNx_cast<int, float>(xs);
    502         Sk4i YIs = SkNx_cast<int, float>(ys);
    503         Sk4i bufferLoc = YIs * fWidth + XIs;
    504         *px0 = getPixel(fSrc, bufferLoc[0]);
    505         *px1 = getPixel(fSrc, bufferLoc[1]);
    506         *px2 = getPixel(fSrc, bufferLoc[2]);
    507         *px3 = getPixel(fSrc, bufferLoc[3]);
    508     }
    509 
    510     const uint32_t* row(int y) { return fSrc + y * fWidth[0]; }
    511 
    512 private:
    513     Sk4f getPixel(const uint32_t* src, int index) {
    514         Sk4b bytePixel = Sk4b::Load((uint8_t *)(&src[index]));
    515         Sk4f pixel = SkNx_cast<float, uint8_t>(bytePixel);
    516         pixel = pixel * Sk4f{1.0f/255.0f};
    517         if (colorProfile == kSRGB_SkColorProfileType) {
    518             pixel = sRGBFast::sRGBToLinear(pixel);
    519         }
    520         return pixel;
    521     }
    522     const uint32_t* const fSrc;
    523     const Sk4i fWidth;
    524 };
    525 
    526 // Explaination of the math:
    527 //              1 - x      x
    528 //           +--------+--------+
    529 //           |        |        |
    530 //  1 - y    |  px00  |  px10  |
    531 //           |        |        |
    532 //           +--------+--------+
    533 //           |        |        |
    534 //    y      |  px01  |  px11  |
    535 //           |        |        |
    536 //           +--------+--------+
    537 //
    538 //
    539 // Given a pixelxy each is multiplied by a different factor derived from the fractional part of x
    540 // and y:
    541 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy
    542 // * px10 -> x(1 - y) = x - xy
    543 // * px01 -> (1 - x)y = y - xy
    544 // * px11 -> xy
    545 // So x * y is calculated first and then used to calculate all the other factors.
    546 static Sk4f VECTORCALL bilerp4(Sk4f xs, Sk4f ys, Sk4f px00, Sk4f px10,
    547                                                  Sk4f px01, Sk4f px11) {
    548     // Calculate fractional xs and ys.
    549     Sk4f fxs = xs - xs.floor();
    550     Sk4f fys = ys - ys.floor();
    551     Sk4f fxys{fxs * fys};
    552     Sk4f sum =  px11 * fxys;
    553     sum = sum + px01 * (fys - fxys);
    554     sum = sum + px10 * (fxs - fxys);
    555     sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys);
    556     return sum;
    557 }
    558 
    559 template <typename SourceStrategy>
    560 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface {
    561 public:
    562     template <typename... Args>
    563     Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args)
    564         : fNext{next}
    565         , fStrategy{std::forward<Args>(args)...} { }
    566 
    567     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
    568         SkASSERT(0 < n && n < 4);
    569         Sk4f px0, px1, px2;
    570         fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2);
    571         if (n >= 1) fNext->placePixel(px0);
    572         if (n >= 2) fNext->placePixel(px1);
    573         if (n >= 3) fNext->placePixel(px2);
    574     }
    575 
    576     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
    577         Sk4f px0, px1, px2, px3;
    578         fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
    579         fNext->place4Pixels(px0, px1, px2, px3);
    580     }
    581 
    582     void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override {
    583         Sk4f px00, px10, px01, px11;
    584         fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11);
    585         Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11);
    586         fNext->placePixel(pixel);
    587     }
    588 
    589     void pointSpan(SkPoint start, SkScalar length, int count) override {
    590         span_fallback(start, length, count, this);
    591     }
    592 
    593 private:
    594     SkLinearBitmapPipeline::PixelPlacerInterface* const fNext;
    595     SourceStrategy fStrategy;
    596 };
    597 
    598 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler(
    599     SkLinearBitmapPipeline::PixelPlacerInterface* next,
    600     const SkPixmap& srcPixmap,
    601     SkLinearBitmapPipeline::SampleStage* sampleStage) {
    602     const SkImageInfo& imageInfo = srcPixmap.info();
    603     switch (imageInfo.colorType()) {
    604         case kRGBA_8888_SkColorType:
    605         case kBGRA_8888_SkColorType:
    606             if (kN32_SkColorType == imageInfo.colorType()) {
    607                 if (imageInfo.profileType() == kSRGB_SkColorProfileType) {
    608                     sampleStage->Initialize<Sampler<Passthrough8888<kSRGB_SkColorProfileType>>>(
    609                         next, static_cast<int>(srcPixmap.rowBytes() / 4),
    610                         srcPixmap.addr32());
    611                 } else {
    612                     sampleStage->Initialize<Sampler<Passthrough8888<kLinear_SkColorProfileType>>>(
    613                         next, static_cast<int>(srcPixmap.rowBytes() / 4),
    614                         srcPixmap.addr32());
    615                 }
    616             } else {
    617                 SkFAIL("Not implemented. No 8888 Swizzle");
    618             }
    619             break;
    620         default:
    621             SkFAIL("Not implemented. Unsupported src");
    622             break;
    623     }
    624     return sampleStage->get();
    625 }
    626 
    627 template <SkAlphaType alphaType>
    628 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface {
    629 public:
    630     void VECTORCALL placePixel(Sk4f pixel) override {
    631         PlacePixel(fDst, pixel, 0);
    632         fDst += 1;
    633     }
    634 
    635     void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
    636         SkPM4f* dst = fDst;
    637         PlacePixel(dst, p0, 0);
    638         PlacePixel(dst, p1, 1);
    639         PlacePixel(dst, p2, 2);
    640         PlacePixel(dst, p3, 3);
    641         fDst += 4;
    642     }
    643 
    644     void setDestination(SkPM4f* dst) override {
    645         fDst = dst;
    646     }
    647 
    648 private:
    649     static void VECTORCALL PlacePixel(SkPM4f* dst, Sk4f pixel, int index) {
    650         Sk4f newPixel = pixel;
    651         if (alphaType == kUnpremul_SkAlphaType) {
    652             newPixel = Premultiply(pixel);
    653         }
    654         newPixel.store(dst + index);
    655     }
    656     static Sk4f VECTORCALL Premultiply(Sk4f pixel) {
    657         float alpha = pixel[3];
    658         return pixel * Sk4f{alpha, alpha, alpha, 1.0f};
    659     }
    660 
    661     SkPM4f* fDst;
    662 };
    663 
    664 static SkLinearBitmapPipeline::PixelPlacerInterface* choose_pixel_placer(
    665     SkAlphaType alphaType,
    666     SkLinearBitmapPipeline::PixelStage* placerStage) {
    667     if (alphaType == kUnpremul_SkAlphaType) {
    668         placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>();
    669     } else {
    670         // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
    671         placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>();
    672     }
    673     return placerStage->get();
    674 }
    675 }  // namespace
    676 
    677 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
    678 
    679 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
    680     const SkMatrix& inverse,
    681     SkFilterQuality filterQuality,
    682     SkShader::TileMode xTile, SkShader::TileMode yTile,
    683     const SkPixmap& srcPixmap) {
    684     SkSize size = SkSize::Make(srcPixmap.width(), srcPixmap.height());
    685     const SkImageInfo& srcImageInfo = srcPixmap.info();
    686 
    687     // As the stages are built, the chooser function may skip a stage. For example, with the
    688     // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
    689     auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelStage);
    690     auto samplerStage   = choose_pixel_sampler(placementStage, srcPixmap, &fSampleStage);
    691     auto tilerStage     = choose_tiler(samplerStage, size, xTile, yTile, &fTileXOrBothStage,
    692                                        &fTileYStage);
    693     auto filterStage    = choose_filter(tilerStage, filterQuality, &fFilterStage);
    694     fFirstStage         = choose_matrix(filterStage, inverse, &fMatrixStage);
    695 }
    696 
    697 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
    698     SkASSERT(count > 0);
    699     fPixelStage->setDestination(dst);
    700     // Adjust points by 0.5, 0.5 to sample from the center of the pixels.
    701     if (count == 1) {
    702         fFirstStage->pointListFew(1, Sk4f{x + 0.5f}, Sk4f{y + 0.5f});
    703     } else {
    704         // The count and length arguments start out in a precise relation in order to keep the
    705         // math correct through the different stages. Count is the number of pixel to produce.
    706         // Since the code samples at pixel centers, length is the distance from the center of the
    707         // first pixel to the center of the last pixel. This implies that length is count-1.
    708         fFirstStage->pointSpan(SkPoint{x + 0.5f, y + 0.5f}, count - 1, count);
    709     }
    710 }
    711