diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp index 5a4f86daa7..f3b281aac7 100644 --- a/src/core/SkLinearBitmapPipeline.cpp +++ b/src/core/SkLinearBitmapPipeline.cpp @@ -14,6 +14,63 @@ #include "SkColor.h" #include "SkSize.h" +// Tweak ABI of functions that pass Sk4f by value to pass them via registers. +#if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 + #define VECTORCALL __vectorcall + #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) + #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) + #else + #define VECTORCALL + #endif + +class SkLinearBitmapPipeline::PointProcessorInterface { +public: + virtual ~PointProcessorInterface() { } + virtual void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) = 0; + virtual void VECTORCALL pointList4(Sk4f xs, Sk4f ys) = 0; + + // The pointSpan method efficiently process horizontal spans of pixels. + // * start - the point where to start the span. + // * length - the number of pixels to traverse in source space. + // * count - the number of pixels to produce in destination space. + // Both start and length are mapped through the inversion matrix to produce values in source + // space. After the matrix operation, the tilers may break the spans up into smaller spans. + // The tilers can produce spans that seem nonsensical. + // * The clamp tiler can create spans with length of 0. This indicates to copy an edge pixel out + // to the edge of the destination scan. + // * The mirror tiler can produce spans with negative length. This indicates that the source + // should be traversed in the opposite direction to the destination pixels. + virtual void pointSpan(SkPoint start, SkScalar length, int count) = 0; +}; + +class SkLinearBitmapPipeline::BilerpProcessorInterface + : public SkLinearBitmapPipeline::PointProcessorInterface { +public: + // The x's and y's are setup in the following order: + // +--------+--------+ + // | | | + // | px00 | px10 | + // | 0 | 1 | + // +--------+--------+ + // | | | + // | px01 | px11 | + // | 2 | 3 | + // +--------+--------+ + // These pixels coordinates are arranged in the following order in xs and ys: + // px00 px10 px01 px11 + virtual void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) = 0; +}; + +class SkLinearBitmapPipeline::PixelPlacerInterface { +public: + virtual ~PixelPlacerInterface() { } + virtual void setDestination(SkPM4f* dst) = 0; + virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; + virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0; +}; + +namespace { + struct X { explicit X(SkScalar val) : fVal{val} { } explicit X(SkPoint pt) : fVal{pt.fX} { } @@ -68,21 +125,21 @@ void span_fallback(SkPoint start, SkScalar length, int count, Stage* stage) { // maybeProcessSpan - returns false if it can not process the span and needs to fallback to // point lists for processing. template -class PointProcessor final : public PointProcessorInterface { +class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterface { public: template PointProcessor(Next* next, Args&&... args) : fNext{next} , fStrategy{std::forward(args)...}{ } - void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { Sk4f newXs = xs; Sk4f newYs = ys; fStrategy.processPoints(&newXs, &newYs); fNext->pointListFew(n, newXs, newYs); } - void pointList4(Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { Sk4f newXs = xs; Sk4f newYs = ys; fStrategy.processPoints(&newXs, &newYs); @@ -102,28 +159,28 @@ private: // See PointProcessor for responsibilities of Strategy. template -class BilerpProcessor final : public BilerpProcessorInterface { +class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInterface { public: template BilerpProcessor(Next* next, Args&&... args) : fNext{next} , fStrategy{std::forward(args)...}{ } - void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { Sk4f newXs = xs; Sk4f newYs = ys; fStrategy.processPoints(&newXs, &newYs); fNext->pointListFew(n, newXs, newYs); } - void pointList4(Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { Sk4f newXs = xs; Sk4f newYs = ys; fStrategy.processPoints(&newXs, &newYs); fNext->pointList4(newXs, newYs); } - void bilerpList(Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { Sk4f newXs = xs; Sk4f newYs = ys; fStrategy.processPoints(&newXs, &newYs); @@ -141,14 +198,14 @@ private: Strategy fStrategy; }; -class SkippedStage final : public BilerpProcessorInterface { - void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { +class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterface { + void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { SkFAIL("Skipped stage."); } - void pointList4(Sk4fArg Xs, Sk4fArg Ys) override { + void VECTORCALL pointList4(Sk4f Xs, Sk4f Ys) override { SkFAIL("Skipped stage."); } - void bilerpList(Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { SkFAIL("Skipped stage."); } void pointSpan(SkPoint start, SkScalar length, int count) override { @@ -176,7 +233,7 @@ public: private: const Sk4f fXOffset, fYOffset; }; -template +template using TranslateMatrix = PointProcessor; class ScaleMatrixStrategy { @@ -202,7 +259,7 @@ private: const Sk4f fXOffset, fYOffset; const Sk4f fXScale, fYScale; }; -template +template using ScaleMatrix = PointProcessor; class AffineMatrixStrategy { @@ -229,11 +286,11 @@ private: const Sk4f fXScale, fYScale; const Sk4f fXSkew, fYSkew; }; -template +template using AffineMatrix = PointProcessor; -static PointProcessorInterface* choose_matrix( - PointProcessorInterface* next, +static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( + SkLinearBitmapPipeline::PointProcessorInterface* next, const SkMatrix& inverse, SkLinearBitmapPipeline::MatrixStage* matrixProc) { if (inverse.hasPerspective()) { @@ -260,12 +317,12 @@ static PointProcessorInterface* choose_matrix( return matrixProc->get(); } -template -class ExpandBilerp final : public PointProcessorInterface { +template +class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterface { public: ExpandBilerp(Next* next) : fNext{next} { } - void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { SkASSERT(0 < n && n < 4); // px00 px10 px01 px11 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, @@ -275,7 +332,7 @@ public: if (n >= 3) fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets); } - void pointList4(Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { // px00 px10 px01 px11 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; @@ -293,8 +350,8 @@ private: Next* const fNext; }; -static PointProcessorInterface* choose_filter( - BilerpProcessorInterface* next, +static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( + SkLinearBitmapPipeline::BilerpProcessorInterface* next, SkFilterQuality filterQuailty, SkLinearBitmapPipeline::FilterStage* filterProc) { if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) { @@ -336,7 +393,7 @@ private: const Sk4f fXMax{SK_FloatInfinity}; const Sk4f fYMax{SK_FloatInfinity}; }; -template +template using Clamp = BilerpProcessor; class RepeatStrategy { @@ -370,11 +427,11 @@ private: const Sk4f fYInvMax{0.0f}; }; -template +template using Repeat = BilerpProcessor; -static BilerpProcessorInterface* choose_tiler( - BilerpProcessorInterface* next, +static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( + SkLinearBitmapPipeline::BilerpProcessorInterface* next, SkSize dimensions, SkShader::TileMode xMode, SkShader::TileMode yMode, @@ -422,7 +479,7 @@ static BilerpProcessorInterface* choose_tiler( class sRGBFast { public: - static Sk4f sRGBToLinear(Sk4fArg pixel) { + static Sk4f VECTORCALL sRGBToLinear(Sk4f pixel) { Sk4f l = pixel * pixel; return Sk4f{l[0], l[1], l[2], pixel[3]}; } @@ -434,7 +491,7 @@ public: Passthrough8888(int width, const uint32_t* src) : fSrc{src}, fWidth{width}{ } - void getFewPixels(int n, Sk4fArg xs, Sk4fArg ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) { + void VECTORCALL getFewPixels(int n, Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) { Sk4i XIs = SkNx_cast(xs); Sk4i YIs = SkNx_cast(ys); Sk4i bufferLoc = YIs * fWidth + XIs; @@ -450,7 +507,7 @@ public: } } - void get4Pixels(Sk4fArg xs, Sk4fArg ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) { + void VECTORCALL get4Pixels(Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) { Sk4i XIs = SkNx_cast(xs); Sk4i YIs = SkNx_cast(ys); Sk4i bufferLoc = YIs * fWidth + XIs; @@ -496,8 +553,8 @@ private: // * px01 -> (1 - x)y = y - xy // * px11 -> xy // So x * y is calculated first and then used to calculate all the other factors. -static Sk4f bilerp4(Sk4fArg xs, Sk4fArg ys, Sk4fArg px00, Sk4fArg px10, - Sk4fArg px01, Sk4fArg px11) { +static Sk4f VECTORCALL bilerp4(Sk4f xs, Sk4f ys, Sk4f px00, Sk4f px10, + Sk4f px01, Sk4f px11) { // Calculate fractional xs and ys. Sk4f fxs = xs - xs.floor(); Sk4f fys = ys - ys.floor(); @@ -510,14 +567,14 @@ static Sk4f bilerp4(Sk4fArg xs, Sk4fArg ys, Sk4fArg px00, Sk4fArg px10, } template -class Sampler final : public BilerpProcessorInterface { +class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface { public: template - Sampler(PixelPlacerInterface* next, Args&&... args) + Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) : fNext{next} , fStrategy{std::forward(args)...} { } - void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { SkASSERT(0 < n && n < 4); Sk4f px0, px1, px2; fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); @@ -526,13 +583,13 @@ public: if (n >= 3) fNext->placePixel(px2); } - void pointList4(Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { Sk4f px0, px1, px2, px3; fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); fNext->place4Pixels(px0, px1, px2, px3); } - void bilerpList(Sk4fArg xs, Sk4fArg ys) override { + void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { Sk4f px00, px10, px01, px11; fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); @@ -544,12 +601,12 @@ public: } private: - PixelPlacerInterface* const fNext; + SkLinearBitmapPipeline::PixelPlacerInterface* const fNext; SourceStrategy fStrategy; }; -static BilerpProcessorInterface* choose_pixel_sampler( - PixelPlacerInterface* next, +static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler( + SkLinearBitmapPipeline::PixelPlacerInterface* next, const SkPixmap& srcPixmap, SkLinearBitmapPipeline::SampleStage* sampleStage) { const SkImageInfo& imageInfo = srcPixmap.info(); @@ -578,14 +635,14 @@ static BilerpProcessorInterface* choose_pixel_sampler( } template -class PlaceFPPixel final : public PixelPlacerInterface { +class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface { public: - void placePixel(Sk4fArg pixel) override { + void VECTORCALL placePixel(Sk4f pixel) override { PlacePixel(fDst, pixel, 0); fDst += 1; } - void place4Pixels(Sk4fArg p0, Sk4fArg p1, Sk4fArg p2, Sk4fArg p3) override { + void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { SkPM4f* dst = fDst; PlacePixel(dst, p0, 0); PlacePixel(dst, p1, 1); @@ -599,14 +656,14 @@ public: } private: - static void PlacePixel(SkPM4f* dst, Sk4fArg pixel, int index) { + static void VECTORCALL PlacePixel(SkPM4f* dst, Sk4f pixel, int index) { Sk4f newPixel = pixel; if (alphaType == kUnpremul_SkAlphaType) { newPixel = Premultiply(pixel); } newPixel.store(dst + index); } - static Sk4f Premultiply(Sk4fArg pixel) { + static Sk4f VECTORCALL Premultiply(Sk4f pixel) { float alpha = pixel[3]; return pixel * Sk4f{alpha, alpha, alpha, 1.0f}; } @@ -614,7 +671,7 @@ private: SkPM4f* fDst; }; -static PixelPlacerInterface* choose_pixel_placer( +static SkLinearBitmapPipeline::PixelPlacerInterface* choose_pixel_placer( SkAlphaType alphaType, SkLinearBitmapPipeline::PixelStage* placerStage) { if (alphaType == kUnpremul_SkAlphaType) { @@ -625,6 +682,9 @@ static PixelPlacerInterface* choose_pixel_placer( } return placerStage->get(); } +} // namespace + +SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {} SkLinearBitmapPipeline::SkLinearBitmapPipeline( const SkMatrix& inverse, diff --git a/src/core/SkLinearBitmapPipeline.h b/src/core/SkLinearBitmapPipeline.h index d9748df750..3d5dd31df3 100644 --- a/src/core/SkLinearBitmapPipeline.h +++ b/src/core/SkLinearBitmapPipeline.h @@ -15,53 +15,6 @@ #include "SkNx.h" #include "SkShader.h" -using Sk4fArg = const Sk4f&; - -class PointProcessorInterface { -public: - virtual ~PointProcessorInterface() { } - virtual void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) = 0; - virtual void pointList4(Sk4fArg xs, Sk4fArg ys) = 0; - - // The pointSpan method efficiently process horizontal spans of pixels. - // * start - the point where to start the span. - // * length - the number of pixels to traverse in source space. - // * count - the number of pixels to produce in destination space. - // Both start and length are mapped through the inversion matrix to produce values in source - // space. After the matrix operation, the tilers may break the spans up into smaller spans. - // The tilers can produce spans that seem nonsensical. - // * The clamp tiler can create spans with length of 0. This indicates to copy an edge pixel out - // to the edge of the destination scan. - // * The mirror tiler can produce spans with negative length. This indicates that the source - // should be traversed in the opposite direction to the destination pixels. - virtual void pointSpan(SkPoint start, SkScalar length, int count) = 0; -}; - -class BilerpProcessorInterface : public PointProcessorInterface { -public: - // The x's and y's are setup in the following order: - // +--------+--------+ - // | | | - // | px00 | px10 | - // | 0 | 1 | - // +--------+--------+ - // | | | - // | px01 | px11 | - // | 2 | 3 | - // +--------+--------+ - // These pixels coordinates are arranged in the following order in xs and ys: - // px00 px10 px01 px11 - virtual void bilerpList(Sk4fArg xs, Sk4fArg ys) = 0; -}; - -class PixelPlacerInterface { -public: - virtual ~PixelPlacerInterface() { } - virtual void setDestination(SkPM4f* dst) = 0; - virtual void placePixel(Sk4fArg pixel0) = 0; - virtual void place4Pixels(Sk4fArg p0, Sk4fArg p1, Sk4fArg p2, Sk4fArg p3) = 0; -}; - class SkLinearBitmapPipeline { public: SkLinearBitmapPipeline( @@ -69,6 +22,7 @@ public: SkFilterQuality filterQuality, SkShader::TileMode xTile, SkShader::TileMode yTile, const SkPixmap& srcPixmap); + ~SkLinearBitmapPipeline(); void shadeSpan4f(int x, int y, SkPM4f* dst, int count); @@ -98,6 +52,10 @@ public: mutable Space fSpace; }; + class PointProcessorInterface; + class BilerpProcessorInterface; + class PixelPlacerInterface; + using MatrixStage = PolymorphicUnion; using FilterStage = PolymorphicUnion; using TileStage = PolymorphicUnion; diff --git a/tests/SkLinearBitmapPipelineTest.cpp b/tests/SkLinearBitmapPipelineTest.cpp index 9d12f1b465..04f2e2783e 100644 --- a/tests/SkLinearBitmapPipelineTest.cpp +++ b/tests/SkLinearBitmapPipelineTest.cpp @@ -10,14 +10,6 @@ #include "SkPM4f.h" #include "Test.h" -struct SinkBilerpProcessor final : public PointProcessorInterface { - void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { fXs = xs; fYs = ys; } - void pointList4(Sk4fArg Xs, Sk4fArg Ys) override { fXs = Xs; fYs = Ys; } - void pointSpan(SkPoint start, SkScalar length, int count) override { } - Sk4f fXs; - Sk4f fYs; -}; - using Pixel = float[4]; DEF_TEST(SkBitmapFP, reporter) {