Index: src/core/SkLinearBitmapPipeline.cpp |
diff --git a/src/core/SkLinearBitmapPipeline.cpp b/src/core/SkLinearBitmapPipeline.cpp |
index d1000282da334f286e831cc0029a957662087df0..52782bc87f45e50222d91a7e0642bc23ef821ce2 100644 |
--- a/src/core/SkLinearBitmapPipeline.cpp |
+++ b/src/core/SkLinearBitmapPipeline.cpp |
@@ -55,12 +55,49 @@ private: |
Strategy fStrategy; |
}; |
-class SkippedStage final : public PointProcessorInterface { |
+template<typename Strategy, typename Next> |
+class BilerpProcessor : public BilerpProcessorInterface { |
mtklein
2016/02/17 20:25:09
final (and PointProcessor too)?
herb_g
2016/02/17 23:40:43
Done.
|
+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; |
mtklein
2016/02/17 20:25:09
This is so sad. :(
herb_g
2016/02/17 23:40:44
Acknowledged.
|
+ 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 { |
mtklein
2016/02/17 20:25:09
I think override's plenty.
herb_g
2016/02/17 23:40:44
Done.
|
+ SkFAIL("Skipped stage."); |
} |
}; |
@@ -147,6 +184,47 @@ 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(n > 0 && n <= 4); |
mtklein
2016/02/17 20:25:09
This seems awkward. It's a bug if we call pointLi
herb_g
2016/02/17 23:40:43
Done.
|
+ 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); |
+ if (n == 4) fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYOffsets); |
+ } |
+ |
+ void pointList4(Sk4fArg xs, Sk4fArg ys) override { |
+ pointListFew(4, xs, ys); |
mtklein
2016/02/17 20:25:09
self calls usually have a this->
herb_g
2016/02/17 23:40:44
Removed
|
+ } |
mtklein
2016/02/17 20:25:09
Is this why we distinguish PointProcessor and Bile
herb_g
2016/02/17 23:40:44
There is no sensible bilerp here or at the matrix
|
+ |
+private: |
+ static const Sk4f kXOffsets; |
+ static const Sk4f kYOffsets; |
+ Next* const fNext; |
+}; |
+ |
+template <typename Next> |
+const Sk4f ExpandBilerp<Next>::kXOffsets = {0.0f, 1.0f, 0.0f, 1.0f}; |
mtklein
2016/02/17 20:25:09
This is all sort of awkward and boilerplate-y.
Le
herb_g
2016/02/17 23:40:43
Done.
|
+template <typename Next> |
+const Sk4f ExpandBilerp<Next>::kYOffsets = {0.0f, 0.0f, 1.0f, 1.0f}; |
+ |
+static PointProcessorInterface* choose_filter( |
+ BilerpProcessorInterface* next, |
+ SkFilterQuality filterQuailty, |
+ SkLinearBitmapPipeline::FilterStage* filterProc) { |
+ if (filterQuailty >= SkFilterQuality::kLow_SkFilterQuality) { |
mtklein
2016/02/17 20:25:09
Might wanna write as:
none -> skipped
else -
herb_g
2016/02/17 23:40:43
Done.
|
+ filterProc->Initialize<ExpandBilerp<>>(next); |
+ return filterProc->get(); |
+ } else { |
+ filterProc->Initialize<SkippedStage>(); |
+ return next; |
+ } |
+} |
+ |
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,20 @@ private: |
const Sk4i fWidth; |
}; |
+inline Sk4f bilerp4(SkPoint pt, Sk4f pixel00, Sk4f pixel01, |
mtklein
2016/02/17 20:25:09
It's a good habit to get into writing static on al
herb_g
2016/02/17 23:40:44
Done.
|
+ Sk4f pixel10, Sk4f pixel11) { |
+ Sk4f Xs{X(pt) - std::floor(X(pt))}; |
mtklein
2016/02/17 20:25:09
If we're using std:: stuff, might want to consider
herb_g
2016/02/17 23:40:43
Redid whole function.
|
+ Sk4f Ys{Y(pt) - std::floor(Y(pt))}; |
+ Sk4f XYs{Xs * Ys}; |
+ Sk4f sum = pixel11 * XYs; |
+ sum = sum + pixel01 * (Xs - XYs); |
+ sum = sum + pixel10 * (Ys - XYs); |
+ sum = sum + pixel00 * (Sk4f{1.0f} - Xs - Ys + XYs); |
mtklein
2016/02/17 20:25:09
This would be a really great place for an ASCII ar
herb_g
2016/02/17 23:40:43
Done.
|
+ 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 +420,20 @@ public: |
fNext->place4Pixels(px0, px1, px2, px3); |
} |
+ void bilerpList(Sk4fArg xs, Sk4fArg ys) override { |
+ SkPoint referencePoint{xs[0], ys[0]}; |
mtklein
2016/02/17 20:25:09
Do these all have the same fractional parts? I'm
herb_g
2016/02/17 23:40:43
Done.
|
+ Sk4f px0, px1, px2, px3; |
+ fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); |
+ Sk4f pixel = bilerp4(referencePoint, px0, px1, px2, px3); |
+ 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 +513,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 +527,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) { |