| Index: src/core/SkLinearBitmapPipeline.cpp
|
| diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp
|
| index 236f5bf8768712e13a19096d9b1fd55148229827..4ab0b90f550ef87063943f6fac9ac2816dc81236 100644
|
| --- a/src/core/SkLinearBitmapPipeline.cpp
|
| +++ b/src/core/SkLinearBitmapPipeline.cpp
|
| @@ -132,6 +132,39 @@ private:
|
| SkScalar fLength;
|
| int fCount;
|
| };
|
| +
|
| +// BilerpSpans are similar to Spans, but they represent four source samples converting to single
|
| +// destination pixel per count. The pixels for the four samples are collect along two horizontal
|
| +// lines; one starting at {x, y0} and the other starting at {x, y1}. There are two distinct lines
|
| +// to deal with the edge case of the tile mode. For example, y0 may be at the last y position in
|
| +// a tile while y1 would be at the first.
|
| +// The step of a Bilerp (dx) is still length / (count - 1) and the start to the next sample is
|
| +// still dx * count, but the bounds are complicated by the sampling kernel so that the pixels
|
| +// touched are from x to x + length + 1.
|
| +class BilerpSpan {
|
| +public:
|
| + BilerpSpan(SkScalar x, SkScalar y0, SkScalar y1, SkScalar length, int count)
|
| + : fX{x}, fY0{y0}, fY1{y1}, fLength{length}, fCount{count} {
|
| + SkASSERT(count >= 0);
|
| + SkASSERT(std::isfinite(length));
|
| + SkASSERT(std::isfinite(x));
|
| + SkASSERT(std::isfinite(y0));
|
| + SkASSERT(std::isfinite(y1));
|
| + }
|
| +
|
| + operator std::tuple<SkScalar&, SkScalar&, SkScalar&, SkScalar&, int&>() {
|
| + return std::tie(fX, fY0, fY1, fLength, fCount);
|
| + }
|
| +
|
| + bool isEmpty() const { return 0 == fCount; }
|
| +
|
| +private:
|
| + SkScalar fX;
|
| + SkScalar fY0;
|
| + SkScalar fY1;
|
| + SkScalar fLength;
|
| + int fCount;
|
| +};
|
| } // namespace
|
|
|
| class SkLinearBitmapPipeline::PointProcessorInterface {
|
| @@ -158,6 +191,7 @@ public:
|
| // These pixels coordinates are arranged in the following order in xs and ys:
|
| // px00 px10 px01 px11
|
| virtual void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) = 0;
|
| + virtual void bilerpSpan(BilerpSpan span) = 0;
|
| };
|
|
|
| class SkLinearBitmapPipeline::PixelPlacerInterface {
|
| @@ -197,6 +231,26 @@ void span_fallback(Span span, Stage* stage) {
|
| }
|
| }
|
|
|
| +template <typename Next>
|
| +void bilerp_span_fallback(BilerpSpan span, Next* next) {
|
| + SkScalar x, y0, y1; SkScalar length; int count;
|
| + std::tie(x, y0, y1, length, count) = span;
|
| +
|
| + SkASSERT(!span.isEmpty());
|
| + float dx = length / (count - 1);
|
| +
|
| + Sk4f xs = Sk4f{x} + Sk4f{0.0f, 1.0f, 0.0f, 1.0f};
|
| + Sk4f ys = Sk4f{y0, y0, y1, y1};
|
| +
|
| + // If count == 1 then dx will be inf or NaN, but that is ok because the resulting addition is
|
| + // never used.
|
| + while (count > 0) {
|
| + next->bilerpList(xs, ys);
|
| + xs = xs + dx;
|
| + count -= 1;
|
| + }
|
| +}
|
| +
|
| // PointProcessor uses a strategy to help complete the work of the different stages. The strategy
|
| // must implement the following methods:
|
| // * processPoints(xs, ys) - must mutate the xs and ys for the stage.
|
| @@ -268,6 +322,13 @@ public:
|
| }
|
| }
|
|
|
| + void bilerpSpan(BilerpSpan bSpan) override {
|
| + SkASSERT(!bSpan.isEmpty());
|
| + if (!fStrategy.maybeProcessBilerpSpan(bSpan, fNext)) {
|
| + bilerp_span_fallback(bSpan, this);
|
| + }
|
| + }
|
| +
|
| private:
|
| Next* const fNext;
|
| Strategy fStrategy;
|
| @@ -409,17 +470,9 @@ public:
|
| SkASSERT(!span.isEmpty());
|
| SkPoint start; SkScalar length; int count;
|
| std::tie(start, length, count) = span;
|
| - float dx = length / (count - 1);
|
| -
|
| - Sk4f Xs = Sk4f{X(start)} + Sk4f{-0.5f, 0.5f, -0.5f, 0.5f};
|
| - Sk4f Ys = Sk4f{Y(start)} + Sk4f{-0.5f, -0.5f, 0.5f, 0.5f};
|
| -
|
| - Sk4f dXs{dx};
|
| - while (count > 0) {
|
| - fNext->bilerpList(Xs, Ys);
|
| - Xs = Xs + dXs;
|
| - count -= 1;
|
| - }
|
| + // Adjust the span so that it is in the correct phase with the pixel.
|
| + BilerpSpan bSpan{X(start) - 0.5f, Y(start) - 0.5f, Y(start) + 0.5f, length, count};
|
| + fNext->bilerpSpan(bSpan);
|
| }
|
|
|
| private:
|
| @@ -540,6 +593,11 @@ public:
|
| return true;
|
| }
|
|
|
| + template <typename Next>
|
| + bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) {
|
| + return false;
|
| + }
|
| +
|
| private:
|
| const Sk4s fXMin{SK_FloatNegativeInfinity};
|
| const Sk4s fYMin{SK_FloatNegativeInfinity};
|
| @@ -643,6 +701,11 @@ public:
|
| return true;
|
| }
|
|
|
| + template <typename Next>
|
| + bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) {
|
| + return false;
|
| + }
|
| +
|
| private:
|
| const Sk4s fXMax{0.0f};
|
| const Sk4s fXInvMax{0.0f};
|
| @@ -924,6 +987,10 @@ private:
|
| span_fallback(span, this);
|
| }
|
|
|
| + void bilerpSpan(BilerpSpan span) override {
|
| + bilerp_span_fallback(span, this);
|
| + }
|
| +
|
| private:
|
| SkLinearBitmapPipeline::PixelPlacerInterface* const fNext;
|
| SourceStrategy fStrategy;
|
|
|