Index: src/core/SkLinearBitmapPipeline.cpp |
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp |
index e836746a891ff740d74d7422f08336cff16c214a..236f5bf8768712e13a19096d9b1fd55148229827 100644 |
--- a/src/core/SkLinearBitmapPipeline.cpp |
+++ b/src/core/SkLinearBitmapPipeline.cpp |
@@ -745,7 +745,16 @@ public: |
*px3 = this->getPixel(fSrc, bufferLoc[3]); |
} |
- Sk4f getPixel(const uint32_t* src, int index) { |
+ void get4Pixels(const void* vsrc, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) { |
+ const uint32_t* src = static_cast<const uint32_t*>(vsrc); |
+ *px0 = this->getPixel(src, index + 0); |
+ *px1 = this->getPixel(src, index + 1); |
+ *px2 = this->getPixel(src, index + 2); |
+ *px3 = this->getPixel(src, index + 3); |
+ } |
+ |
+ Sk4f getPixel(const void* vsrc, int index) { |
+ const uint32_t* src = static_cast<const uint32_t*>(vsrc); |
Sk4b bytePixel = Sk4b::Load((uint8_t *)(&src[index])); |
Sk4f pixel = SkNx_cast<float, uint8_t>(bytePixel); |
if (colorOrder == ColorOrder::kBGRA) { |
@@ -829,6 +838,89 @@ public: |
} |
void pointSpan(Span span) override { |
+ SkASSERT(!span.isEmpty()); |
+ SkPoint start; SkScalar length; int count; |
+ std::tie(start, length, count) = span; |
+ if (length < (count - 1)) { |
+ this->pointSpanSlowRate(span); |
+ } else if (length == (count - 1)) { |
+ this->pointSpanUnitRate(span); |
+ } else { |
+ this->pointSpanFastRate(span); |
+ } |
+ } |
+ |
+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 pointSpanSlowRate(Span span) { |
+ SkPoint start; SkScalar length; int count; |
+ std::tie(start, length, count) = span; |
+ SkScalar x = X(start); |
+ SkFixed fx = SkScalarToFixed(x); |
+ SkScalar dx = length / (count - 1); |
+ SkFixed fdx = SkScalarToFixed(dx); |
+ |
+ const void* row = fStrategy.row((int)std::floor(Y(start))); |
+ SkLinearBitmapPipeline::PixelPlacerInterface* next = fNext; |
+ |
+ int ix = SkFixedFloorToInt(fx); |
+ int prevIX = ix; |
+ Sk4f fpixel = fStrategy.getPixel(row, ix); |
+ |
+ // When dx is less than one, each pixel is used more than once. Using the fixed point fx |
+ // allows the code to quickly check that the same pixel is being used. The code uses this |
+ // same pixel check to do the sRGB and normalization only once. |
+ auto getNextPixel = [&]() { |
+ if (ix != prevIX) { |
+ fpixel = fStrategy.getPixel(row, ix); |
+ prevIX = ix; |
+ } |
+ fx += fdx; |
+ ix = SkFixedFloorToInt(fx); |
+ return fpixel; |
+ }; |
+ |
+ while (count >= 4) { |
+ Sk4f px0 = getNextPixel(); |
+ Sk4f px1 = getNextPixel(); |
+ Sk4f px2 = getNextPixel(); |
+ Sk4f px3 = getNextPixel(); |
+ next->place4Pixels(px0, px1, px2, px3); |
+ count -= 4; |
+ } |
+ while (count > 0) { |
+ next->placePixel(getNextPixel()); |
+ count -= 1; |
+ } |
+ } |
+ |
+ // 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 pointSpanUnitRate(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))); |
+ SkLinearBitmapPipeline::PixelPlacerInterface* next = fNext; |
+ while (count >= 4) { |
+ Sk4f px0, px1, px2, px3; |
+ fStrategy.get4Pixels(row, ix, &px0, &px1, &px2, &px3); |
+ next->place4Pixels(px0, px1, px2, px3); |
+ ix += 4; |
+ count -= 4; |
+ } |
+ |
+ while (count > 0) { |
+ next->placePixel(fStrategy.getPixel(row, ix)); |
+ ix += 1; |
+ count -= 1; |
+ } |
+ } |
+ |
+ // 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 pointSpanFastRate(Span span) { |
span_fallback(span, this); |
} |