Make SkBlurImageFilter capable of cropping during blur (raster path)
SkBlurImageFilter can currently only process a source image which is larger than or equal to the destination rect. If the source image (or crop rect) is smaller, it is padded out to dest size with transparent black via the 6-param version of applyCropRect(). Fixing this requires modifying all the flavours of RGBA box_blur() to accept a src crop rect. BUG=skia:4502, skia:4526 CQ_EXTRA_TRYBOTS=client.skia.android:Test-Android-GCC-Nexus5-CPU-NEON-Arm7-Release-Trybot;client.skia:Test-Ubuntu-GCC-GCE-CPU-AVX2-x86_64-Release-SKNX_NO_SIMD-Trybot Committed: https://skia.googlesource.com/skia/+/1b82ceb737c73327412f2e8a91748481e1aec9e4 Review URL: https://codereview.chromium.org/1415653003
This commit is contained in:
parent
9c58654fa2
commit
29a440d2d6
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>,
|
||||
|
Loading…
Reference in New Issue
Block a user