From: herb Date: Tue, 1 Mar 2016 23:18:52 +0000 (-0800) Subject: Introduce bilerp spans X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~129^2~1710 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1ef8972ee15899996c4a8b208c471a94cce8dd1c;p=platform%2Fupstream%2FlibSkiaSharp.git Introduce bilerp spans BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1751943002 Review URL: https://codereview.chromium.org/1751943002 --- diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp index 236f5bf..4ab0b90 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() { + 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 +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 + 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 + 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;