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

Unified Diff: src/core/SkLinearBitmapPipeline.cpp

Issue 2134893002: Redo Tiling (Closed) Base URL: https://skia.googlesource.com/skia.git@reduce-LBP-sample
Patch Set: Document bug. Created 4 years, 5 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') | src/core/SkLinearBitmapPipeline_core.h » ('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 088e829345f016f3b06a84dc83cdef2f13dcbef2..44a3d77195ef8855130c0775670c76e40e501f11 100644
--- a/src/core/SkLinearBitmapPipeline.cpp
+++ b/src/core/SkLinearBitmapPipeline.cpp
@@ -165,15 +165,14 @@ static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix(
// Tile Stage
template<typename XStrategy, typename YStrategy, typename Next>
-class NearestTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
+class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
public:
- template <typename... Args>
- NearestTileStage(Next* next, SkISize dimensions)
+ CombinedTileStage(Next* next, SkISize dimensions)
: fNext{next}
, fXStrategy{dimensions.width()}
, fYStrategy{dimensions.height()}{ }
- NearestTileStage(Next* next, const NearestTileStage& stage)
+ CombinedTileStage(Next* next, const CombinedTileStage& stage)
: fNext{next}
, fXStrategy{stage.fXStrategy}
, fYStrategy{stage.fYStrategy} { }
@@ -195,187 +194,52 @@ public:
SkASSERT(!span.isEmpty());
SkPoint start; SkScalar length; int count;
std::tie(start, length, count) = span;
- SkScalar x = X(start);
- SkScalar y = fYStrategy.tileY(Y(start));
- Span yAdjustedSpan{{x, y}, length, count};
- if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
- span_fallback(span, this);
- }
- }
-
-private:
- Next* const fNext;
- XStrategy fXStrategy;
- YStrategy fYStrategy;
-};
-
-template<typename XStrategy, typename YStrategy, typename Next>
-class BilerpTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
-public:
- template <typename... Args>
- BilerpTileStage(Next* next, SkISize dimensions)
- : fNext{next}
- , fXMax(dimensions.width())
- , fYMax(dimensions.height())
- , fXStrategy{dimensions.width()}
- , fYStrategy{dimensions.height()} { }
-
- BilerpTileStage(Next* next, const BilerpTileStage& stage)
- : fNext{next}
- , fXMax{stage.fXMax}
- , fYMax{stage.fYMax}
- , fXStrategy{stage.fXStrategy}
- , fYStrategy{stage.fYStrategy} { }
- void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
- fXStrategy.tileXPoints(&xs);
- fYStrategy.tileYPoints(&ys);
- // TODO: check to see if xs and ys are in range then just call pointListFew on next.
- if (n >= 1) this->bilerpPoint(xs[0], ys[0]);
- if (n >= 2) this->bilerpPoint(xs[1], ys[1]);
- if (n >= 3) this->bilerpPoint(xs[2], ys[2]);
- }
-
- void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
- fXStrategy.tileXPoints(&xs);
- fYStrategy.tileYPoints(&ys);
- // TODO: check to see if xs and ys are in range then just call pointList4 on next.
- this->bilerpPoint(xs[0], ys[0]);
- this->bilerpPoint(xs[1], ys[1]);
- this->bilerpPoint(xs[2], ys[2]);
- this->bilerpPoint(xs[3], ys[3]);
- }
-
- struct Wrapper {
- void pointSpan(Span span) {
- processor->breakIntoEdges(span);
- }
-
- void repeatSpan(Span span, int32_t repeatCount) {
- while (repeatCount --> 0) {
- processor->pointSpan(span);
- }
+ if (span.count() == 1) {
+ // DANGER:
+ // The explicit casts from float to Sk4f are not usually necessary, but are here to
+ // work around an MSVC 2015u2 c++ code generation bug. This is tracked using skia bug
+ // 5566.
+ this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()});
+ return;
}
- BilerpTileStage* processor;
- };
-
- // The span you pass must not be empty.
- void pointSpan(Span span) override {
- SkASSERT(!span.isEmpty());
+ SkScalar x = X(start);
+ SkScalar y = fYStrategy.tileY(Y(start));
+ Span yAdjustedSpan{{x, y}, length, count};
- Wrapper wrapper = {this};
- if (!fXStrategy.maybeProcessSpan(span, &wrapper)) {
+ if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
span_fallback(span, this);
}
}
private:
- void bilerpPoint(SkScalar x, SkScalar y) {
- Sk4f txs = Sk4f{x} + Sk4f{-0.5f, 0.5f, -0.5f, 0.5f};
- Sk4f tys = Sk4f{y} + Sk4f{-0.5f, -0.5f, 0.5f, 0.5f};
- fXStrategy.tileXPoints(&txs);
- fYStrategy.tileYPoints(&tys);
- fNext->bilerpEdge(txs, tys);
- }
-
- void handleEdges(Span span, SkScalar dx) {
- SkPoint start; SkScalar length; int count;
- std::tie(start, length, count) = span;
- SkScalar x = X(start);
- SkScalar y = Y(start);
- SkScalar tiledY = fYStrategy.tileY(y);
- while (count > 0) {
- this->bilerpPoint(x, tiledY);
- x += dx;
- count -= 1;
- }
- }
-
- void yProcessSpan(Span span) {
- SkScalar tiledY = fYStrategy.tileY(span.startY());
- if (0.5f <= tiledY && tiledY < fYMax - 0.5f ) {
- Span tiledSpan{{span.startX(), tiledY}, span.length(), span.count()};
- fNext->pointSpan(tiledSpan);
- } else {
- // Convert to the Y0 bilerp sample set by shifting by -0.5f. Then tile that new y
- // value and shift it back resulting in the working Y0. Do the same thing with Y1 but
- // in the opposite direction.
- SkScalar y0 = fYStrategy.tileY(span.startY() - 0.5f) + 0.5f;
- SkScalar y1 = fYStrategy.tileY(span.startY() + 0.5f) - 0.5f;
- Span newSpan{{span.startX(), y0}, span.length(), span.count()};
- fNext->bilerpSpan(newSpan, y1);
- }
- }
- void breakIntoEdges(Span span) {
- if (span.count() == 1) {
- this->bilerpPoint(span.startX(), span.startY());
- } else if (span.length() == 0) {
- yProcessSpan(span);
- } else {
- SkScalar dx = span.length() / (span.count() - 1);
- if (span.length() > 0) {
- Span leftBorder = span.breakAt(0.5f, dx);
- if (!leftBorder.isEmpty()) {
- this->handleEdges(leftBorder, dx);
- }
- Span center = span.breakAt(fXMax - 0.5f, dx);
- if (!center.isEmpty()) {
- this->yProcessSpan(center);
- }
-
- if (!span.isEmpty()) {
- this->handleEdges(span, dx);
- }
- } else {
- Span center = span.breakAt(fXMax + 0.5f, dx);
- if (!span.isEmpty()) {
- this->handleEdges(span, dx);
- }
- Span leftEdge = center.breakAt(0.5f, dx);
- if (!center.isEmpty()) {
- this->yProcessSpan(center);
- }
- if (!leftEdge.isEmpty()) {
- this->handleEdges(leftEdge, dx);
- }
-
- }
- }
- }
-
Next* const fNext;
- SkScalar fXMax;
- SkScalar fYMax;
XStrategy fXStrategy;
YStrategy fYStrategy;
};
-template <typename XStrategy, typename YStrategy, typename Next>
-void make_tile_stage(
- SkFilterQuality filterQuality, SkISize dimensions,
- Next* next, SkLinearBitmapPipeline::TileStage* tileStage) {
- if (filterQuality == kNone_SkFilterQuality) {
- tileStage->initStage<NearestTileStage<XStrategy, YStrategy, Next>>(next, dimensions);
- } else {
- tileStage->initStage<BilerpTileStage<XStrategy, YStrategy, Next>>(next, dimensions);
- }
-}
-template <typename XStrategy>
+template <typename XStrategy, typename Next>
void choose_tiler_ymode(
SkShader::TileMode yMode, SkFilterQuality filterQuality, SkISize dimensions,
- SkLinearBitmapPipeline::SampleProcessorInterface* next,
+ Next* next,
SkLinearBitmapPipeline::TileStage* tileStage) {
switch (yMode) {
- case SkShader::kClamp_TileMode:
- make_tile_stage<XStrategy, YClampStrategy>(filterQuality, dimensions, next, tileStage);
+ case SkShader::kClamp_TileMode: {
+ using Tiler = CombinedTileStage<XStrategy, YClampStrategy, Next>;
+ tileStage->initStage<Tiler>(next, dimensions);
break;
- case SkShader::kRepeat_TileMode:
- make_tile_stage<XStrategy, YRepeatStrategy>(filterQuality, dimensions, next, tileStage);
+ }
+ case SkShader::kRepeat_TileMode: {
+ using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, Next>;
+ tileStage->initStage<Tiler>(next, dimensions);
break;
- case SkShader::kMirror_TileMode:
- make_tile_stage<XStrategy, YMirrorStrategy>(filterQuality, dimensions, next, tileStage);
+ }
+ case SkShader::kMirror_TileMode: {
+ using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, Next>;
+ tileStage->initStage<Tiler>(next, dimensions);
break;
+ }
}
};
@@ -467,10 +331,6 @@ public:
fDest = dest;
}
- void SK_VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override { SkFAIL("Not Implemented"); }
-
- void bilerpSpan(Span span, SkScalar y) override { SkFAIL("Not Implemented"); }
-
void setDestination(void* dst, int count) override {
fDest = static_cast<uint32_t*>(dst);
fEnd = fDest + count;
@@ -538,10 +398,6 @@ public:
SkASSERT(fDest <= fEnd);
}
- void SK_VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override { SkFAIL("Not Implemented"); }
-
- void bilerpSpan(Span span, SkScalar y) override { SkFAIL("Not Implemented"); }
-
void setDestination(void* dst, int count) override {
SkASSERT(count > 0);
fDest = static_cast<uint32_t*>(dst);
@@ -582,12 +438,9 @@ static SkLinearBitmapPipeline::PixelAccessorInterface* choose_specific_accessor(
}
}
-template<template <typename, typename> class Sampler>
-static SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler_base(
- Blender* next,
+static SkLinearBitmapPipeline::PixelAccessorInterface* choose_pixel_accessor(
const SkPixmap& srcPixmap,
const SkColor A8TintColor,
- SkLinearBitmapPipeline::SampleStage* sampleStage,
SkLinearBitmapPipeline::Accessor* accessor)
{
const SkImageInfo& imageInfo = srcPixmap.info();
@@ -629,19 +482,19 @@ static SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler_ba
break;
}
- using S = Sampler<PixelAccessorShim, Blender>;
- sampleStage->initStage<S>(next, pixelAccessor);
- return sampleStage->get();
+ return pixelAccessor;
}
SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler(
Blender* next,
SkFilterQuality filterQuality,
+ SkShader::TileMode xTile, SkShader::TileMode yTile,
const SkPixmap& srcPixmap,
const SkColor A8TintColor,
SkLinearBitmapPipeline::SampleStage* sampleStage,
SkLinearBitmapPipeline::Accessor* accessor) {
const SkImageInfo& imageInfo = srcPixmap.info();
+ SkISize dimensions = imageInfo.dimensions();
// Special case samplers with fully expanded templates
if (imageInfo.gammaCloseToSRGB()) {
@@ -670,14 +523,14 @@ SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler(
using S =
BilerpSampler<
PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
- sampleStage->initStage<S>(next, srcPixmap);
+ sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
return sampleStage->get();
}
case kIndex_8_SkColorType: {
using S =
BilerpSampler<
PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
- sampleStage->initStage<S>(next, srcPixmap);
+ sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
return sampleStage->get();
}
default:
@@ -686,14 +539,16 @@ SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler(
}
}
+ auto pixelAccessor = choose_pixel_accessor(srcPixmap, A8TintColor, accessor);
// General cases.
if (filterQuality == kNone_SkFilterQuality) {
- return choose_pixel_sampler_base<NearestNeighborSampler>(
- next, srcPixmap, A8TintColor, sampleStage, accessor);
+ using S = NearestNeighborSampler<PixelAccessorShim, Blender>;
+ sampleStage->initStage<S>(next, pixelAccessor);
} else {
- return choose_pixel_sampler_base<BilerpSampler>(
- next, srcPixmap, A8TintColor, sampleStage, accessor);
+ using S = BilerpSampler<PixelAccessorShim, Blender>;
+ sampleStage->initStage<S>(next, dimensions, xTile, yTile, pixelAccessor);
}
+ return sampleStage->get();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -705,17 +560,17 @@ public:
SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {}
void SK_VECTORCALL blendPixel(Sk4f pixel) override {
SkASSERT(fDst + 1 <= fEnd );
- SrcPixel(fDst, pixel, 0);
+ this->srcPixel(fDst, pixel, 0);
fDst += 1;
}
void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
SkASSERT(fDst + 4 <= fEnd);
SkPM4f* dst = fDst;
- SrcPixel(dst, p0, 0);
- SrcPixel(dst, p1, 1);
- SrcPixel(dst, p2, 2);
- SrcPixel(dst, p3, 3);
+ this->srcPixel(dst, p0, 0);
+ this->srcPixel(dst, p1, 1);
+ this->srcPixel(dst, p2, 2);
+ this->srcPixel(dst, p3, 3);
fDst += 4;
}
@@ -725,7 +580,9 @@ public:
}
private:
- void SK_VECTORCALL SrcPixel(SkPM4f* dst, Sk4f pixel, int index) {
+ void SK_VECTORCALL srcPixel(SkPM4f* dst, Sk4f pixel, int index) {
+ check_pixel(pixel);
+
Sk4f newPixel = pixel;
if (alphaType == kUnpremul_SkAlphaType) {
newPixel = Premultiply(pixel);
@@ -797,7 +654,8 @@ SkLinearBitmapPipeline::SkLinearBitmapPipeline(
// identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
auto blenderStage = choose_blender_for_shading(alphaType, postAlpha, &fBlenderStage);
auto samplerStage = choose_pixel_sampler(
- blenderStage, filterQuality, srcPixmap, paintColor, &fSampleStage, &fAccessor);
+ blenderStage, filterQuality, xTile, yTile,
+ srcPixmap, paintColor, &fSampleStage, &fAccessor);
auto tilerStage = choose_tiler(samplerStage, dimensions, xTile, yTile,
filterQuality, dx, &fTileStage);
fFirstStage = choose_matrix(tilerStage, adjustedInverse, &fMatrixStage);
« no previous file with comments | « src/core/SkLinearBitmapPipeline.h ('k') | src/core/SkLinearBitmapPipeline_core.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698