| Index: src/core/SkLinearBitmapPipeline_sample.h
|
| diff --git a/src/core/SkLinearBitmapPipeline_sample.h b/src/core/SkLinearBitmapPipeline_sample.h
|
| index 15a7c359cc1ab6ace6fa15024ac43e31232f91fa..930759f271ea1a108432a4ac4447209f794cccc7 100644
|
| --- a/src/core/SkLinearBitmapPipeline_sample.h
|
| +++ b/src/core/SkLinearBitmapPipeline_sample.h
|
| @@ -266,22 +266,60 @@ private:
|
| PixelGetter<colorType, colorProfile> fGetter;
|
| };
|
|
|
| -////////////////////////////////////////////////////////////////////////////////////////////////////
|
| -// GeneralSampler handles all the different sampling scenarios. It makes runtime decisions to
|
| -// choose the fastest strategy given a particular job. It ultimately uses PixelGetters to access
|
| -// the pixels.
|
| +// We're moving through source space at a rate of 1 source pixel per 1 dst pixel.
|
| +// We'll never re-use pixels, but we can at least load contiguous pixels.
|
| +template <typename Next, typename Strategy>
|
| +static void src_strategy_blend(Span span, Next* next, Strategy* strategy) {
|
| + SkPoint start;
|
| + SkScalar length;
|
| + int count;
|
| + std::tie(start, length, count) = span;
|
| + int ix = SkScalarFloorToInt(X(start));
|
| + const void* row = strategy->row((int)std::floor(Y(start)));
|
| + if (length > 0) {
|
| + while (count >= 4) {
|
| + Sk4f px0, px1, px2, px3;
|
| + strategy->get4Pixels(row, ix, &px0, &px1, &px2, &px3);
|
| + next->blend4Pixels(px0, px1, px2, px3);
|
| + ix += 4;
|
| + count -= 4;
|
| + }
|
| +
|
| + while (count > 0) {
|
| + next->blendPixel(strategy->getPixelFromRow(row, ix));
|
| + ix += 1;
|
| + count -= 1;
|
| + }
|
| + } else {
|
| + while (count >= 4) {
|
| + Sk4f px0, px1, px2, px3;
|
| + strategy->get4Pixels(row, ix - 3, &px3, &px2, &px1, &px0);
|
| + next->blend4Pixels(px0, px1, px2, px3);
|
| + ix -= 4;
|
| + count -= 4;
|
| + }
|
| +
|
| + while (count > 0) {
|
| + next->blendPixel(strategy->getPixelFromRow(row, ix));
|
| + ix -= 1;
|
| + count -= 1;
|
| + }
|
| + }
|
| +}
|
| +
|
| +// NearestNeighborSampler - use nearest neighbor filtering to create runs of destination pixels.
|
| template<SkColorType colorType, SkColorProfileType colorProfile, typename Next>
|
| -class GeneralSampler {
|
| +class NearestNeighborSampler : public SkLinearBitmapPipeline::SampleProcessorInterface {
|
| public:
|
| template<typename... Args>
|
| - GeneralSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next, Args&& ... args)
|
| - : fNext{next}, fStrategy{std::forward<Args>(args)...} { }
|
| + NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next, Args&& ... args)
|
| + : fNext{next}, fStrategy{std::forward<Args>(args)...} { }
|
|
|
| - GeneralSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next,
|
| - const GeneralSampler& sampler)
|
| - : fNext{next}, fStrategy{sampler.fStrategy} { }
|
| + NearestNeighborSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next,
|
| + const NearestNeighborSampler& sampler)
|
| + : fNext{next}, fStrategy{sampler.fStrategy} { }
|
|
|
| - void VECTORCALL nearestListFew(int n, Sk4s xs, Sk4s ys) {
|
| + void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
|
| SkASSERT(0 < n && n < 4);
|
| Sk4f px0, px1, px2;
|
| fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2);
|
| @@ -290,13 +328,13 @@ public:
|
| if (n >= 3) fNext->blendPixel(px2);
|
| }
|
|
|
| - void VECTORCALL nearestList4(Sk4s xs, Sk4s ys) {
|
| + void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
|
| Sk4f px0, px1, px2, px3;
|
| fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
|
| fNext->blend4Pixels(px0, px1, px2, px3);
|
| }
|
|
|
| - void nearestSpan(Span span) {
|
| + void pointSpan(Span span) override {
|
| SkASSERT(!span.isEmpty());
|
| SkPoint start;
|
| SkScalar length;
|
| @@ -304,86 +342,33 @@ public:
|
| std::tie(start, length, count) = span;
|
| SkScalar absLength = SkScalarAbs(length);
|
| if (absLength < (count - 1)) {
|
| - this->nearestSpanSlowRate(span);
|
| + this->spanSlowRate(span);
|
| } else if (absLength == (count - 1)) {
|
| - this->nearestSpanUnitRate(span);
|
| + src_strategy_blend(span, fNext, &fStrategy);
|
| } else {
|
| - this->nearestSpanFastRate(span);
|
| + this->spanFastRate(span);
|
| }
|
| }
|
|
|
| - Sk4f bilerpNonEdgePixel(SkScalar x, SkScalar y) {
|
| - Sk4f px00, px10, px01, px11;
|
| - // bilerp4() expects xs, ys are the top-lefts of the 2x2 kernel.
|
| - Sk4f xs = Sk4f{x} - 0.5f;
|
| - Sk4f ys = Sk4f{y} - 0.5f;
|
| - Sk4f sampleXs = xs + Sk4f{0.0f, 1.0f, 0.0f, 1.0f};
|
| - Sk4f sampleYs = ys + Sk4f{0.0f, 0.0f, 1.0f, 1.0f};
|
| - fStrategy.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
|
| - return bilerp4(xs, ys, px00, px10, px01, px11);
|
| - }
|
| -
|
| - void VECTORCALL bilerpListFew(int n, Sk4s xs, Sk4s ys) {
|
| - SkASSERT(0 < n && n < 4);
|
| - auto bilerpPixel = [&](int index) {
|
| - return this->bilerpNonEdgePixel(xs[index], ys[index]);
|
| - };
|
| -
|
| - if (n >= 1) fNext->blendPixel(bilerpPixel(0));
|
| - if (n >= 2) fNext->blendPixel(bilerpPixel(1));
|
| - if (n >= 3) fNext->blendPixel(bilerpPixel(2));
|
| - }
|
| -
|
| - void VECTORCALL bilerpList4(Sk4s xs, Sk4s ys) {
|
| - auto bilerpPixel = [&](int index) {
|
| - return this->bilerpNonEdgePixel(xs[index], ys[index]);
|
| - };
|
| - fNext->blend4Pixels(bilerpPixel(0), bilerpPixel(1), bilerpPixel(2), bilerpPixel(3));
|
| - }
|
| -
|
| - void VECTORCALL bilerpEdge(Sk4s sampleXs, Sk4s sampleYs) {
|
| - Sk4f px00, px10, px01, px11;
|
| - Sk4f xs = Sk4f{sampleXs[0]};
|
| - Sk4f ys = Sk4f{sampleYs[0]};
|
| - fStrategy.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
|
| - Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11);
|
| - fNext->blendPixel(pixel);
|
| + void repeatSpan(Span span, int32_t repeatCount) override {
|
| + while (repeatCount > 0) {
|
| + this->pointSpan(span);
|
| + repeatCount--;
|
| + }
|
| }
|
|
|
| - void bilerpSpan(Span span) {
|
| - this->bilerpSpanWithY(span, span.startY());
|
| + void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override {
|
| + SkFAIL("Using nearest neighbor sampler, but calling a bilerpEdge.");
|
| }
|
|
|
| - void bilerpSpanWithY(Span span, SkScalar y) {
|
| - SkASSERT(!span.isEmpty());
|
| - SkPoint start;
|
| - SkScalar length;
|
| - int count;
|
| - std::tie(start, length, count) = span;
|
| - SkScalar absLength = SkScalarAbs(length);
|
| - if (absLength == 0.0f) {
|
| - this->bilerpSpanZeroRate(span, y);
|
| - } else if (absLength < (count - 1)) {
|
| - this->bilerpSpanSlowRate(span, y);
|
| - } else if (absLength == (count - 1)) {
|
| - if (std::fmod(span.startX() - 0.5f, 1.0f) == 0.0f) {
|
| - if (std::fmod(span.startY() - 0.5f, 1.0f) == 0.0f) {
|
| - this->nearestSpanUnitRate(span);
|
| - } else {
|
| - this->bilerpSpanUnitRateAlignedX(span, y);
|
| - }
|
| - } else {
|
| - this->bilerpSpanUnitRate(span, y);
|
| - }
|
| - } else {
|
| - this->bilerpSpanFastRate(span, y);
|
| - }
|
| + void bilerpSpan(Span span, SkScalar y) override {
|
| + SkFAIL("Using nearest neighbor sampler, but calling a bilerpSpan.");
|
| }
|
|
|
| private:
|
| // When moving through source space more slowly than dst space (zoomed in),
|
| // we'll be sampling from the same source pixel more than once.
|
| - void nearestSpanSlowRate(Span span) {
|
| + void spanSlowRate(Span span) {
|
| SkPoint start;
|
| SkScalar length;
|
| int count;
|
| @@ -429,64 +414,110 @@ private:
|
|
|
| // We're moving through source space at a rate of 1 source pixel per 1 dst pixel.
|
| // We'll never re-use pixels, but we can at least load contiguous pixels.
|
| - void nearestSpanUnitRate(Span span) {
|
| - SkPoint start;
|
| - SkScalar length;
|
| - int count;
|
| - std::tie(start, length, count) = span;
|
| - int ix = SkScalarFloorToInt(X(start));
|
| - const void* row = fStrategy.row((int)std::floor(Y(start)));
|
| - Next* next = fNext;
|
| - if (length > 0) {
|
| - while (count >= 4) {
|
| - Sk4f px0, px1, px2, px3;
|
| - fStrategy.get4Pixels(row, ix, &px0, &px1, &px2, &px3);
|
| - next->blend4Pixels(px0, px1, px2, px3);
|
| - ix += 4;
|
| - count -= 4;
|
| - }
|
| -
|
| - while (count > 0) {
|
| - next->blendPixel(fStrategy.getPixelFromRow(row, ix));
|
| - ix += 1;
|
| - count -= 1;
|
| - }
|
| - } else {
|
| - while (count >= 4) {
|
| - Sk4f px0, px1, px2, px3;
|
| - fStrategy.get4Pixels(row, ix - 3, &px3, &px2, &px1, &px0);
|
| - next->blend4Pixels(px0, px1, px2, px3);
|
| - ix -= 4;
|
| - count -= 4;
|
| - }
|
| -
|
| - while (count > 0) {
|
| - next->blendPixel(fStrategy.getPixelFromRow(row, ix));
|
| - ix -= 1;
|
| - count -= 1;
|
| - }
|
| - }
|
| + void spanUnitRate(Span span) {
|
| + src_strategy_blend(span, fNext, &fStrategy);
|
| }
|
|
|
| // We're moving through source space faster than dst (zoomed out),
|
| // so we'll never reuse a source pixel or be able to do contiguous loads.
|
| - void nearestSpanFastRate(Span span) {
|
| - struct NearestWrapper {
|
| - void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) {
|
| - fSampler.nearestListFew(n, xs, ys);
|
| - }
|
| + void spanFastRate(Span span) {
|
| + span_fallback(span, this);
|
| + }
|
|
|
| - void VECTORCALL pointList4(Sk4s xs, Sk4s ys) {
|
| - fSampler.nearestList4(xs, ys);
|
| - }
|
| + Next* const fNext;
|
| + PixelAccessor<colorType, colorProfile> fStrategy;
|
| +};
|
| +
|
| +// BilerpSampler - use a bilerp filter to create runs of destination pixels.
|
| +template<SkColorType colorType, SkColorProfileType colorProfile, typename Next>
|
| +class BilerpSampler : public SkLinearBitmapPipeline::SampleProcessorInterface {
|
| +public:
|
| + template<typename... Args>
|
| + BilerpSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next, Args&& ... args)
|
| + : fNext{next}, fStrategy{std::forward<Args>(args)...} { }
|
|
|
| - GeneralSampler& fSampler;
|
| + BilerpSampler(SkLinearBitmapPipeline::BlendProcessorInterface* next,
|
| + const BilerpSampler& sampler)
|
| + : fNext{next}, fStrategy{sampler.fStrategy} { }
|
| +
|
| + Sk4f bilerpNonEdgePixel(SkScalar x, SkScalar y) {
|
| + Sk4f px00, px10, px01, px11;
|
| +
|
| + // bilerp4() expects xs, ys are the top-lefts of the 2x2 kernel.
|
| + Sk4f xs = Sk4f{x} - 0.5f;
|
| + Sk4f ys = Sk4f{y} - 0.5f;
|
| + Sk4f sampleXs = xs + Sk4f{0.0f, 1.0f, 0.0f, 1.0f};
|
| + Sk4f sampleYs = ys + Sk4f{0.0f, 0.0f, 1.0f, 1.0f};
|
| + fStrategy.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
|
| + return bilerp4(xs, ys, px00, px10, px01, px11);
|
| + }
|
| +
|
| + void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
|
| + SkASSERT(0 < n && n < 4);
|
| + auto bilerpPixel = [&](int index) {
|
| + return this->bilerpNonEdgePixel(xs[index], ys[index]);
|
| };
|
| - NearestWrapper wrapper{*this};
|
| - span_fallback(span, &wrapper);
|
| +
|
| + if (n >= 1) fNext->blendPixel(bilerpPixel(0));
|
| + if (n >= 2) fNext->blendPixel(bilerpPixel(1));
|
| + if (n >= 3) fNext->blendPixel(bilerpPixel(2));
|
| }
|
|
|
| - void bilerpSpanZeroRate(Span span, SkScalar y1) {
|
| + void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
|
| + auto bilerpPixel = [&](int index) {
|
| + return this->bilerpNonEdgePixel(xs[index], ys[index]);
|
| + };
|
| + fNext->blend4Pixels(bilerpPixel(0), bilerpPixel(1), bilerpPixel(2), bilerpPixel(3));
|
| + }
|
| +
|
| + void pointSpan(Span span) override {
|
| + this->bilerpSpan(span, span.startY());
|
| + }
|
| +
|
| + void repeatSpan(Span span, int32_t repeatCount) override {
|
| + while (repeatCount > 0) {
|
| + this->pointSpan(span);
|
| + repeatCount--;
|
| + }
|
| + }
|
| +
|
| + void VECTORCALL bilerpEdge(Sk4s sampleXs, Sk4s sampleYs) override {
|
| + Sk4f px00, px10, px01, px11;
|
| + Sk4f xs = Sk4f{sampleXs[0]};
|
| + Sk4f ys = Sk4f{sampleYs[0]};
|
| + fStrategy.get4Pixels(sampleXs, sampleYs, &px00, &px10, &px01, &px11);
|
| + Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11);
|
| + fNext->blendPixel(pixel);
|
| + }
|
| +
|
| + void bilerpSpan(Span span, SkScalar y) override {
|
| + SkASSERT(!span.isEmpty());
|
| + SkPoint start;
|
| + SkScalar length;
|
| + int count;
|
| + std::tie(start, length, count) = span;
|
| + SkScalar absLength = SkScalarAbs(length);
|
| + if (absLength == 0.0f) {
|
| + this->spanZeroRate(span, y);
|
| + } else if (absLength < (count - 1)) {
|
| + this->spanSlowRate(span, y);
|
| + } else if (absLength == (count - 1)) {
|
| + if (std::fmod(span.startX() - 0.5f, 1.0f) == 0.0f) {
|
| + if (std::fmod(span.startY() - 0.5f, 1.0f) == 0.0f) {
|
| + src_strategy_blend(span, fNext, &fStrategy);
|
| + } else {
|
| + this->spanUnitRateAlignedX(span, y);
|
| + }
|
| + } else {
|
| + this->spanUnitRate(span, y);
|
| + }
|
| + } else {
|
| + this->spanFastRate(span, y);
|
| + }
|
| + }
|
| +
|
| +private:
|
| + void spanZeroRate(Span span, SkScalar y1) {
|
| SkScalar y0 = span.startY() - 0.5f;
|
| y1 += 0.5f;
|
| int iy0 = SkScalarFloorToInt(y0);
|
| @@ -510,7 +541,7 @@ private:
|
|
|
| // When moving through source space more slowly than dst space (zoomed in),
|
| // we'll be sampling from the same source pixel more than once.
|
| - void bilerpSpanSlowRate(Span span, SkScalar ry1) {
|
| + void spanSlowRate(Span span, SkScalar ry1) {
|
| SkPoint start;
|
| SkScalar length;
|
| int count;
|
| @@ -579,7 +610,7 @@ private:
|
|
|
| // We're moving through source space at a rate of 1 source pixel per 1 dst pixel.
|
| // We'll never re-use pixels, but we can at least load contiguous pixels.
|
| - void bilerpSpanUnitRate(Span span, SkScalar y1) {
|
| + void spanUnitRate(Span span, SkScalar y1) {
|
| y1 += 0.5f;
|
| SkScalar y0 = span.startY() - 0.5f;
|
| int iy0 = SkScalarFloorToInt(y0);
|
| @@ -684,7 +715,7 @@ private:
|
| }
|
| }
|
|
|
| - void bilerpSpanUnitRateAlignedX(Span span, SkScalar y1) {
|
| + void spanUnitRateAlignedX(Span span, SkScalar y1) {
|
| SkScalar y0 = span.startY() - 0.5f;
|
| y1 += 0.5f;
|
| int iy0 = SkScalarFloorToInt(y0);
|
| @@ -743,30 +774,19 @@ private:
|
|
|
| // We're moving through source space faster than dst (zoomed out),
|
| // so we'll never reuse a source pixel or be able to do contiguous loads.
|
| - void bilerpSpanFastRate(Span span, SkScalar y1) {
|
| + void spanFastRate(Span span, SkScalar y1) {
|
| SkPoint start;
|
| SkScalar length;
|
| int count;
|
| std::tie(start, length, count) = span;
|
| SkScalar x = X(start);
|
| SkScalar y = Y(start);
|
| +
|
| // In this sampler, it is assumed that if span.StartY() and y1 are the same then both
|
| // y-lines are on the same tile.
|
| if (y == y1) {
|
| // Both y-lines are on the same tile.
|
| - struct BilerpWrapper {
|
| - void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) {
|
| - fSampler.bilerpListFew(n, xs, ys);
|
| - }
|
| -
|
| - void VECTORCALL pointList4(Sk4s xs, Sk4s ys) {
|
| - fSampler.bilerpList4(xs, ys);
|
| - }
|
| -
|
| - GeneralSampler& fSampler;
|
| - };
|
| - BilerpWrapper wrapper{*this};
|
| - span_fallback(span, &wrapper);
|
| + span_fallback(span, this);
|
| } else {
|
| // The y-lines are on different tiles.
|
| SkScalar dx = length / (count - 1);
|
|
|