Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Unified Diff: src/core/SkLinearBitmapPipeline.cpp

Issue 1719333002: tile spans (Closed) Base URL: https://skia.googlesource.com/skia.git@code-organization-speed
Patch Set: Handle -dx. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gm/SkLinearBitmapPipelineGM.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkLinearBitmapPipeline.cpp
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp
index 02a4bd39f3df869a5d6a75284da472bb636646e2..b9a987b45f7d66960a9e1ac597c43cb577352ae6 100644
--- a/src/core/SkLinearBitmapPipeline.cpp
+++ b/src/core/SkLinearBitmapPipeline.cpp
@@ -15,19 +15,19 @@
#include "SkSize.h"
// Tweak ABI of functions that pass Sk4f by value to pass them via registers.
-#if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
+ #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
#define VECTORCALL __vectorcall
- #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON)
+ #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON)
#define VECTORCALL __attribute__((pcs("aapcs-vfp")))
- #else
+ #else
#define VECTORCALL
- #endif
+ #endif
class SkLinearBitmapPipeline::PointProcessorInterface {
public:
virtual ~PointProcessorInterface() { }
- virtual void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) = 0;
- virtual void VECTORCALL pointList4(Sk4f xs, Sk4f ys) = 0;
+ virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0;
+ virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0;
// The pointSpan method efficiently process horizontal spans of pixels.
// * start - the point where to start the span.
@@ -58,7 +58,7 @@ public:
// +--------+--------+
// These pixels coordinates are arranged in the following order in xs and ys:
// px00 px10 px01 px11
- virtual void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) = 0;
+ virtual void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) = 0;
};
class SkLinearBitmapPipeline::PixelPlacerInterface {
@@ -76,9 +76,9 @@ struct X {
explicit X(SkPoint pt) : fVal{pt.fX} { }
explicit X(SkSize s) : fVal{s.fWidth} { }
explicit X(SkISize s) : fVal(s.fWidth) { }
- operator float () const {return fVal;}
+ operator SkScalar () const {return fVal;}
private:
- float fVal;
+ SkScalar fVal;
};
struct Y {
@@ -86,28 +86,30 @@ struct Y {
explicit Y(SkPoint pt) : fVal{pt.fY} { }
explicit Y(SkSize s) : fVal{s.fHeight} { }
explicit Y(SkISize s) : fVal(s.fHeight) { }
- operator float () const {return fVal;}
+ operator SkScalar () const {return fVal;}
private:
- float fVal;
+ SkScalar fVal;
};
template <typename Stage>
void span_fallback(SkPoint start, SkScalar length, int count, Stage* stage) {
- // If count == 1 use PointListFew instead.
- SkASSERT(count > 1);
-
- float dx = length / (count - 1);
- Sk4f Xs = Sk4f(X(start)) + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * Sk4f{dx};
- Sk4f Ys{Y(start)};
- Sk4f fourDx = {4.0f * dx};
+ Sk4f xs{X(start)};
+ Sk4f ys{Y(start)};
+ Sk4s fourDx;
+ if (count > 1) {
+ SkScalar dx = length / (count - 1);
+ xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx;
+ // Only used if count is >= 4.
+ fourDx = Sk4f{4.0f * dx};
+ }
while (count >= 4) {
- stage->pointList4(Xs, Ys);
- Xs = Xs + fourDx;
+ stage->pointList4(xs, ys);
+ xs = xs + fourDx;
count -= 4;
}
if (count > 0) {
- stage->pointListFew(count, Xs, Ys);
+ stage->pointListFew(count, xs, ys);
}
}
@@ -132,12 +134,12 @@ public:
: fNext{next}
, fStrategy{std::forward<Args>(args)...}{ }
- void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
+ void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
fStrategy.processPoints(&xs, &ys);
fNext->pointListFew(n, xs, ys);
}
- void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
+ void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
fStrategy.processPoints(&xs, &ys);
fNext->pointList4(xs, ys);
}
@@ -162,17 +164,17 @@ public:
: fNext{next}
, fStrategy{std::forward<Args>(args)...}{ }
- void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
+ void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
fStrategy.processPoints(&xs, &ys);
fNext->pointListFew(n, xs, ys);
}
- void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
+ void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
fStrategy.processPoints(&xs, &ys);
fNext->pointList4(xs, ys);
}
- void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override {
+ void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override {
fStrategy.processPoints(&xs, &ys);
fNext->bilerpList(xs, ys);
}
@@ -189,13 +191,13 @@ private:
};
class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterface {
- void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
+ void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
SkFAIL("Skipped stage.");
}
- void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
+ void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
SkFAIL("Skipped stage.");
}
- void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override {
+ void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override {
SkFAIL("Skipped stage.");
}
void pointSpan(SkPoint start, SkScalar length, int count) override {
@@ -209,7 +211,7 @@ public:
: fXOffset{X(offset)}
, fYOffset{Y(offset)} { }
- void processPoints(Sk4f* xs, Sk4f* ys) {
+ void processPoints(Sk4s* xs, Sk4s* ys) {
*xs = *xs + fXOffset;
*ys = *ys + fYOffset;
}
@@ -221,7 +223,7 @@ public:
}
private:
- const Sk4f fXOffset, fYOffset;
+ const Sk4s fXOffset, fYOffset;
};
template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>;
@@ -231,7 +233,7 @@ public:
ScaleMatrixStrategy(SkVector offset, SkVector scale)
: fXOffset{X(offset)}, fYOffset{Y(offset)}
, fXScale{X(scale)}, fYScale{Y(scale)} { }
- void processPoints(Sk4f* xs, Sk4f* ys) {
+ void processPoints(Sk4s* xs, Sk4s* ys) {
*xs = *xs * fXScale + fXOffset;
*ys = *ys * fYScale + fYOffset;
}
@@ -246,8 +248,8 @@ public:
}
private:
- const Sk4f fXOffset, fYOffset;
- const Sk4f fXScale, fYScale;
+ const Sk4s fXOffset, fYOffset;
+ const Sk4s fXScale, fYScale;
};
template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>;
@@ -258,9 +260,9 @@ public:
: fXOffset{X(offset)}, fYOffset{Y(offset)}
, fXScale{X(scale)}, fYScale{Y(scale)}
, fXSkew{X(skew)}, fYSkew{Y(skew)} { }
- void processPoints(Sk4f* xs, Sk4f* ys) {
- Sk4f newXs = fXScale * *xs + fXSkew * *ys + fXOffset;
- Sk4f newYs = fYSkew * *xs + fYScale * *ys + fYOffset;
+ void processPoints(Sk4s* xs, Sk4s* ys) {
+ Sk4s newXs = fXScale * *xs + fXSkew * *ys + fXOffset;
+ Sk4s newYs = fYSkew * *xs + fYScale * *ys + fYOffset;
*xs = newXs;
*ys = newYs;
@@ -272,9 +274,9 @@ public:
}
private:
- const Sk4f fXOffset, fYOffset;
- const Sk4f fXScale, fYScale;
- const Sk4f fXSkew, fYSkew;
+ const Sk4s fXOffset, fYOffset;
+ const Sk4s fXScale, fYScale;
+ const Sk4s fXSkew, fYSkew;
};
template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>;
@@ -312,24 +314,24 @@ class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac
public:
ExpandBilerp(Next* next) : fNext{next} { }
- void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
+ void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
SkASSERT(0 < n && n < 4);
// px00 px10 px01 px11
- const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f},
+ const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f},
kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f};
- if (n >= 1) fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets);
- if (n >= 2) fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets);
- if (n >= 3) fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets);
+ if (n >= 1) fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYOffsets);
+ if (n >= 2) fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYOffsets);
+ if (n >= 3) fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYOffsets);
}
void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
// px00 px10 px01 px11
const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f},
kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f};
- fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets);
- fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets);
- fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets);
- fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYOffsets);
+ fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYOffsets);
+ fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYOffsets);
+ fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYOffsets);
+ fNext->bilerpList(Sk4s{xs[3]} + kXOffsets, Sk4s{ys[3]} + kYOffsets);
}
void pointSpan(SkPoint start, SkScalar length, int count) override {
@@ -353,6 +355,84 @@ static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter(
}
}
+class Span {
+public:
+ Span(SkPoint start, SkScalar length, int count)
+ : fStart{start}
+ , fLength(length)
+ , fCount{count} {
+ SkASSERT(std::isfinite(length));
+ }
+
+ bool isEmpty() const { return 0 == count(); }
+ int count() const { return fCount; }
+ SkScalar length() const { return fLength; }
+ SkScalar startX() const { return X(fStart); }
+ SkScalar endX() const { return startX() + length(); }
+
+ bool inRange(SkScalar xMin, SkScalar xMax) const {
mtklein 2016/02/25 21:47:41 -> completelyWithin? inRange seems ambiguous abou
herb_g 2016/02/26 04:05:53 Done.
+ SkScalar sMin, sMax;
+ std::tie(sMin, sMax) = std::minmax(startX(), endX());
+ return xMin <= sMin && sMax <= xMax;
+ }
+
+ void offset(SkScalar offsetX) {
+ fStart.offset(offsetX, 0.0f);
+ }
+
+ Span breakAt(SkScalar breakX, SkScalar dx) {
mtklein 2016/02/25 21:47:41 I find the countToBreak() and lengthToBreakAndAdju
herb_g 2016/02/26 04:05:54 Done.
+ SkPoint newStart = fStart;
+
+ int newCount = countToBreak(breakX, dx);
mtklein 2016/02/25 21:47:41 all self calls need this->
herb_g 2016/02/26 04:05:54 Done.
+
+ // The length is one dx less than the count * dx like the example above. There are
mtklein 2016/02/25 21:47:40 this comment doesn't belong here given the code th
herb_g 2016/02/26 04:05:54 Done.
+ // middleCount samples, but dx is advanced one less time to get to the last sample.
+ SkScalar newLength = lengthToBreakAndAdjust(newCount, dx);
+
+ return Span{newStart, newLength, newCount};
+ }
+
+ Span breakAtSingleColor(SkScalar breakX, SkScalar dx) {
mtklein 2016/02/25 21:47:41 I don't understand where colors are getting involv
herb_g 2016/02/26 04:05:54 Changed the way this is done.
+
+ int newCount = countToBreak(breakX, dx);
+
+ lengthToBreakAndAdjust(newCount, dx);
+ return Span{{breakX, Y(fStart)}, 0.0f, newCount};
+ }
+
+ template <typename Next>
+ void nextStage(Next* next) {
+ SkASSERT(next != nullptr);
+ SkASSERT(fCount > 0);
+ next->pointSpan(fStart, fLength, fCount);
mtklein 2016/02/25 21:47:41 why does this function exist? doesn't this sugges
herb_g 2016/02/26 04:05:53 This is still a work in progress. Doing it now.
+ }
+
+private:
+ int countToBreak(SkScalar breakX, SkScalar dx) {
+ SkASSERT(std::isfinite(breakX));
+ SkASSERT(std::isfinite(dx));
+ SkScalar x = X(fStart);
+ // newCount will be at least 1.
+ int newCount = SkScalarFloorToInt((breakX - x) / dx) + 1;
+ SkASSERT(newCount > 0);
+ return newCount;
+ }
+
+ SkScalar lengthToBreakAndAdjust(int count, SkScalar dx) {
+ SkScalar lengthToStart = count * dx;
+ fLength -= lengthToStart;
+ fCount -= count;
+ fStart = {X(fStart) + lengthToStart, Y(fStart)};
+ // The length is one dx less than the count * dx like the example above. There are
mtklein 2016/02/25 21:47:41 there is no example above
herb_g 2016/02/26 04:05:54 Done.
+ // middleCount samples, but dx is advanced one less time to get to the last sample.
+ return lengthToStart - dx;
+ }
+
+ SkPoint fStart;
+ SkScalar fLength;
+ int fCount;
+};
+
class ClampStrategy {
public:
ClampStrategy(X max)
@@ -367,25 +447,128 @@ public:
, fXMax{X(max) - 1.0f}
, fYMax{Y(max) - 1.0f} { }
- void processPoints(Sk4f* xs, Sk4f* ys) {
- *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax);
- *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax);
+ void processPoints(Sk4s* xs, Sk4s* ys) {
+ *xs = Sk4s::Min(Sk4s::Max(*xs, fXMin), fXMax);
+ *ys = Sk4s::Min(Sk4s::Max(*ys, fYMin), fYMax);
}
template <typename Next>
bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
- return false;
+ SkASSERT(count > 0);
+ SkASSERT(std::isfinite(length));
mtklein 2016/02/25 21:47:41 We seem to assert this multiple times, but count >
herb_g 2016/02/26 04:05:54 Acknowledged.
+ SkScalar xMin = fXMin[0];
+ SkScalar xMax = fXMax[0] + 1.0f;
+ SkScalar yMin = fYMin[0];
+ SkScalar yMax = fYMax[0];
+ SkScalar x = X(start);
+ SkScalar y = std::min(std::max<SkScalar>(yMin, Y(start)), yMax);
+
+ Span span{{x, y}, length, count};
+
+ // Handle the Span is on the tile if xMin and xMax not infinities or handle the case where
mtklein 2016/02/25 21:47:40 please make this a sentence or delete it?
herb_g 2016/02/26 04:05:53 Done.
+ // the x component is a pass through when xMin and xMax are infinities.
+ if (span.inRange(xMin, xMax)) {
+ span.nextStage(next);
+ return true;
+ }
+
+ SkScalar dx = length / (count - 1);
+
+ // This is only the case where the count is one and it is in x < xMin || xMax < x,
mtklein 2016/02/25 21:47:41 ...and it it outside [xMin, xMax]? Is it really i
herb_g 2016/02/26 04:05:54 Acknowledged.
+ // otherwise it was handled above.
+ if (1 == count || dx < 0) {
mtklein 2016/02/25 21:47:41 if (count == 1 || length < 0) { return false;
herb_g 2016/02/26 04:05:53 Changed logic
+ return false;
+ }
+
+ // A B C
+ // +-------+-------+-------++-------+-------+-------+ +-------+-------++------
+ // | *---*|---*---|*---*--||-*---*-|---*---|*---...| |--*---*|---*---||*---*....
+ // | | | || | | | ... | | ||
+ // | | | || | | | | | ||
+ // +-------+-------+-------++-------+-------+-------+ +-------+-------++------
+ // ^ ^
+ // | xMin xMax-1 | xMax
+ //
+ // *---*---*---... - track of samples. * = sample
+ //
+ // +-+ ||
+ // | | - pixels in source space. || - tile border.
+ // +-+ ||
+ //
+ // The length from A to B is the length in source space or 4 * dx or (count - 1) * dx
+ // where dx is the distance between samples. There are 5 destination pixels
+ // corresponding to 5 samples specified in the A, B span. The distance from A to the next
+ // span starting at C is 5 * dx, so count * dx.
+ // Remember, count is the number of pixels needed for the destination and the number of
+ // samples.
+ // Overall Strategy:
+ // * Under - for portions of the span < xMin, take the color at pixel {xMin, y} and use it
+ // to fill in the 5 pixel sampled from A to B.
+ // * Middle - for the portion of the span between xMin and xMax sample normally.
+ // * Over - for the portion of the span > xMax, take the color at pixel {xMax-1, y} and
+ // use it to fill in the rest of the destination pixels.
+
+ if (dx > 0) {
+ if (span.startX() < xMin) {
+ if (span.endX() > xMin) {
+ Span toDraw = span.breakAtSingleColor(xMin, dx);
mtklein 2016/02/25 21:47:40 This breakAtSingleColor seems like something Span
mtklein 2016/02/25 21:47:41 We're not drawing anything here...
herb_g 2016/02/26 04:05:54 Totally redid logic.
+ toDraw.nextStage(next);
+ } else {
+ span.nextStage(next);
mtklein 2016/02/25 21:47:41 I don't think I follow this case. It's entirely o
herb_g 2016/02/26 04:05:54 Redid logic
+ return true;
+ }
+ }
+ if (!span.isEmpty() && span.startX() < xMax) {
mtklein 2016/02/25 21:47:40 All these if cases are really complicated. Seems
herb_g 2016/02/26 04:05:53 Done.
+ if (span.endX() > xMax) {
+ Span toDraw = span.breakAt(xMax, dx);
+ toDraw.nextStage(next);
+ } else {
+ span.nextStage(next);
+ return true;
+ };
+ }
+ if (!span.isEmpty()) {
+ next->pointSpan({xMax - 1.0f, y}, 0.0f, span.count());
+ }
+ } else {
mtklein 2016/02/25 21:47:41 How did we get dx == 0 here? Some sort of degener
herb_g 2016/02/26 04:05:54 Done.
+ if (span.startX() > xMax) {
+ if (span.endX() < xMax) {
+ Span toDraw = span.breakAtSingleColor(xMax - 1.0f, dx);
+ toDraw.nextStage(next);
+ } else {
+ span.nextStage(next);
+ return true;
+ }
+ }
+ if (!span.isEmpty() && span.startX() > xMin) {
+ if (span.endX() < xMin) {
+ Span toDraw = span.breakAt(xMin, dx);
+ toDraw.nextStage(next);
+ } else {
+ span.nextStage(next);
+ return true;
+ }
+ }
+ if (!span.isEmpty()) {
+ next->pointSpan({xMin, y}, 0.0f, span.count());
+ }
+ }
+ return true;
}
private:
- const Sk4f fXMin{SK_FloatNegativeInfinity};
- const Sk4f fYMin{SK_FloatNegativeInfinity};
- const Sk4f fXMax{SK_FloatInfinity};
- const Sk4f fYMax{SK_FloatInfinity};
+ const Sk4s fXMin{SK_FloatNegativeInfinity};
+ const Sk4s fYMin{SK_FloatNegativeInfinity};
+ const Sk4s fXMax{SK_FloatInfinity};
+ const Sk4s fYMax{SK_FloatInfinity};
};
template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
using Clamp = BilerpProcessor<ClampStrategy, Next>;
+static SkScalar tile_mod(SkScalar x, SkScalar base) {
+ return x - std::floor(x / base) * base;
+}
+
class RepeatStrategy {
public:
RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { }
@@ -396,25 +579,89 @@ public:
, fYMax{Y(max)}
, fYInvMax{1.0f / Y(max)} { }
- void processPoints(Sk4f* xs, Sk4f* ys) {
- Sk4f divX = (*xs * fXInvMax).floor();
- Sk4f divY = (*ys * fYInvMax).floor();
- Sk4f baseX = (divX * fXMax);
- Sk4f baseY = (divY * fYMax);
+ void processPoints(Sk4s* xs, Sk4s* ys) {
+ Sk4s divX = (*xs * fXInvMax).floor();
+ Sk4s divY = (*ys * fYInvMax).floor();
+ Sk4s baseX = (divX * fXMax);
+ Sk4s baseY = (divY * fYMax);
*xs = *xs - baseX;
*ys = *ys - baseY;
}
template <typename Next>
bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
- return false;
+ SkASSERT(count > 0);
+ SkASSERT(std::isfinite(length));
+ // Make x and y in range on the tile.
+ SkScalar x = tile_mod(X(start), fXMax[0]);
+ SkScalar y = tile_mod(Y(start), fYMax[0]);
+ SkScalar xMax = fXMax[0];
+ SkScalar xMin = 0.0f;
+ SkScalar dx = length / (count - 1);
+
+ if (SkScalarAbs(dx) >= xMax) {
+ return false;
+ }
+
+ // A B C D Z
+ // +-------+-------+-------++-------+-------+-------++ +-------+-------++------
+ // | | *---|*---*--||-*---*-|---*---|*---*--|| |--*---*| ||
+ // | | | || | | || ... | | ||
+ // | | | || | | || | | ||
+ // +-------+-------+-------++-------+-------+-------++ +-------+-------++------
+ // ^^ ^^ ^^
+ // xMax || xMin xMax || xMin xMax || xMin
+ //
+ // *---*---*---... - track of samples. * = sample
+ //
+ // +-+ ||
+ // | | - pixels in source space. || - tile border.
+ // +-+ ||
+ //
+ //
+ // The given span starts at A and continues on through several tiles to sample point Z.
+ // The idea is to break this into several spans one on each tile the entire span
+ // intersects. The A to B span only covers a partial tile and has a count of 3 and the
+ // distance from A to B is (count - 1) * dx or 2 * dx. The distance from A to the start of
+ // the next span is count * dx or 3 * dx. Span C to D covers an entire tile has a count
+ // of 5 and a length of 4 * dx. Remember, count is the number of pixels needed for the
+ // destination and the number of samples.
+ //
+ // Overall Strategy:
+ // While the span hangs over the edge of the tile, draw the span covering the tile then
+ // slide the span over to the next tile.
+
+ // The guard could have been count > 0, but then a bunch of math would be done in the
+ // common case.
+
+ Span span{{x, y}, length, count};
+ if (dx > 0) {
+ while (!span.isEmpty() && span.endX() > xMax) {
+ Span toDraw = span.breakAt(xMax, dx);
+ toDraw.nextStage(next);
+ span.offset(-xMax);
+ }
+ } else {
+ while (!span.isEmpty() && span.endX() < xMin) {
+ Span toDraw = span.breakAt(xMin, dx);
+ toDraw.nextStage(next);
+ span.offset(xMax);
+ }
+ }
+
+ // All on a single tile.
+ if (!span.isEmpty()) {
+ span.nextStage(next);
+ }
+
+ return true;
}
private:
- const Sk4f fXMax{0.0f};
- const Sk4f fXInvMax{0.0f};
- const Sk4f fYMax{0.0f};
- const Sk4f fYInvMax{0.0f};
+ const Sk4s fXMax{0.0f};
+ const Sk4s fXInvMax{0.0f};
+ const Sk4s fYMax{0.0f};
+ const Sk4s fYInvMax{0.0f};
};
template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
@@ -469,9 +716,9 @@ static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler(
class sRGBFast {
public:
- static Sk4f VECTORCALL sRGBToLinear(Sk4f pixel) {
- Sk4f l = pixel * pixel;
- return Sk4f{l[0], l[1], l[2], pixel[3]};
+ static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) {
+ Sk4s l = pixel * pixel;
+ return Sk4s{l[0], l[1], l[2], pixel[3]};
}
};
@@ -481,9 +728,9 @@ public:
Passthrough8888(int width, const uint32_t* src)
: fSrc{src}, fWidth{width}{ }
- void VECTORCALL getFewPixels(int n, Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) {
- Sk4i XIs = SkNx_cast<int, float>(xs);
- Sk4i YIs = SkNx_cast<int, float>(ys);
+ void VECTORCALL getFewPixels(int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) {
+ Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
+ Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
Sk4i bufferLoc = YIs * fWidth + XIs;
switch (n) {
case 3:
@@ -497,9 +744,9 @@ public:
}
}
- void VECTORCALL get4Pixels(Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) {
- Sk4i XIs = SkNx_cast<int, float>(xs);
- Sk4i YIs = SkNx_cast<int, float>(ys);
+ void VECTORCALL get4Pixels(Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) {
+ Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
+ Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
Sk4i bufferLoc = YIs * fWidth + XIs;
*px0 = getPixel(fSrc, bufferLoc[0]);
*px1 = getPixel(fSrc, bufferLoc[1]);
@@ -543,12 +790,12 @@ private:
// * px01 -> (1 - x)y = y - xy
// * px11 -> xy
// So x * y is calculated first and then used to calculate all the other factors.
-static Sk4f VECTORCALL bilerp4(Sk4f xs, Sk4f ys, Sk4f px00, Sk4f px10,
+static Sk4s VECTORCALL bilerp4(Sk4s xs, Sk4s ys, Sk4f px00, Sk4f px10,
Sk4f px01, Sk4f px11) {
// Calculate fractional xs and ys.
- Sk4f fxs = xs - xs.floor();
- Sk4f fys = ys - ys.floor();
- Sk4f fxys{fxs * fys};
+ Sk4s fxs = xs - xs.floor();
+ Sk4s fys = ys - ys.floor();
+ Sk4s fxys{fxs * fys};
Sk4f sum = px11 * fxys;
sum = sum + px01 * (fys - fxys);
sum = sum + px10 * (fxs - fxys);
@@ -564,7 +811,7 @@ public:
: fNext{next}
, fStrategy{std::forward<Args>(args)...} { }
- void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
+ 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);
@@ -573,13 +820,13 @@ public:
if (n >= 3) fNext->placePixel(px2);
}
- void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
+ void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
Sk4f px0, px1, px2, px3;
fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
fNext->place4Pixels(px0, px1, px2, px3);
}
- void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override {
+ void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override {
Sk4f px00, px10, px01, px11;
fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11);
Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11);
@@ -697,14 +944,9 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline(
void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
SkASSERT(count > 0);
fPixelStage->setDestination(dst);
- // Adjust points by 0.5, 0.5 to sample from the center of the pixels.
- if (count == 1) {
- fFirstStage->pointListFew(1, Sk4f{x + 0.5f}, Sk4f{y + 0.5f});
- } else {
- // The count and length arguments start out in a precise relation in order to keep the
- // math correct through the different stages. Count is the number of pixel to produce.
- // Since the code samples at pixel centers, length is the distance from the center of the
- // first pixel to the center of the last pixel. This implies that length is count-1.
- fFirstStage->pointSpan(SkPoint{x + 0.5f, y + 0.5f}, count - 1, count);
- }
+ // The count and length arguments start out in a precise relation in order to keep the
+ // math correct through the different stages. Count is the number of pixel to produce.
+ // Since the code samples at pixel centers, length is the distance from the center of the
+ // first pixel to the center of the last pixel. This implies that length is count-1.
+ fFirstStage->pointSpan(SkPoint{x + 0.5f, y + 0.5f}, count - 1, count);
}
« no previous file with comments | « gm/SkLinearBitmapPipelineGM.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698