aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/SkOpts.h2
-rw-r--r--src/effects/SkBlurImageFilter.cpp44
-rw-r--r--src/opts/SkBlurImageFilter_opts.h87
3 files changed, 94 insertions, 39 deletions
diff --git a/src/core/SkOpts.h b/src/core/SkOpts.h
index 6fa1e46cd9..1b94126cf7 100644
--- a/src/core/SkOpts.h
+++ b/src/core/SkOpts.h
@@ -33,7 +33,7 @@ namespace SkOpts {
// May return nullptr if we haven't specialized the given Mode.
extern SkXfermode* (*create_xfermode)(const ProcCoeff&, SkXfermode::Mode);
- typedef void (*BoxBlur)(const SkPMColor*, int, SkPMColor*, int, int, int, int, int);
+ typedef void (*BoxBlur)(const SkPMColor*, int, const SkIRect& srcBounds, SkPMColor*, int, int, int, int, int);
extern BoxBlur box_blur_xx, box_blur_xy, box_blur_yx;
typedef void (*Morph)(const SkPMColor*, SkPMColor*, int, int, int, int, int);
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index c77a444da5..3f4c852c12 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -82,7 +82,7 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
}
SkIRect srcBounds, dstBounds;
- if (!this->applyCropRect(ctx, proxy, src, &srcOffset, &srcBounds, &src)) {
+ if (!this->applyCropRect(ctx, src, srcOffset, &dstBounds, &srcBounds)) {
return false;
}
@@ -91,13 +91,12 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
return false;
}
- SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(srcBounds.width(), srcBounds.height()));
+ SkAutoTUnref<SkBaseDevice> device(proxy->createDevice(dstBounds.width(), dstBounds.height()));
if (!device) {
return false;
}
*dst = device->accessBitmap(false);
SkAutoLockPixels alp_dst(*dst);
- dst->getBounds(&dstBounds);
SkVector sigma = mapSigma(fSigma, ctx.ctm());
@@ -112,8 +111,8 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
if (kernelSizeX == 0 && kernelSizeY == 0) {
src.copyTo(dst, dst->colorType());
- offset->fX = srcBounds.fLeft;
- offset->fY = srcBounds.fTop;
+ offset->fX = dstBounds.x() + srcOffset.x();
+ offset->fY = dstBounds.y() + srcOffset.y();
return true;
}
@@ -124,13 +123,16 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
SkBitmap temp = tempDevice->accessBitmap(false);
SkAutoLockPixels alpTemp(temp);
- offset->fX = srcBounds.fLeft;
- offset->fY = srcBounds.fTop;
- srcBounds.offset(-srcOffset);
- const SkPMColor* s = src.getAddr32(srcBounds.left(), srcBounds.top());
+ offset->fX = dstBounds.fLeft;
+ offset->fY = dstBounds.fTop;
SkPMColor* t = temp.getAddr32(0, 0);
SkPMColor* d = dst->getAddr32(0, 0);
int w = dstBounds.width(), h = dstBounds.height();
+ const SkPMColor* s = src.getAddr32(srcBounds.x() - srcOffset.x(), srcBounds.y() - srcOffset.y());
+ srcBounds.offset(-dstBounds.x(), -dstBounds.y());
+ dstBounds.offset(-dstBounds.x(), -dstBounds.y());
+ SkIRect srcBoundsT = SkIRect::MakeLTRB(srcBounds.top(), srcBounds.left(), srcBounds.bottom(), srcBounds.right());
+ SkIRect dstBoundsT = SkIRect::MakeWH(dstBounds.height(), dstBounds.width());
int sw = src.rowBytesAsPixels();
/**
@@ -152,20 +154,20 @@ bool SkBlurImageFilter::onFilterImage(Proxy* proxy,
* images, and all memory reads are contiguous.
*/
if (kernelSizeX > 0 && kernelSizeY > 0) {
- SkOpts::box_blur_xx(s, sw, t, kernelSizeX, lowOffsetX, highOffsetX, w, h);
- SkOpts::box_blur_xx(t, w, d, kernelSizeX, highOffsetX, lowOffsetX, w, h);
- SkOpts::box_blur_xy(d, w, t, kernelSizeX3, highOffsetX, highOffsetX, w, h);
- SkOpts::box_blur_xx(t, h, d, kernelSizeY, lowOffsetY, highOffsetY, h, w);
- SkOpts::box_blur_xx(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h, w);
- SkOpts::box_blur_xy(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h, w);
+ SkOpts::box_blur_xx(s, sw, srcBounds, t, kernelSizeX, lowOffsetX, highOffsetX, w, h);
+ SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX, highOffsetX, lowOffsetX, w, h);
+ SkOpts::box_blur_xy(d, w, dstBounds, t, kernelSizeX3, highOffsetX, highOffsetX, w, h);
+ SkOpts::box_blur_xx(t, h, dstBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w);
+ SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w);
+ SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w);
} else if (kernelSizeX > 0) {
- SkOpts::box_blur_xx(s, sw, d, kernelSizeX, lowOffsetX, highOffsetX, w, h);
- SkOpts::box_blur_xx(d, w, t, kernelSizeX, highOffsetX, lowOffsetX, w, h);
- SkOpts::box_blur_xx(t, w, d, kernelSizeX3, highOffsetX, highOffsetX, w, h);
+ SkOpts::box_blur_xx(s, sw, srcBounds, d, kernelSizeX, lowOffsetX, highOffsetX, w, h);
+ SkOpts::box_blur_xx(d, w, dstBounds, t, kernelSizeX, highOffsetX, lowOffsetX, w, h);
+ SkOpts::box_blur_xx(t, w, dstBounds, d, kernelSizeX3, highOffsetX, highOffsetX, w, h);
} else if (kernelSizeY > 0) {
- SkOpts::box_blur_yx(s, sw, d, kernelSizeY, lowOffsetY, highOffsetY, h, w);
- SkOpts::box_blur_xx(d, h, t, kernelSizeY, highOffsetY, lowOffsetY, h, w);
- SkOpts::box_blur_xy(t, h, d, kernelSizeY3, highOffsetY, highOffsetY, h, w);
+ SkOpts::box_blur_yx(s, sw, srcBoundsT, d, kernelSizeY, lowOffsetY, highOffsetY, h, w);
+ SkOpts::box_blur_xx(d, h, dstBoundsT, t, kernelSizeY, highOffsetY, lowOffsetY, h, w);
+ SkOpts::box_blur_xy(t, h, dstBoundsT, d, kernelSizeY3, highOffsetY, highOffsetY, h, w);
}
return true;
}
diff --git a/src/opts/SkBlurImageFilter_opts.h b/src/opts/SkBlurImageFilter_opts.h
index 720130b1ec..8d22391b5f 100644
--- a/src/opts/SkBlurImageFilter_opts.h
+++ b/src/opts/SkBlurImageFilter_opts.h
@@ -84,8 +84,8 @@ static inline __m128i mullo_epi32(__m128i a, __m128i b) {
// Fast path for kernel sizes between 2 and 127, working on two rows at a time.
template<BlurDirection srcDirection, BlurDirection dstDirection>
-void box_blur_double(const SkPMColor** src, int srcStride, SkPMColor** dst, int kernelSize,
- int leftOffset, int rightOffset, int width, int* height) {
+int box_blur_double(const SkPMColor** src, int srcStride, const SkIRect& srcBounds, SkPMColor** dst, int kernelSize,
+ int leftOffset, int rightOffset, int width, int height) {
// Load 2 pixels from adjacent rows.
auto load_2_pixels = [&](const SkPMColor* s) {
if (srcDirection == BlurDirection::kX) {
@@ -99,16 +99,21 @@ void box_blur_double(const SkPMColor** src, int srcStride, SkPMColor** dst, int
return vld1_u8((uint8_t*)s);
}
};
- int incrementStart = SkMax32(-rightOffset - 1, -width);
- int incrementEnd = SkMax32(width - rightOffset - 1, 0);
- int decrementStart = SkMin32(leftOffset, width);
+ int left = srcBounds.left();
+ int right = srcBounds.right();
+ int top = srcBounds.top();
+ int bottom = srcBounds.bottom();
+ int incrementStart = SkMax32(left - rightOffset - 1, left - right);
+ int incrementEnd = SkMax32(right - rightOffset - 1, 0);
+ int decrementStart = SkMin32(left + leftOffset, width);
+ int decrementEnd = SkMin32(right + leftOffset, width);
const int srcStrideX = srcDirection == BlurDirection::kX ? 1 : srcStride;
- const int dstStrideX = dstDirection == BlurDirection::kX ? 1 : *height;
+ const int dstStrideX = dstDirection == BlurDirection::kX ? 1 : height;
const int srcStrideY = srcDirection == BlurDirection::kX ? srcStride : 1;
const int dstStrideY = dstDirection == BlurDirection::kX ? width : 1;
const uint16x8_t scale = vdupq_n_u16((1 << 15) / kernelSize);
- for (; *height >= 2; *height -= 2) {
+ for (; bottom - top >= 2; top += 2) {
uint16x8_t sum = vdupq_n_u16(0);
const SkPMColor* lptr = *src;
const SkPMColor* rptr = *src;
@@ -118,6 +123,12 @@ void box_blur_double(const SkPMColor** src, int srcStride, SkPMColor** dst, int
INCREMENT_SUMS_DOUBLE(rptr);
rptr += srcStrideX;
}
+ // Clear to zero when sampling to the left our domain. "sum" is zero here because we
+ // initialized it above, and the preceeding loop has no effect in this case.
+ for (x = 0; x < incrementStart; ++x) {
+ STORE_SUMS_DOUBLE
+ dptr += dstStrideX;
+ }
for (; x < decrementStart && x < incrementEnd; ++x) {
STORE_SUMS_DOUBLE
dptr += dstStrideX;
@@ -136,15 +147,22 @@ void box_blur_double(const SkPMColor** src, int srcStride, SkPMColor** dst, int
STORE_SUMS_DOUBLE
dptr += dstStrideX;
}
- for (; x < width; ++x) {
+ for (; x < decrementEnd; ++x) {
STORE_SUMS_DOUBLE
dptr += dstStrideX;
DECREMENT_SUMS_DOUBLE(lptr);
lptr += srcStrideX;
}
+ // Clear to zero when sampling to the right of our domain. "sum" is zero here because we
+ // added on then subtracted off all of the pixels, leaving zero.
+ for (; x < width; ++x) {
+ STORE_SUMS_DOUBLE
+ dptr += dstStrideX;
+ }
*src += srcStrideY * 2;
*dst += dstStrideY * 2;
}
+ return top;
}
// ARGB -> 0A0R 0G0B
@@ -166,8 +184,9 @@ static inline uint16x4_t expand(SkPMColor p) {
#define DOUBLE_ROW_OPTIMIZATION \
if (1 < kernelSize && kernelSize < 128) { \
- box_blur_double<srcDirection, dstDirection>(&src, srcStride, &dst, kernelSize, \
- leftOffset, rightOffset, width, &height); \
+ top = box_blur_double<srcDirection, dstDirection>(&src, srcStride, srcBounds, &dst, \
+ kernelSize, leftOffset, rightOffset, \
+ width, height); \
}
#else // Neither NEON nor >=SSE2.
@@ -200,11 +219,16 @@ static inline uint16x4_t expand(SkPMColor p) {
}
template<BlurDirection srcDirection, BlurDirection dstDirection>
-static void box_blur(const SkPMColor* src, int srcStride, SkPMColor* dst, int kernelSize,
- int leftOffset, int rightOffset, int width, int height) {
- int incrementStart = SkMax32(-rightOffset - 1, -width);
- int incrementEnd = SkMax32(width - rightOffset - 1, 0);
- int decrementStart = SkMin32(leftOffset, width);
+static void box_blur(const SkPMColor* src, int srcStride, const SkIRect& srcBounds, SkPMColor* dst,
+ int kernelSize, int leftOffset, int rightOffset, int width, int height) {
+ int left = srcBounds.left();
+ int right = srcBounds.right();
+ int top = srcBounds.top();
+ int bottom = srcBounds.bottom();
+ int incrementStart = SkMax32(left - rightOffset - 1, left - right);
+ int incrementEnd = SkMax32(right - rightOffset - 1, 0);
+ int decrementStart = SkMin32(left + leftOffset, width);
+ int decrementEnd = SkMin32(right + leftOffset, width);
int srcStrideX = srcDirection == BlurDirection::kX ? 1 : srcStride;
int dstStrideX = dstDirection == BlurDirection::kX ? 1 : height;
int srcStrideY = srcDirection == BlurDirection::kX ? srcStride : 1;
@@ -212,9 +236,19 @@ static void box_blur(const SkPMColor* src, int srcStride, SkPMColor* dst, int ke
INIT_SCALE
INIT_HALF
+ // Clear to zero when sampling above our domain.
+ for (int y = 0; y < top; y++) {
+ SkColor* dptr = dst;
+ for (int x = 0; x < width; ++x) {
+ *dptr = 0;
+ dptr += dstStrideX;
+ }
+ dst += dstStrideY;
+ }
+
DOUBLE_ROW_OPTIMIZATION
- for (int y = 0; y < height; ++y) {
+ for (int y = top; y < bottom; ++y) {
INIT_SUMS
const SkPMColor* lptr = src;
const SkPMColor* rptr = src;
@@ -225,6 +259,11 @@ static void box_blur(const SkPMColor* src, int srcStride, SkPMColor* dst, int ke
rptr += srcStrideX;
PREFETCH_RPTR
}
+ // Clear to zero when sampling to the left of our domain.
+ for (x = 0; x < incrementStart; ++x) {
+ *dptr = 0;
+ dptr += dstStrideX;
+ }
for (; x < decrementStart && x < incrementEnd; ++x) {
STORE_SUMS
dptr += dstStrideX;
@@ -245,15 +284,29 @@ static void box_blur(const SkPMColor* src, int srcStride, SkPMColor* dst, int ke
STORE_SUMS
dptr += dstStrideX;
}
- for (; x < width; ++x) {
+ for (; x < decrementEnd; ++x) {
STORE_SUMS
dptr += dstStrideX;
DECREMENT_SUMS(*lptr);
lptr += srcStrideX;
}
+ // Clear to zero when sampling to the right of our domain.
+ for (; x < width; ++x) {
+ *dptr = 0;
+ dptr += dstStrideX;
+ }
src += srcStrideY;
dst += dstStrideY;
}
+ // Clear to zero when sampling below our domain.
+ for (int y = bottom; y < height; ++y) {
+ SkColor* dptr = dst;
+ for (int x = 0; x < width; ++x) {
+ *dptr = 0;
+ dptr += dstStrideX;
+ }
+ dst += dstStrideY;
+ }
}
static auto box_blur_xx = &box_blur<BlurDirection::kX, BlurDirection::kX>,