| Index: src/core/SkLinearBitmapPipeline.cpp
|
| diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp
|
| index 088e829345f016f3b06a84dc83cdef2f13dcbef2..44a3d77195ef8855130c0775670c76e40e501f11 100644
|
| --- a/src/core/SkLinearBitmapPipeline.cpp
|
| +++ b/src/core/SkLinearBitmapPipeline.cpp
|
| @@ -165,15 +165,14 @@ static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix(
|
| // Tile Stage
|
|
|
| template<typename XStrategy, typename YStrategy, typename Next>
|
| -class NearestTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
|
| +class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
|
| public:
|
| - template <typename... Args>
|
| - 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,187 +194,52 @@ public:
|
| SkASSERT(!span.isEmpty());
|
| SkPoint start; SkScalar length; int count;
|
| std::tie(start, length, count) = span;
|
| - 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);
|
| - }
|
| - }
|
| -
|
| -private:
|
| - Next* const fNext;
|
| - XStrategy fXStrategy;
|
| - YStrategy fYStrategy;
|
| -};
|
| -
|
| -template<typename XStrategy, typename YStrategy, typename Next>
|
| -class BilerpTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
|
| -public:
|
| - template <typename... Args>
|
| - 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);
|
| - }
|
| + 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;
|
| }
|
|
|
| - BilerpTileStage* processor;
|
| - };
|
| -
|
| - // The span you pass must not be empty.
|
| - void pointSpan(Span span) override {
|
| - SkASSERT(!span.isEmpty());
|
| + SkScalar x = X(start);
|
| + SkScalar y = fYStrategy.tileY(Y(start));
|
| + Span yAdjustedSpan{{x, y}, length, count};
|
|
|
| - Wrapper wrapper = {this};
|
| - if (!fXStrategy.maybeProcessSpan(span, &wrapper)) {
|
| + if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
|
| 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 <typename XStrategy, typename YStrategy, typename Next>
|
| -void make_tile_stage(
|
| - SkFilterQuality filterQuality, SkISize dimensions,
|
| - Next* next, SkLinearBitmapPipeline::TileStage* tileStage) {
|
| - if (filterQuality == kNone_SkFilterQuality) {
|
| - tileStage->initStage<NearestTileStage<XStrategy, YStrategy, Next>>(next, dimensions);
|
| - } else {
|
| - tileStage->initStage<BilerpTileStage<XStrategy, YStrategy, Next>>(next, dimensions);
|
| - }
|
| -}
|
| -template <typename XStrategy>
|
| +template <typename XStrategy, typename Next>
|
| 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<XStrategy, YClampStrategy>(filterQuality, dimensions, next, tileStage);
|
| + case SkShader::kClamp_TileMode: {
|
| + using Tiler = CombinedTileStage<XStrategy, YClampStrategy, Next>;
|
| + tileStage->initStage<Tiler>(next, dimensions);
|
| break;
|
| - case SkShader::kRepeat_TileMode:
|
| - make_tile_stage<XStrategy, YRepeatStrategy>(filterQuality, dimensions, next, tileStage);
|
| + }
|
| + case SkShader::kRepeat_TileMode: {
|
| + using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, Next>;
|
| + tileStage->initStage<Tiler>(next, dimensions);
|
| break;
|
| - case SkShader::kMirror_TileMode:
|
| - make_tile_stage<XStrategy, YMirrorStrategy>(filterQuality, dimensions, next, tileStage);
|
| + }
|
| + case SkShader::kMirror_TileMode: {
|
| + using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, Next>;
|
| + tileStage->initStage<Tiler>(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<uint32_t*>(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<uint32_t*>(dst);
|
| @@ -582,12 +438,9 @@ static SkLinearBitmapPipeline::PixelAccessorInterface* choose_specific_accessor(
|
| }
|
| }
|
|
|
| -template<template <typename, typename> class Sampler>
|
| -static SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler_base(
|
| - Blender* next,
|
| +static SkLinearBitmapPipeline::PixelAccessorInterface* choose_pixel_accessor(
|
| const SkPixmap& srcPixmap,
|
| const SkColor A8TintColor,
|
| - SkLinearBitmapPipeline::SampleStage* sampleStage,
|
| SkLinearBitmapPipeline::Accessor* accessor)
|
| {
|
| const SkImageInfo& imageInfo = srcPixmap.info();
|
| @@ -629,19 +482,19 @@ static SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler_ba
|
| break;
|
| }
|
|
|
| - using S = Sampler<PixelAccessorShim, Blender>;
|
| - sampleStage->initStage<S>(next, pixelAccessor);
|
| - return sampleStage->get();
|
| + return pixelAccessor;
|
| }
|
|
|
| SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler(
|
| Blender* next,
|
| SkFilterQuality filterQuality,
|
| + SkShader::TileMode xTile, SkShader::TileMode yTile,
|
| const SkPixmap& srcPixmap,
|
| const SkColor A8TintColor,
|
| SkLinearBitmapPipeline::SampleStage* sampleStage,
|
| SkLinearBitmapPipeline::Accessor* accessor) {
|
| const SkImageInfo& imageInfo = srcPixmap.info();
|
| + SkISize dimensions = imageInfo.dimensions();
|
|
|
| // Special case samplers with fully expanded templates
|
| if (imageInfo.gammaCloseToSRGB()) {
|
| @@ -670,14 +523,14 @@ SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler(
|
| using S =
|
| BilerpSampler<
|
| PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
|
| - sampleStage->initStage<S>(next, srcPixmap);
|
| + sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
|
| return sampleStage->get();
|
| }
|
| case kIndex_8_SkColorType: {
|
| using S =
|
| BilerpSampler<
|
| PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
|
| - sampleStage->initStage<S>(next, srcPixmap);
|
| + sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
|
| return sampleStage->get();
|
| }
|
| default:
|
| @@ -686,14 +539,16 @@ SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler(
|
| }
|
| }
|
|
|
| + auto pixelAccessor = choose_pixel_accessor(srcPixmap, A8TintColor, accessor);
|
| // General cases.
|
| if (filterQuality == kNone_SkFilterQuality) {
|
| - return choose_pixel_sampler_base<NearestNeighborSampler>(
|
| - next, srcPixmap, A8TintColor, sampleStage, accessor);
|
| + using S = NearestNeighborSampler<PixelAccessorShim, Blender>;
|
| + sampleStage->initStage<S>(next, pixelAccessor);
|
| } else {
|
| - return choose_pixel_sampler_base<BilerpSampler>(
|
| - next, srcPixmap, A8TintColor, sampleStage, accessor);
|
| + using S = BilerpSampler<PixelAccessorShim, Blender>;
|
| + sampleStage->initStage<S>(next, dimensions, xTile, yTile, pixelAccessor);
|
| }
|
| + return sampleStage->get();
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////////////////////////
|
| @@ -705,17 +560,17 @@ public:
|
| SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {}
|
| void SK_VECTORCALL blendPixel(Sk4f pixel) override {
|
| SkASSERT(fDst + 1 <= fEnd );
|
| - SrcPixel(fDst, pixel, 0);
|
| + this->srcPixel(fDst, pixel, 0);
|
| fDst += 1;
|
| }
|
|
|
| void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
|
| SkASSERT(fDst + 4 <= fEnd);
|
| SkPM4f* dst = fDst;
|
| - SrcPixel(dst, p0, 0);
|
| - SrcPixel(dst, p1, 1);
|
| - SrcPixel(dst, p2, 2);
|
| - SrcPixel(dst, p3, 3);
|
| + this->srcPixel(dst, p0, 0);
|
| + this->srcPixel(dst, p1, 1);
|
| + this->srcPixel(dst, p2, 2);
|
| + this->srcPixel(dst, p3, 3);
|
| fDst += 4;
|
| }
|
|
|
| @@ -725,7 +580,9 @@ public:
|
| }
|
|
|
| private:
|
| - void SK_VECTORCALL SrcPixel(SkPM4f* dst, Sk4f pixel, int index) {
|
| + void SK_VECTORCALL srcPixel(SkPM4f* dst, Sk4f pixel, int index) {
|
| + check_pixel(pixel);
|
| +
|
| Sk4f newPixel = pixel;
|
| if (alphaType == kUnpremul_SkAlphaType) {
|
| newPixel = Premultiply(pixel);
|
| @@ -797,7 +654,8 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline(
|
| // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
|
| auto blenderStage = choose_blender_for_shading(alphaType, postAlpha, &fBlenderStage);
|
| auto samplerStage = choose_pixel_sampler(
|
| - blenderStage, filterQuality, srcPixmap, paintColor, &fSampleStage, &fAccessor);
|
| + blenderStage, filterQuality, xTile, yTile,
|
| + srcPixmap, paintColor, &fSampleStage, &fAccessor);
|
| auto tilerStage = choose_tiler(samplerStage, dimensions, xTile, yTile,
|
| filterQuality, dx, &fTileStage);
|
| fFirstStage = choose_matrix(tilerStage, adjustedInverse, &fMatrixStage);
|
|
|