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 "SkTemplates.h"
|
||||||
#include "SkEndian.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,
|
// Unrolling the integer blur kernel seems to give us a ~15% speedup on Windows,
|
||||||
// breakeven on Mac, and ~15% slowdown on Linux.
|
// breakeven on Mac, and ~15% slowdown on Linux.
|
||||||
// Reading a word at a time when bulding the sum buffer seems to give
|
// 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,
|
bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
||||||
SkScalar radius, Style style, Quality quality,
|
SkScalar radius, Style style, Quality quality,
|
||||||
SkIPoint* margin)
|
SkIPoint* margin, bool separable)
|
||||||
{
|
{
|
||||||
if (src.fFormat != SkMask::kA8_Format) {
|
if (src.fFormat != SkMask::kA8_Format) {
|
||||||
return false;
|
return false;
|
||||||
@ -602,7 +678,20 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
|||||||
SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp);
|
SkAutoTCallVProc<uint8_t, SkMask_FreeImage> autoCall(dp);
|
||||||
|
|
||||||
// build the blurry destination
|
// 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 storageW = sw + 2 * (passCount - 1) * rx + 1;
|
||||||
const size_t storageH = sh + 2 * (passCount - 1) * ry + 1;
|
const size_t storageH = sh + 2 * (passCount - 1) * ry + 1;
|
||||||
SkAutoTMalloc<uint32_t> storage(storageW * storageH);
|
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,
|
apply_kernel_interp(dp, rx, ry, sumBuffer, tmp_sw, tmp_sh,
|
||||||
outer_weight);
|
outer_weight);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
dst->fImage = dp;
|
dst->fImage = dp;
|
||||||
@ -670,3 +760,16 @@ bool SkBlurMask::Blur(SkMask* dst, const SkMask& src,
|
|||||||
return true;
|
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,
|
static bool Blur(SkMask* dst, const SkMask& src,
|
||||||
SkScalar radius, Style style, Quality quality,
|
SkScalar radius, Style style, Quality quality,
|
||||||
SkIPoint* margin = NULL);
|
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
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user