aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar herb <herb@google.com>2016-02-17 19:50:05 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-02-17 19:50:05 -0800
commitc5eddd7d8d67a6e931973a729c5868c155cb751f (patch)
tree256e9d303b3f25339c59cc260f4a36a163e578b0 /src
parent576af8f0cc97f12f60eeea5c2434d079a62fd0db (diff)
Add bilerp filtering.
Diffstat (limited to 'src')
-rw-r--r--src/core/SkLinearBitmapPipeline.cpp148
-rw-r--r--src/core/SkLinearBitmapPipeline.h24
2 files changed, 156 insertions, 16 deletions
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp
index d1000282da..d25335b0e7 100644
--- a/src/core/SkLinearBitmapPipeline.cpp
+++ b/src/core/SkLinearBitmapPipeline.cpp
@@ -22,14 +22,13 @@ struct Y {
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 {
+class PointProcessor final : public PointProcessorInterface {
public:
template <typename... Args>
PointProcessor(Next* next, Args&&... args)
@@ -55,12 +54,49 @@ private:
Strategy fStrategy;
};
-class SkippedStage final : public PointProcessorInterface {
+template<typename Strategy, typename Next>
+class BilerpProcessor final : public BilerpProcessorInterface {
+public:
+ template <typename... Args>
+ BilerpProcessor(Next* next, Args&&... args)
+ : fNext{next}
+ , fStrategy{std::forward<Args>(args)...}{ }
+
void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
- SkFAIL("Abort tiler.");
+ 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);
+ }
+
+ void bilerpList(Sk4fArg xs, Sk4fArg ys) override {
+ Sk4f newXs = xs;
+ Sk4f newYs = ys;
+ fStrategy.processPoints(&newXs, &newYs);
+ fNext->bilerpList(newXs, newYs);
+ }
+
+private:
+ Next* const fNext;
+ Strategy fStrategy;
+};
+
+class SkippedStage final : public BilerpProcessorInterface {
+ void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
+ SkFAIL("Skipped stage.");
}
void pointList4(Sk4fArg Xs, Sk4fArg Ys) override {
- SkFAIL("Abort point processor.");
+ SkFAIL("Skipped stage.");
+ }
+ virtual void bilerpList(Sk4fArg xs, Sk4fArg ys) override {
+ SkFAIL("Skipped stage.");
}
};
@@ -147,6 +183,48 @@ static PointProcessorInterface* choose_matrix(
return matrixProc->get();
}
+template <typename Next = BilerpProcessorInterface>
+class ExpandBilerp final : public PointProcessorInterface {
+public:
+ ExpandBilerp(Next* next) : fNext{next} { }
+
+ void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
+ SkASSERT(0 < n && n < 4);
+ // px00 px10 px01 px11
+ const Sk4f kXOffsets{0.0f, 1.0f, 0.0f, 1.0f},
+ kYOffsets{0.0f, 0.0f, 1.0f, 1.0f};
+ if (n >= 1) fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets);
+ if (n >= 2) fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets);
+ if (n >= 3) fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets);
+ }
+
+ void pointList4(Sk4fArg xs, Sk4fArg ys) override {
+ // px00 px10 px01 px11
+ const Sk4f kXOffsets{0.0f, 1.0f, 0.0f, 1.0f},
+ kYOffsets{0.0f, 0.0f, 1.0f, 1.0f};
+ fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets);
+ fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets);
+ fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets);
+ fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYOffsets);
+ }
+
+private:
+ Next* const fNext;
+};
+
+static PointProcessorInterface* choose_filter(
+ BilerpProcessorInterface* next,
+ SkFilterQuality filterQuailty,
+ SkLinearBitmapPipeline::FilterStage* filterProc) {
+ if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) {
+ filterProc->Initialize<SkippedStage>();
+ return next;
+ } else {
+ filterProc->Initialize<ExpandBilerp<>>(next);
+ return filterProc->get();
+ }
+}
+
class ClampStrategy {
public:
ClampStrategy(X max)
@@ -172,8 +250,8 @@ private:
const Sk4f fXMax{SK_FloatInfinity};
const Sk4f fYMax{SK_FloatInfinity};
};
-template <typename Next = PointProcessorInterface>
-using Clamp = PointProcessor<ClampStrategy, Next>;
+template <typename Next = BilerpProcessorInterface>
+using Clamp = BilerpProcessor<ClampStrategy, Next>;
class RepeatStrategy {
public:
@@ -201,11 +279,11 @@ private:
const Sk4f fYInvMax{0.0f};
};
-template <typename Next = PointProcessorInterface>
-using Repeat = PointProcessor<RepeatStrategy, Next>;
+template <typename Next = BilerpProcessorInterface>
+using Repeat = BilerpProcessor<RepeatStrategy, Next>;
-static PointProcessorInterface* choose_tiler(
- PointProcessorInterface* next,
+static BilerpProcessorInterface* choose_tiler(
+ BilerpProcessorInterface* next,
SkSize dimensions,
SkShader::TileMode xMode,
SkShader::TileMode yMode,
@@ -307,8 +385,41 @@ private:
const Sk4i fWidth;
};
+// Explaination of the math:
+// 1 - x x
+// +--------+--------+
+// | | |
+// 1 - y | px00 | px10 |
+// | | |
+// +--------+--------+
+// | | |
+// y | px01 | px11 |
+// | | |
+// +--------+--------+
+//
+//
+// Given a pixelxy each is multiplied by a different factor derived from the fractional part of x
+// and y:
+// * px00 -> (1 - x)(1 - y) = 1 - x - y + xy
+// * px10 -> x(1 - y) = x - xy
+// * 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) {
+ // Calculate fractional xs and ys.
+ Sk4f fxs = xs - xs.floor();
+ Sk4f fys = ys - ys.floor();
+ Sk4f fxys{fxs * fys};
+ Sk4f sum = px11 * fxys;
+ sum = sum + px01 * (fys - fxys);
+ sum = sum + px10 * (fxs - fxys);
+ sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys);
+ return sum;
+}
+
template <typename SourceStrategy>
-class Sampler final : public PointProcessorInterface {
+class Sampler final : public BilerpProcessorInterface {
public:
template <typename... Args>
Sampler(PixelPlacerInterface* next, Args&&... args)
@@ -330,12 +441,19 @@ public:
fNext->place4Pixels(px0, px1, px2, px3);
}
+ void bilerpList(Sk4fArg xs, Sk4fArg ys) override {
+ Sk4f px00, px10, px01, px11;
+ fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11);
+ Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11);
+ fNext->placePixel(pixel);
+ }
+
private:
PixelPlacerInterface* const fNext;
SourceStrategy fStrategy;
};
-static PointProcessorInterface* choose_pixel_sampler(
+static BilerpProcessorInterface* choose_pixel_sampler(
PixelPlacerInterface* next,
const SkImageInfo& imageInfo,
const void* imageData,
@@ -415,6 +533,7 @@ static PixelPlacerInterface* choose_pixel_placer(
SkLinearBitmapPipeline::SkLinearBitmapPipeline(
const SkMatrix& inverse,
+ SkFilterQuality filterQuality,
SkShader::TileMode xTile, SkShader::TileMode yTile,
const SkImageInfo& srcImageInfo,
const void* srcImageData) {
@@ -428,7 +547,8 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline(
srcImageData, &fSampleStage);
auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileXOrBothStage,
&fTileYStage);
- fFirstStage = choose_matrix(tilerStage, inverse, &fMatrixStage);
+ auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage);
+ fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage);
}
void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
diff --git a/src/core/SkLinearBitmapPipeline.h b/src/core/SkLinearBitmapPipeline.h
index f6875c6a96..9d537df501 100644
--- a/src/core/SkLinearBitmapPipeline.h
+++ b/src/core/SkLinearBitmapPipeline.h
@@ -28,6 +28,23 @@ public:
virtual void pointList4(Sk4fArg xs, Sk4fArg ys) = 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() { }
@@ -40,6 +57,7 @@ class SkLinearBitmapPipeline {
public:
SkLinearBitmapPipeline(
const SkMatrix& inverse,
+ SkFilterQuality filterQuality,
SkShader::TileMode xTile, SkShader::TileMode yTile,
const SkImageInfo& srcImageInfo,
const void* srcImageData);
@@ -73,13 +91,15 @@ public:
};
using MatrixStage = PolymorphicUnion<PointProcessorInterface, 112>;
- using TileStage = PolymorphicUnion<PointProcessorInterface, 96>;
- using SampleStage = PolymorphicUnion<PointProcessorInterface, 80>;
+ using FilterStage = PolymorphicUnion<PointProcessorInterface, 8>;
+ using TileStage = PolymorphicUnion<BilerpProcessorInterface, 96>;
+ using SampleStage = PolymorphicUnion<BilerpProcessorInterface, 80>;
using PixelStage = PolymorphicUnion<PixelPlacerInterface, 80>;
private:
PointProcessorInterface* fFirstStage;
MatrixStage fMatrixStage;
+ FilterStage fFilterStage;
TileStage fTileXOrBothStage;
TileStage fTileYStage;
SampleStage fSampleStage;