diff options
-rw-r--r-- | src/core/SkOpts.h | 2 | ||||
-rw-r--r-- | src/effects/SkBlurImageFilter.cpp | 44 | ||||
-rw-r--r-- | src/opts/SkBlurImageFilter_opts.h | 87 |
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>, |