Chromium Code Reviews| Index: src/core/SkLinearBitmapPipeline_tile.h |
| diff --git a/src/core/SkLinearBitmapPipeline_tile.h b/src/core/SkLinearBitmapPipeline_tile.h |
| index 60cc2a5ef09acb8eb01f4f71d1f5608ebe0484f3..f407ad5d16dbdf7a7f43b775240b4a214ed7129f 100644 |
| --- a/src/core/SkLinearBitmapPipeline_tile.h |
| +++ b/src/core/SkLinearBitmapPipeline_tile.h |
| @@ -234,6 +234,95 @@ private: |
| const Sk4s fXsInvMax; |
| }; |
| +// The XRepeatUnitScaleStrategy exploits the situation where dx = 1.0. The main advantage is that |
| +// the relationship between the sample points and the source pixels does not change from tile to |
| +// repeated tile. This allows the tiler to calculate the span once and re-use it for each |
| +// repeated tile. This is later exploited by some samplers to avoid converting pixels to linear |
| +// space allowing the use of memmove to place pixel in the destination. |
| +class XRepeatUnitScaleStrategy { |
| +public: |
| + XRepeatUnitScaleStrategy(int32_t max) |
| + : fXMax{SkScalar(max)} |
| + , fXsMax{SkScalar(max)} |
| + , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))} |
| + , fXsInvMax{1.0f / SkScalar(max)} { } |
| + |
| + void tileXPoints(Sk4s* xs) { |
| + Sk4s divX = *xs * fXsInvMax; |
| + Sk4s modX = *xs - divX.floor() * fXsMax; |
| + *xs = Sk4s::Min(fXsCap, modX); |
| + SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax); |
| + SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax); |
| + SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax); |
| + SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax); |
| + } |
| + |
| + template<typename Next> |
| + bool maybeProcessSpan(Span originalSpan, Next* next) { |
| + SkASSERT(!originalSpan.isEmpty()); |
| + SkPoint start; SkScalar length; int count; |
| + std::tie(start, length, count) = originalSpan; |
| + // Make x and y in range on the tile. |
| + SkScalar x = tile_mod(X(start), fXMax); |
| + SkScalar y = Y(start); |
| + |
| + // No need trying to go fast because the steps are larger than a tile or there is one point. |
| + if (fXMax == 1 || count <= 1) { |
| + return false; |
| + } |
| + |
| + // x should be on the tile. |
| + SkASSERT(0.0f <= x && x < fXMax); |
| + Span span({x, y}, length, count); |
| + |
| + if (SkScalarFloorToScalar(x) != 0.0f) { |
| + Span toDraw = span.breakAt(fXMax, 1.0f); |
| + SkASSERT(0.0f <= toDraw.startX() && toDraw.endX() < fXMax); |
| + next->pointSpan(toDraw); |
| + span.offset(-fXMax); |
| + } |
| + |
| + // All of the span could have been on the first tile. If so, then no work to do. |
| + if (span.isEmpty()) return true; |
| + |
| + // At this point the span should be aligned to zero. |
| + SkASSERT(SkScalarFloorToScalar(span.startX()) == 0.0f); |
| + |
| + // At this point the span should be aligned to zero. |
| + SkASSERT(SkScalarFloorToScalar(span.startX()) == 0.0f); |
|
f(malita)
2016/04/07 00:56:45
Nit: double-paste?
herb_g
2016/04/07 14:37:03
Done.
|
| + |
| + // Note: The span length has an unintuitive relation to the tile width. The tile width is |
| + // a half open interval [tb, te), but the span is a closed interval [sb, se]. In order to |
| + // compare the two, you need to convert the span to a half open interval. This is done by |
| + // adding dx to se. So, the span becomes: [sb, se + dx). Hence the + 1.0f below. |
| + SkScalar div = (span.length() + 1.0f) / fXMax; |
| + int32_t repeatCount = SkScalarFloorToInt(div); |
| + Span repeatableSpan{{0.0f, y}, fXMax - 1.0f, SkScalarFloorToInt(fXMax)}; |
| + |
| + // Repeat the center section. |
| + SkASSERT(0.0f <= repeatableSpan.startX() && repeatableSpan.endX() < fXMax); |
| + next->repeatSpan(repeatableSpan, repeatCount); |
| + |
| + // There may be some of the span left over. |
| + span.breakAt(SkScalar(repeatCount) * fXMax, 1.0f); |
| + |
| + // All on a single tile. |
| + if (!span.isEmpty()) { |
| + span.offset(-fXMax * SkScalar(repeatCount)); |
|
f(malita)
2016/04/07 00:56:45
Nit: maybe use a const SkScalar advance = fXMax *
herb_g
2016/04/07 14:37:03
Done.
|
| + SkASSERT(0.0f <= span.startX() && span.endX() < fXMax); |
| + next->pointSpan(span); |
| + } |
| + |
| + return true; |
| + } |
| + |
| +private: |
| + const SkScalar fXMax; |
| + const Sk4s fXsMax; |
| + const Sk4s fXsCap; |
| + const Sk4s fXsInvMax; |
| +}; |
| + |
| class YRepeatStrategy { |
| public: |
| YRepeatStrategy(int32_t max) |