diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h index f21e3d6adc..624034851d 100644 --- a/src/core/SkBitmapProcShader.h +++ b/src/core/SkBitmapProcShader.h @@ -54,7 +54,7 @@ private: typedef SkShader INHERITED; }; -enum {kSkBlitterContextSize = 3200}; +enum {kSkBlitterContextSize = 3332}; // Commonly used allocator. It currently is only used to allocate up to 3 objects. The total // bytes requested is calculated using one of our large shaders, its context size plus the size of diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp index 088e829345..44a3d77195 100644 --- a/src/core/SkLinearBitmapPipeline.cpp +++ b/src/core/SkLinearBitmapPipeline.cpp @@ -165,15 +165,14 @@ static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( // Tile Stage template -class NearestTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface { +class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface { public: - template - NearestTileStage(Next* next, SkISize dimensions) + CombinedTileStage(Next* next, SkISize dimensions) : fNext{next} , fXStrategy{dimensions.width()} , fYStrategy{dimensions.height()}{ } - NearestTileStage(Next* next, const NearestTileStage& stage) + CombinedTileStage(Next* next, const CombinedTileStage& stage) : fNext{next} , fXStrategy{stage.fXStrategy} , fYStrategy{stage.fYStrategy} { } @@ -195,9 +194,20 @@ public: SkASSERT(!span.isEmpty()); SkPoint start; SkScalar length; int count; std::tie(start, length, count) = span; + + if (span.count() == 1) { + // DANGER: + // The explicit casts from float to Sk4f are not usually necessary, but are here to + // work around an MSVC 2015u2 c++ code generation bug. This is tracked using skia bug + // 5566. + this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()}); + return; + } + SkScalar x = X(start); SkScalar y = fYStrategy.tileY(Y(start)); Span yAdjustedSpan{{x, y}, length, count}; + if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) { span_fallback(span, this); } @@ -209,173 +219,27 @@ private: YStrategy fYStrategy; }; -template -class BilerpTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface { -public: - template - BilerpTileStage(Next* next, SkISize dimensions) - : fNext{next} - , fXMax(dimensions.width()) - , fYMax(dimensions.height()) - , fXStrategy{dimensions.width()} - , fYStrategy{dimensions.height()} { } - - BilerpTileStage(Next* next, const BilerpTileStage& stage) - : fNext{next} - , fXMax{stage.fXMax} - , fYMax{stage.fYMax} - , fXStrategy{stage.fXStrategy} - , fYStrategy{stage.fYStrategy} { } - - void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { - fXStrategy.tileXPoints(&xs); - fYStrategy.tileYPoints(&ys); - // TODO: check to see if xs and ys are in range then just call pointListFew on next. - if (n >= 1) this->bilerpPoint(xs[0], ys[0]); - if (n >= 2) this->bilerpPoint(xs[1], ys[1]); - if (n >= 3) this->bilerpPoint(xs[2], ys[2]); - } - - void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { - fXStrategy.tileXPoints(&xs); - fYStrategy.tileYPoints(&ys); - // TODO: check to see if xs and ys are in range then just call pointList4 on next. - this->bilerpPoint(xs[0], ys[0]); - this->bilerpPoint(xs[1], ys[1]); - this->bilerpPoint(xs[2], ys[2]); - this->bilerpPoint(xs[3], ys[3]); - } - - struct Wrapper { - void pointSpan(Span span) { - processor->breakIntoEdges(span); - } - - void repeatSpan(Span span, int32_t repeatCount) { - while (repeatCount --> 0) { - processor->pointSpan(span); - } - } - - BilerpTileStage* processor; - }; - - // The span you pass must not be empty. - void pointSpan(Span span) override { - SkASSERT(!span.isEmpty()); - - Wrapper wrapper = {this}; - if (!fXStrategy.maybeProcessSpan(span, &wrapper)) { - span_fallback(span, this); - } - } - -private: - void bilerpPoint(SkScalar x, SkScalar y) { - Sk4f txs = Sk4f{x} + Sk4f{-0.5f, 0.5f, -0.5f, 0.5f}; - Sk4f tys = Sk4f{y} + Sk4f{-0.5f, -0.5f, 0.5f, 0.5f}; - fXStrategy.tileXPoints(&txs); - fYStrategy.tileYPoints(&tys); - fNext->bilerpEdge(txs, tys); - } - - void handleEdges(Span span, SkScalar dx) { - SkPoint start; SkScalar length; int count; - std::tie(start, length, count) = span; - SkScalar x = X(start); - SkScalar y = Y(start); - SkScalar tiledY = fYStrategy.tileY(y); - while (count > 0) { - this->bilerpPoint(x, tiledY); - x += dx; - count -= 1; - } - } - - void yProcessSpan(Span span) { - SkScalar tiledY = fYStrategy.tileY(span.startY()); - if (0.5f <= tiledY && tiledY < fYMax - 0.5f ) { - Span tiledSpan{{span.startX(), tiledY}, span.length(), span.count()}; - fNext->pointSpan(tiledSpan); - } else { - // Convert to the Y0 bilerp sample set by shifting by -0.5f. Then tile that new y - // value and shift it back resulting in the working Y0. Do the same thing with Y1 but - // in the opposite direction. - SkScalar y0 = fYStrategy.tileY(span.startY() - 0.5f) + 0.5f; - SkScalar y1 = fYStrategy.tileY(span.startY() + 0.5f) - 0.5f; - Span newSpan{{span.startX(), y0}, span.length(), span.count()}; - fNext->bilerpSpan(newSpan, y1); - } - } - void breakIntoEdges(Span span) { - if (span.count() == 1) { - this->bilerpPoint(span.startX(), span.startY()); - } else if (span.length() == 0) { - yProcessSpan(span); - } else { - SkScalar dx = span.length() / (span.count() - 1); - if (span.length() > 0) { - Span leftBorder = span.breakAt(0.5f, dx); - if (!leftBorder.isEmpty()) { - this->handleEdges(leftBorder, dx); - } - Span center = span.breakAt(fXMax - 0.5f, dx); - if (!center.isEmpty()) { - this->yProcessSpan(center); - } - - if (!span.isEmpty()) { - this->handleEdges(span, dx); - } - } else { - Span center = span.breakAt(fXMax + 0.5f, dx); - if (!span.isEmpty()) { - this->handleEdges(span, dx); - } - Span leftEdge = center.breakAt(0.5f, dx); - if (!center.isEmpty()) { - this->yProcessSpan(center); - } - if (!leftEdge.isEmpty()) { - this->handleEdges(leftEdge, dx); - } - - } - } - } - - Next* const fNext; - SkScalar fXMax; - SkScalar fYMax; - XStrategy fXStrategy; - YStrategy fYStrategy; -}; - -template -void make_tile_stage( - SkFilterQuality filterQuality, SkISize dimensions, - Next* next, SkLinearBitmapPipeline::TileStage* tileStage) { - if (filterQuality == kNone_SkFilterQuality) { - tileStage->initStage>(next, dimensions); - } else { - tileStage->initStage>(next, dimensions); - } -} -template +template void choose_tiler_ymode( SkShader::TileMode yMode, SkFilterQuality filterQuality, SkISize dimensions, - SkLinearBitmapPipeline::SampleProcessorInterface* next, + Next* next, SkLinearBitmapPipeline::TileStage* tileStage) { switch (yMode) { - case SkShader::kClamp_TileMode: - make_tile_stage(filterQuality, dimensions, next, tileStage); + case SkShader::kClamp_TileMode: { + using Tiler = CombinedTileStage; + tileStage->initStage(next, dimensions); break; - case SkShader::kRepeat_TileMode: - make_tile_stage(filterQuality, dimensions, next, tileStage); + } + case SkShader::kRepeat_TileMode: { + using Tiler = CombinedTileStage; + tileStage->initStage(next, dimensions); break; - case SkShader::kMirror_TileMode: - make_tile_stage(filterQuality, dimensions, next, tileStage); + } + case SkShader::kMirror_TileMode: { + using Tiler = CombinedTileStage; + tileStage->initStage(next, dimensions); break; + } } }; @@ -467,10 +331,6 @@ public: fDest = dest; } - void SK_VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override { SkFAIL("Not Implemented"); } - - void bilerpSpan(Span span, SkScalar y) override { SkFAIL("Not Implemented"); } - void setDestination(void* dst, int count) override { fDest = static_cast(dst); fEnd = fDest + count; @@ -538,10 +398,6 @@ public: SkASSERT(fDest <= fEnd); } - void SK_VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override { SkFAIL("Not Implemented"); } - - void bilerpSpan(Span span, SkScalar y) override { SkFAIL("Not Implemented"); } - void setDestination(void* dst, int count) override { SkASSERT(count > 0); fDest = static_cast(dst); @@ -582,12 +438,9 @@ static SkLinearBitmapPipeline::PixelAccessorInterface* choose_specific_accessor( } } -template