A new implementation of mask blurs, using separable X/Y passes. Disabled for now.
Review URL: https://codereview.appspot.com/6826086 git-svn-id: http://skia.googlecode.com/svn/trunk@6404 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
5596a69e9f
commit
71f0f34f7d
@ -12,6 +12,82 @@
|
||||
#include "SkTemplates.h"
|
||||
#include "SkEndian.h"
|
||||
|
||||
static int boxBlurX(const uint8_t* src, int src_row_bytes,
|
||||
uint8_t* dst, int dst_row_bytes,
|
||||
int radius, int width, int height)
|
||||
{
|
||||
int kernelSize = radius * 2 + 1;
|
||||
int border = SkMin32(width, radius * 2);
|
||||
uint32_t scale = (1 << 24) / kernelSize;
|
||||
for (int y = 0; y < height; ++y) {
|
||||
int sum = 0;
|
||||
uint8_t* dptr = dst + y * dst_row_bytes;
|
||||
const uint8_t* sptr = src + y * src_row_bytes - radius;
|
||||
for (int x = 0; x < border; ++x) {
|
||||
sum += *(sptr + radius);
|
||||
*dptr++ = (sum * scale) >> 24;
|
||||
sptr++;
|
||||
}
|
||||
for (int x = width; x < radius * 2; ++x) {
|
||||
*dptr++ = (sum * scale) >> 24;
|
||||
sptr++;
|
||||
}
|
||||
for (int x = radius * 2; x < width; ++x) {
|
||||
sum += *(sptr + radius);
|
||||
*dptr++ = (sum * scale) >> 24;
|
||||
sum -= *(sptr - radius);
|
||||
sptr++;
|
||||
}
|
||||
for (int x = 0; x < border; ++x) {
|
||||
*dptr++ = (sum * scale) >> 24;
|
||||
sum -= *(sptr - radius);
|
||||
sptr++;
|
||||
}
|
||||
SkASSERT(sum == 0);
|
||||
}
|
||||
return width + radius * 2;
|
||||
}
|
||||
|
||||
static int boxBlurY(const uint8_t* src, int src_row_bytes,
|
||||
uint8_t* dst, int dst_row_bytes,
|
||||
int radius, int width, int height)
|
||||
{
|
||||
int kernelSize = radius * 2 + 1;
|
||||
uint32_t scale = (1 << 24) / kernelSize;
|
||||
int border = SkMin32(height, radius * 2);
|
||||
for (int x = 0; x < width; ++x) {
|
||||
int sum = 0;
|
||||
uint8_t* dptr = dst + x;
|
||||
const uint8_t* sptr = src + x - radius * src_row_bytes;
|
||||
for (int y = 0; y < border; ++y) {
|
||||
sum += *(sptr + radius * src_row_bytes);
|
||||
*dptr = (sum * scale) >> 24;
|
||||
sptr += src_row_bytes;
|
||||
dptr += dst_row_bytes;
|
||||
}
|
||||
for (int y = height; y < radius * 2; ++y) {
|
||||
*dptr = (sum * scale) >> 24;
|
||||
sptr += src_row_bytes;
|
||||
dptr += dst_row_bytes;
|
||||
}
|
||||
for (int y = radius * 2; y < height; ++y) {
|
||||
sum += *(sptr + radius * src_row_bytes);
|
||||
*dptr = (sum * scale) >> 24;
|
||||
sum -= *(sptr - radius * src_row_bytes);
|
||||
sptr += src_row_bytes;
|
||||
dptr += dst_row_bytes;
|
||||
}
|
||||
for (int y = 0; y < border; ++y) {
|
||||
*dptr = (sum * scale) >> 24;
|
||||
sum -= *(sptr - radius * src_row_bytes);
|
||||
sptr += src_row_bytes;
|
||||
dptr += dst_row_bytes;
|
||||
}
|
||||
SkASSERT(sum == 0);
|
||||
}
|
||||
return height + radius * 2;
|
||||
}
|
||||
|
||||
// Unrolling the integer blur kernel seems to give us a ~15% speedup on Windows,
|
||||
// breakeven on Mac, and ~15% slowdown on Linux.
|
||||
// Reading a word at a time when bulding the sum buffer seems to give
|
||||
@ -553,7 +629,7 @@ void SkMask_FreeImage(uint8_t* image) {
|
||||
|
||||
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin)
|
||||
SkIPoint* margin, bool separable)
|
||||
{
|
||||
if (src.fFormat != SkMask::kA8_Format) {
|
||||
return false;
|
||||
@ -602,7 +678,20 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
||||
SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp);
|
||||
|
||||
// build the blurry destination
|
||||
{
|
||||
if (separable) {
|
||||
SkAutoTMalloc<uint8_t> tmpBuffer(dstSize);
|
||||
uint8_t* tp = tmpBuffer.get();
|
||||
int w = sw, h = sh;
|
||||
|
||||
w = boxBlurX(sp, src.fRowBytes, tp, dst->fRowBytes, rx, w, h);
|
||||
h = boxBlurY(tp, dst->fRowBytes, dp, dst->fRowBytes, ry, w, h);
|
||||
if (quality == kHigh_Quality) {
|
||||
w = boxBlurX(dp, dst->fRowBytes, tp, dst->fRowBytes, rx, w, h);
|
||||
h = boxBlurY(tp, dst->fRowBytes, dp, dst->fRowBytes, ry, w, h);
|
||||
w = boxBlurX(dp, dst->fRowBytes, tp, dst->fRowBytes, rx, w, h);
|
||||
h = boxBlurY(tp, dst->fRowBytes, dp, dst->fRowBytes, ry, w, h);
|
||||
}
|
||||
} else {
|
||||
const size_t storageW = sw + 2 * (passCount - 1) * rx + 1;
|
||||
const size_t storageH = sh + 2 * (passCount - 1) * ry + 1;
|
||||
SkAutoTMalloc<uint32_t> storage(storageW * storageH);
|
||||
@ -638,6 +727,7 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
||||
apply_kernel_interp(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh,
|
||||
outer_weight);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
dst->fImage = dp;
|
||||
@ -670,3 +760,16 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkBlurMask::BlurSeparable(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin)
|
||||
{
|
||||
return SkBlurMask::Blur(dst, src, radius, style, quality, margin, true);
|
||||
}
|
||||
|
||||
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin)
|
||||
{
|
||||
return SkBlurMask::Blur(dst, src, radius, style, quality, margin, false);
|
||||
}
|
||||
|
@ -31,6 +31,13 @@ public:
|
||||
static bool Blur(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin = NULL);
|
||||
static bool BlurSeparable(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin = NULL);
|
||||
private:
|
||||
static bool Blur(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin, bool separable);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user