aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar herb <herb@google.com>2016-02-17 10:00:07 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-02-17 10:00:07 -0800
commitfeec878e850850cb0a092a765e3af0f5a3fa2a42 (patch)
treeb8a14038dc972876ba7d1c3f0bcaa0f54c56fc87 /src
parent68c063bf11c91b2b3b15cb93168cf2af9b2c642d (diff)
Simplified linear pipeline.
Diffstat (limited to 'src')
-rw-r--r--src/core/SkLinearBitmapPipeline.cpp449
-rw-r--r--src/core/SkLinearBitmapPipeline.h89
-rw-r--r--src/core/SkNx.h1
3 files changed, 539 insertions, 0 deletions
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp
new file mode 100644
index 0000000000..d1000282da
--- /dev/null
+++ b/src/core/SkLinearBitmapPipeline.cpp
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkLinearBitmapPipeline.h"
+
+struct X {
+ explicit X(SkScalar val) : fVal{val} { }
+ explicit X(SkPoint pt) : fVal{pt.fX} { }
+ explicit X(SkSize s) : fVal{s.fWidth} { }
+ explicit X(SkISize s) : fVal(s.fWidth) { }
+ operator float () const {return fVal;}
+private:
+ float fVal;
+};
+
+struct Y {
+ explicit Y(SkScalar val) : fVal{val} { }
+ explicit Y(SkPoint pt) : fVal{pt.fY} { }
+ explicit Y(SkSize s) : fVal{s.fHeight} { }
+ explicit Y(SkISize s) : fVal(s.fHeight) { }
+
+ operator float () const {return fVal;}
+private:
+ float fVal;
+};
+
+template<typename Strategy, typename Next>
+class PointProcessor : public PointProcessorInterface {
+public:
+ template <typename... Args>
+ PointProcessor(Next* next, Args&&... args)
+ : fNext{next}
+ , fStrategy{std::forward<Args>(args)...}{ }
+
+ void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
+ Sk4f newXs = xs;
+ Sk4f newYs = ys;
+ fStrategy.processPoints(&newXs, &newYs);
+ fNext->pointListFew(n, newXs, newYs);
+ }
+
+ void pointList4(Sk4fArg xs, Sk4fArg ys) override {
+ Sk4f newXs = xs;
+ Sk4f newYs = ys;
+ fStrategy.processPoints(&newXs, &newYs);
+ fNext->pointList4(newXs, newYs);
+ }
+
+private:
+ Next* const fNext;
+ Strategy fStrategy;
+};
+
+class SkippedStage final : public PointProcessorInterface {
+ void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
+ SkFAIL("Abort tiler.");
+ }
+ void pointList4(Sk4fArg Xs, Sk4fArg Ys) override {
+ SkFAIL("Abort point processor.");
+ }
+};
+
+class TranslateMatrixStrategy {
+public:
+ TranslateMatrixStrategy(SkVector offset)
+ : fXOffset{X(offset)}
+ , fYOffset{Y(offset)} { }
+ void processPoints(Sk4f* xs, Sk4f* ys) {
+ *xs = *xs + fXOffset;
+ *ys = *ys + fYOffset;
+ }
+
+private:
+ const Sk4f fXOffset, fYOffset;
+};
+template <typename Next = PointProcessorInterface>
+using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>;
+
+class ScaleMatrixStrategy {
+public:
+ ScaleMatrixStrategy(SkVector offset, SkVector scale)
+ : fXOffset{X(offset)}, fYOffset{Y(offset)}
+ , fXScale{X(scale)}, fYScale{Y(scale)} { }
+ void processPoints(Sk4f* xs, Sk4f* ys) {
+ *xs = *xs * fXScale + fXOffset;
+ *ys = *ys * fYScale + fYOffset;
+ }
+
+private:
+ const Sk4f fXOffset, fYOffset;
+ const Sk4f fXScale, fYScale;
+};
+template <typename Next = PointProcessorInterface>
+using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>;
+
+class AffineMatrixStrategy {
+public:
+ AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew)
+ : fXOffset{X(offset)}, fYOffset{Y(offset)}
+ , fXScale{X(scale)}, fYScale{Y(scale)}
+ , fXSkew{X(skew)}, fYSkew{Y(skew)} { }
+ void processPoints(Sk4f* xs, Sk4f* ys) {
+ Sk4f newXs = fXScale * *xs + fXSkew * *ys + fXOffset;
+ Sk4f newYs = fYSkew * *xs + fYScale * *ys + fYOffset;
+
+ *xs = newXs;
+ *ys = newYs;
+ }
+
+private:
+ const Sk4f fXOffset, fYOffset;
+ const Sk4f fXScale, fYScale;
+ const Sk4f fXSkew, fYSkew;
+};
+template <typename Next = PointProcessorInterface>
+using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>;
+
+static PointProcessorInterface* choose_matrix(
+ PointProcessorInterface* next,
+ const SkMatrix& inverse,
+ SkLinearBitmapPipeline::MatrixStage* matrixProc) {
+ if (inverse.hasPerspective()) {
+ SkFAIL("Not implemented.");
+ } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
+ matrixProc->Initialize<AffineMatrix<>>(
+ next,
+ SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
+ SkVector{inverse.getScaleX(), inverse.getScaleY()},
+ SkVector{inverse.getSkewX(), inverse.getSkewY()});
+ } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
+ matrixProc->Initialize<ScaleMatrix<>>(
+ next,
+ SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
+ SkVector{inverse.getScaleX(), inverse.getScaleY()});
+ } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
+ matrixProc->Initialize<TranslateMatrix<>>(
+ next,
+ SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
+ } else {
+ matrixProc->Initialize<SkippedStage>();
+ return next;
+ }
+ return matrixProc->get();
+}
+
+class ClampStrategy {
+public:
+ ClampStrategy(X max)
+ : fXMin{0.0f}
+ , fXMax{max - 1.0f} { }
+ ClampStrategy(Y max)
+ : fYMin{0.0f}
+ , fYMax{max - 1.0f} { }
+ ClampStrategy(SkSize max)
+ : fXMin{0.0f}
+ , fYMin{0.0f}
+ , fXMax{X(max) - 1.0f}
+ , fYMax{Y(max) - 1.0f} { }
+
+ void processPoints(Sk4f* xs, Sk4f* ys) {
+ *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax);
+ *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax);
+ }
+
+private:
+ const Sk4f fXMin{SK_FloatNegativeInfinity};
+ const Sk4f fYMin{SK_FloatNegativeInfinity};
+ const Sk4f fXMax{SK_FloatInfinity};
+ const Sk4f fYMax{SK_FloatInfinity};
+};
+template <typename Next = PointProcessorInterface>
+using Clamp = PointProcessor<ClampStrategy, Next>;
+
+class RepeatStrategy {
+public:
+ RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { }
+ RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { }
+ RepeatStrategy(SkSize max)
+ : fXMax{X(max)}
+ , fXInvMax{1.0f / X(max)}
+ , fYMax{Y(max)}
+ , fYInvMax{1.0f / Y(max)} { }
+
+ void processPoints(Sk4f* xs, Sk4f* ys) {
+ Sk4f divX = (*xs * fXInvMax).floor();
+ Sk4f divY = (*ys * fYInvMax).floor();
+ Sk4f baseX = (divX * fXMax);
+ Sk4f baseY = (divY * fYMax);
+ *xs = *xs - baseX;
+ *ys = *ys - baseY;
+ }
+
+private:
+ const Sk4f fXMax{0.0f};
+ const Sk4f fXInvMax{0.0f};
+ const Sk4f fYMax{0.0f};
+ const Sk4f fYInvMax{0.0f};
+};
+
+template <typename Next = PointProcessorInterface>
+using Repeat = PointProcessor<RepeatStrategy, Next>;
+
+static PointProcessorInterface* choose_tiler(
+ PointProcessorInterface* next,
+ SkSize dimensions,
+ SkShader::TileMode xMode,
+ SkShader::TileMode yMode,
+ SkLinearBitmapPipeline::TileStage* tileProcXOrBoth,
+ SkLinearBitmapPipeline::TileStage* tileProcY) {
+ if (xMode == yMode) {
+ switch (xMode) {
+ case SkShader::kClamp_TileMode:
+ tileProcXOrBoth->Initialize<Clamp<>>(next, dimensions);
+ break;
+ case SkShader::kRepeat_TileMode:
+ tileProcXOrBoth->Initialize<Repeat<>>(next, dimensions);
+ break;
+ case SkShader::kMirror_TileMode:
+ SkFAIL("Not implemented.");
+ break;
+ }
+ tileProcY->Initialize<SkippedStage>();
+ } else {
+ switch (yMode) {
+ case SkShader::kClamp_TileMode:
+ tileProcY->Initialize<Clamp<>>(next, Y(dimensions));
+ break;
+ case SkShader::kRepeat_TileMode:
+ tileProcY->Initialize<Repeat<>>(next, Y(dimensions));
+ break;
+ case SkShader::kMirror_TileMode:
+ SkFAIL("Not implemented.");
+ break;
+ }
+ switch (xMode) {
+ case SkShader::kClamp_TileMode:
+ tileProcXOrBoth->Initialize<Clamp<>>(tileProcY->get(), X(dimensions));
+ break;
+ case SkShader::kRepeat_TileMode:
+ tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimensions));
+ break;
+ case SkShader::kMirror_TileMode:
+ SkFAIL("Not implemented.");
+ break;
+ }
+ }
+ return tileProcXOrBoth->get();
+}
+
+class sRGBFast {
+public:
+ static Sk4f sRGBToLinear(Sk4fArg pixel) {
+ Sk4f l = pixel * pixel;
+ return Sk4f{l[0], l[1], l[2], pixel[3]};
+ }
+};
+
+template <SkColorProfileType colorProfile>
+class Passthrough8888 {
+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) {
+ Sk4i XIs = SkNx_cast<int, float>(xs);
+ Sk4i YIs = SkNx_cast<int, float>(ys);
+ Sk4i bufferLoc = YIs * fWidth + XIs;
+ switch (n) {
+ case 3:
+ *px2 = getPixel(fSrc, bufferLoc[2]);
+ case 2:
+ *px1 = getPixel(fSrc, bufferLoc[1]);
+ case 1:
+ *px0 = getPixel(fSrc, bufferLoc[0]);
+ default:
+ break;
+ }
+ }
+
+ void get4Pixels(Sk4fArg xs, Sk4fArg ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) {
+ Sk4i XIs = SkNx_cast<int, float>(xs);
+ Sk4i YIs = SkNx_cast<int, float>(ys);
+ Sk4i bufferLoc = YIs * fWidth + XIs;
+ *px0 = getPixel(fSrc, bufferLoc[0]);
+ *px1 = getPixel(fSrc, bufferLoc[1]);
+ *px2 = getPixel(fSrc, bufferLoc[2]);
+ *px3 = getPixel(fSrc, bufferLoc[3]);
+ }
+
+ const uint32_t* row(int y) { return fSrc + y * fWidth[0]; }
+
+private:
+ Sk4f getPixel(const uint32_t* src, int index) {
+ Sk4b bytePixel = Sk4b::Load((uint8_t *)(&src[index]));
+ Sk4f pixel = SkNx_cast<float, uint8_t>(bytePixel);
+ pixel = pixel * Sk4f{1.0f/255.0f};
+ if (colorProfile == kSRGB_SkColorProfileType) {
+ pixel = sRGBFast::sRGBToLinear(pixel);
+ }
+ return pixel;
+ }
+ const uint32_t* const fSrc;
+ const Sk4i fWidth;
+};
+
+template <typename SourceStrategy>
+class Sampler final : public PointProcessorInterface {
+public:
+ template <typename... Args>
+ Sampler(PixelPlacerInterface* next, Args&&... args)
+ : fNext{next}
+ , fStrategy{std::forward<Args>(args)...} { }
+
+ void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
+ SkASSERT(0 < n && n < 4);
+ Sk4f px0, px1, px2;
+ fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2);
+ if (n >= 1) fNext->placePixel(px0);
+ if (n >= 2) fNext->placePixel(px1);
+ if (n >= 3) fNext->placePixel(px2);
+ }
+
+ void pointList4(Sk4fArg xs, Sk4fArg ys) override {
+ Sk4f px0, px1, px2, px3;
+ fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
+ fNext->place4Pixels(px0, px1, px2, px3);
+ }
+
+private:
+ PixelPlacerInterface* const fNext;
+ SourceStrategy fStrategy;
+};
+
+static PointProcessorInterface* choose_pixel_sampler(
+ PixelPlacerInterface* next,
+ const SkImageInfo& imageInfo,
+ const void* imageData,
+ SkLinearBitmapPipeline::SampleStage* sampleStage) {
+ switch (imageInfo.colorType()) {
+ case kRGBA_8888_SkColorType:
+ case kBGRA_8888_SkColorType:
+ if (kN32_SkColorType == imageInfo.colorType()) {
+ if (imageInfo.profileType() == kSRGB_SkColorProfileType) {
+ sampleStage->Initialize<Sampler<Passthrough8888<kSRGB_SkColorProfileType>>>(
+ next, imageInfo.width(),
+ (uint32_t*)imageData);
+ } else {
+ sampleStage->Initialize<Sampler<Passthrough8888<kLinear_SkColorProfileType>>>(
+ next, imageInfo.width(),
+ (uint32_t*)imageData);
+ }
+ } else {
+ SkFAIL("Not implemented. No 8888 Swizzle");
+ }
+ break;
+ default:
+ SkFAIL("Not implemented. Unsupported src");
+ break;
+ }
+ return sampleStage->get();
+}
+
+template <SkAlphaType alphaType>
+class PlaceFPPixel final : public PixelPlacerInterface {
+public:
+ void placePixel(Sk4fArg pixel) override {
+ PlacePixel(fDst, pixel, 0);
+ fDst += 1;
+ }
+
+ void place4Pixels(Sk4fArg p0, Sk4fArg p1, Sk4fArg p2, Sk4fArg p3) override {
+ SkPM4f* dst = fDst;
+ PlacePixel(dst, p0, 0);
+ PlacePixel(dst, p1, 1);
+ PlacePixel(dst, p2, 2);
+ PlacePixel(dst, p3, 3);
+ fDst += 4;
+ }
+
+ void setDestination(SkPM4f* dst) override {
+ fDst = dst;
+ }
+
+private:
+ static void PlacePixel(SkPM4f* dst, Sk4fArg pixel, int index) {
+ Sk4f newPixel = pixel;
+ if (alphaType == kUnpremul_SkAlphaType) {
+ newPixel = Premultiply(pixel);
+ }
+ newPixel.store(dst + index);
+ }
+ static Sk4f Premultiply(Sk4fArg pixel) {
+ float alpha = pixel[3];
+ return pixel * Sk4f{alpha, alpha, alpha, 1.0f};
+ }
+
+ SkPM4f* fDst;
+};
+
+static PixelPlacerInterface* choose_pixel_placer(
+ SkAlphaType alphaType,
+ SkLinearBitmapPipeline::PixelStage* placerStage) {
+ if (alphaType == kUnpremul_SkAlphaType) {
+ placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>();
+ } else {
+ // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
+ placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>();
+ }
+ return placerStage->get();
+}
+
+SkLinearBitmapPipeline::SkLinearBitmapPipeline(
+ const SkMatrix& inverse,
+ SkShader::TileMode xTile, SkShader::TileMode yTile,
+ const SkImageInfo& srcImageInfo,
+ const void* srcImageData) {
+ SkSize size;
+ size = srcImageInfo.dimensions();
+
+ // As the stages are built, the chooser function may skip a stage. For example, with the
+ // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
+ auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelStage);
+ auto samplerStage = choose_pixel_sampler(placementStage, srcImageInfo,
+ srcImageData, &fSampleStage);
+ auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileXOrBothStage,
+ &fTileYStage);
+ fFirstStage = choose_matrix(tilerStage, inverse, &fMatrixStage);
+}
+
+void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
+ fPixelStage->setDestination(dst);
+
+ Sk4f Xs = Sk4f(x) + Sk4f{0.5f, 1.5f, 2.5f, 3.5f};
+ Sk4f Ys(y);
+ Sk4f fours{4.0f};
+
+ while (count >= 4) {
+ fFirstStage->pointList4(Xs, Ys);
+ Xs = Xs + fours;
+ count -= 4;
+ }
+ if (count > 0) {
+ fFirstStage->pointListFew(count, Xs, Ys);
+ }
+}
diff --git a/src/core/SkLinearBitmapPipeline.h b/src/core/SkLinearBitmapPipeline.h
new file mode 100644
index 0000000000..f6875c6a96
--- /dev/null
+++ b/src/core/SkLinearBitmapPipeline.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkLinearBitmapPipeline_DEFINED
+#define SkLinearBitmapPipeline_DEFINED
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+#include <cstdio>
+#include "SkColor.h"
+#include "SkImageInfo.h"
+#include "SkMatrix.h"
+#include "SkShader.h"
+#include "SkSize.h"
+#include "SkNx.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;
+};
+
+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(
+ const SkMatrix& inverse,
+ SkShader::TileMode xTile, SkShader::TileMode yTile,
+ const SkImageInfo& srcImageInfo,
+ const void* srcImageData);
+
+ void shadeSpan4f(int x, int y, SkPM4f* dst, int count);
+
+ template<typename Base, size_t kSize>
+ class PolymorphicUnion {
+ public:
+ PolymorphicUnion() {}
+
+ ~PolymorphicUnion() { get()->~Base(); }
+
+ template<typename Variant, typename... Args>
+ void Initialize(Args&&... args) {
+ SkASSERTF(sizeof(Variant) <= sizeof(fSpace),
+ "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace));
+
+ new(&fSpace) Variant(std::forward<Args>(args)...);
+ };
+
+ Base* get() const { return reinterpret_cast<Base*>(&fSpace); }
+ Base* operator->() const { return get(); }
+ Base& operator*() const { return *get(); }
+
+ private:
+ struct SK_STRUCT_ALIGN(16) Space {
+ char space[kSize];
+ };
+ mutable Space fSpace;
+ };
+
+ using MatrixStage = PolymorphicUnion<PointProcessorInterface, 112>;
+ using TileStage = PolymorphicUnion<PointProcessorInterface, 96>;
+ using SampleStage = PolymorphicUnion<PointProcessorInterface, 80>;
+ using PixelStage = PolymorphicUnion<PixelPlacerInterface, 80>;
+
+private:
+ PointProcessorInterface* fFirstStage;
+ MatrixStage fMatrixStage;
+ TileStage fTileXOrBothStage;
+ TileStage fTileYStage;
+ SampleStage fSampleStage;
+ PixelStage fPixelStage;
+};
+
+#endif // SkLinearBitmapPipeline_DEFINED
diff --git a/src/core/SkNx.h b/src/core/SkNx.h
index 8722bf6dfa..166557dda2 100644
--- a/src/core/SkNx.h
+++ b/src/core/SkNx.h
@@ -198,6 +198,7 @@ typedef SkNx<4, uint8_t> Sk4b;
typedef SkNx<16, uint8_t> Sk16b;
typedef SkNx<4, uint16_t> Sk4h;
typedef SkNx<16, uint16_t> Sk16h;
+typedef SkNx<4, int> Sk4i;
typedef SkNx<4, int> Sk4i;