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); |