Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Unified Diff: src/core/SkLinearBitmapPipeline.cpp

Issue 1705203002: Add bilerp filtering. (Closed) Base URL: https://skia.googlesource.com/skia.git@fp-simple-linear-20160217
Patch Set: Redo bilerp. Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkLinearBitmapPipeline.h ('k') | tests/SkLinearBitmapPipelineTest.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkLinearBitmapPipeline.cpp
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp
index d1000282da334f286e831cc0029a957662087df0..d25335b0e7468ad4bc1ec026b08ac133c51e38b0 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.
mtklein 2016/02/17 23:46:55 This is beautiful. Nominated for favorite code sn
herb_g 2016/02/18 03:49:06 Acknowledged.
+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) {
« no previous file with comments | « src/core/SkLinearBitmapPipeline.h ('k') | tests/SkLinearBitmapPipelineTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698