Plumb fast rectangle blur code into the skia mask filter
Review URL: https://codereview.chromium.org/12387099 git-svn-id: http://skia.googlecode.com/svn/trunk@8074 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
ed268bfed3
commit
7c5d7b7813
@ -1185,23 +1185,28 @@ static float gaussianIntegral(float x) {
|
||||
return 0.4375f + (-x3 / 6.0f - 3.0f * x2 * 0.25f - 1.125f * x);
|
||||
}
|
||||
|
||||
/*
|
||||
compute_profile allocates and fills in an array of floating
|
||||
// Compute the size of the array allocated for the profile.
|
||||
|
||||
static int compute_profile_size(SkScalar radius) {
|
||||
return SkScalarRoundToInt(radius * 3);
|
||||
|
||||
}
|
||||
|
||||
/* compute_profile allocates and fills in an array of floating
|
||||
point values between 0 and 255 for the profile signature of
|
||||
a blurred half-plane with the given blur radius. Since we're
|
||||
going to be doing screened multiplications (i.e., 1 - (1-x)(1-y))
|
||||
all the time, we actually fill in the profile pre-inverted
|
||||
(already done 255-x).
|
||||
|
||||
The function returns the size of the array allocated for the
|
||||
profile. It's the responsibility of the caller to delete the
|
||||
It's the responsibility of the caller to delete the
|
||||
memory returned in profile_out.
|
||||
*/
|
||||
|
||||
static int compute_profile(SkScalar radius, unsigned int **profile_out) {
|
||||
int size = SkScalarRoundToInt(radius * 3);
|
||||
static void compute_profile(SkScalar radius, unsigned int **profile_out) {
|
||||
int size = compute_profile_size(radius);
|
||||
|
||||
int center = size >> 1;
|
||||
|
||||
unsigned int *profile = SkNEW_ARRAY(unsigned int, size);
|
||||
|
||||
float invr = 1.f/radius;
|
||||
@ -1214,7 +1219,6 @@ static int compute_profile(SkScalar radius, unsigned int **profile_out) {
|
||||
}
|
||||
|
||||
*profile_out = profile;
|
||||
return size;
|
||||
}
|
||||
|
||||
// TODO MAYBE: Maintain a profile cache to avoid recomputing this for
|
||||
@ -1236,19 +1240,16 @@ static inline unsigned int profile_lookup( unsigned int *profile, int loc, int b
|
||||
|
||||
bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
|
||||
SkScalar provided_radius, Style style,
|
||||
SkIPoint *margin) {
|
||||
SkIPoint *margin, SkMask::CreateMode createMode) {
|
||||
int profile_size;
|
||||
unsigned int *profile;
|
||||
|
||||
float radius = SkScalarToFloat( SkScalarMul( provided_radius, kBlurRadiusFudgeFactor ) );
|
||||
float radius = SkScalarToFloat(SkScalarMul(provided_radius, kBlurRadiusFudgeFactor));
|
||||
|
||||
// adjust blur radius to match interpretation from boxfilter code
|
||||
radius = (radius + .5f) *2.f;
|
||||
|
||||
profile_size = compute_profile( radius, &profile );
|
||||
|
||||
SkAutoTDeleteArray<unsigned int> ada(profile);
|
||||
radius = (radius + .5f) * 2.f;
|
||||
|
||||
profile_size = compute_profile_size(radius);
|
||||
|
||||
int pad = profile_size/2;
|
||||
if (margin) {
|
||||
margin->set( pad, pad );
|
||||
@ -1259,20 +1260,35 @@ bool SkBlurMask::BlurRect(SkMask *dst, const SkRect &src,
|
||||
int shadow_right = (int)(src.width()) + pad;
|
||||
int shadow_bottom = (int)(src.height()) + pad;
|
||||
|
||||
dst->fBounds.set(shadow_left, shadow_top, shadow_right, shadow_bottom);
|
||||
dst->fBounds.set(shadow_left + src.fLeft,
|
||||
shadow_top + src.fTop,
|
||||
shadow_right + src.fRight,
|
||||
shadow_bottom + src.fBottom);
|
||||
|
||||
dst->fRowBytes = dst->fBounds.width();
|
||||
dst->fFormat = SkMask::kA8_Format;
|
||||
dst->fImage = NULL;
|
||||
|
||||
|
||||
int sw = SkScalarFloorToInt(src.width());
|
||||
int sh = SkScalarFloorToInt(src.height());
|
||||
|
||||
if (createMode == SkMask::kJustComputeBounds_CreateMode) {
|
||||
if (style == kInner_Style) {
|
||||
dst->fBounds.set(0, 0, sw, sh); // restore trimmed bounds
|
||||
dst->fRowBytes = sw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
unsigned int *profile = NULL;
|
||||
|
||||
compute_profile(radius, &profile);
|
||||
SkAutoTDeleteArray<unsigned int> ada(profile);
|
||||
|
||||
size_t dstSize = dst->computeImageSize();
|
||||
if (0 == dstSize) {
|
||||
return false; // too big to allocate, abort
|
||||
}
|
||||
|
||||
int sw = SkScalarFloorToInt(src.width());
|
||||
int sh = SkScalarFloorToInt(src.height());
|
||||
|
||||
uint8_t* dp = SkMask::AllocImage(dstSize);
|
||||
|
||||
dst->fImage = dp;
|
||||
|
@ -11,6 +11,7 @@
|
||||
#define SkBlurMask_DEFINED
|
||||
|
||||
#include "SkShader.h"
|
||||
#include "SkMask.h"
|
||||
|
||||
class SkBlurMask {
|
||||
public:
|
||||
@ -30,7 +31,8 @@ public:
|
||||
|
||||
static bool BlurRect(SkMask *dst, const SkRect &src,
|
||||
SkScalar radius, Style style,
|
||||
SkIPoint *margin = NULL);
|
||||
SkIPoint *margin = NULL,
|
||||
SkMask::CreateMode createMode=SkMask::kComputeBoundsAndRenderImage_CreateMode);
|
||||
static bool Blur(SkMask* dst, const SkMask& src,
|
||||
SkScalar radius, Style style, Quality quality,
|
||||
SkIPoint* margin = NULL);
|
||||
|
@ -10,6 +10,9 @@
|
||||
#include "SkBlurMask.h"
|
||||
#include "SkFlattenableBuffers.h"
|
||||
#include "SkMaskFilter.h"
|
||||
#include "SkBounder.h"
|
||||
#include "SkRasterClip.h"
|
||||
#include "SkRTConf.h"
|
||||
|
||||
class SkBlurMaskFilterImpl : public SkMaskFilter {
|
||||
public:
|
||||
@ -20,6 +23,7 @@ public:
|
||||
virtual SkMask::Format getFormat() const SK_OVERRIDE;
|
||||
virtual bool filterMask(SkMask* dst, const SkMask& src, const SkMatrix&,
|
||||
SkIPoint* margin) const SK_OVERRIDE;
|
||||
|
||||
virtual BlurType asABlur(BlurInfo*) const SK_OVERRIDE;
|
||||
virtual void computeFastBounds(const SkRect&, SkRect*) const SK_OVERRIDE;
|
||||
|
||||
@ -29,6 +33,9 @@ protected:
|
||||
virtual FilterReturn filterRectsToNine(const SkRect[], int count, const SkMatrix&,
|
||||
const SkIRect& clipBounds,
|
||||
NinePatch*) const SK_OVERRIDE;
|
||||
|
||||
bool filterRectMask(SkMask* dstM, const SkRect& r, const SkMatrix& matrix,
|
||||
SkIPoint* margin, SkMask::CreateMode createMode) const;
|
||||
|
||||
private:
|
||||
SkScalar fRadius;
|
||||
@ -106,6 +113,26 @@ bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
|
||||
#endif
|
||||
}
|
||||
|
||||
bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
|
||||
const SkMatrix& matrix,
|
||||
SkIPoint* margin, SkMask::CreateMode createMode) const{
|
||||
SkScalar radius;
|
||||
if (fBlurFlags & SkBlurMaskFilter::kIgnoreTransform_BlurFlag) {
|
||||
radius = fRadius;
|
||||
} else {
|
||||
radius = matrix.mapRadius(fRadius);
|
||||
}
|
||||
|
||||
// To avoid unseemly allocation requests (esp. for finite platforms like
|
||||
// handset) we limit the radius so something manageable. (as opposed to
|
||||
// a request like 10,000)
|
||||
static const SkScalar MAX_RADIUS = SkIntToScalar(128);
|
||||
radius = SkMinScalar(radius, MAX_RADIUS);
|
||||
|
||||
return SkBlurMask::BlurRect(dst, r, radius, (SkBlurMask::Style)fBlurStyle,
|
||||
margin, createMode);
|
||||
}
|
||||
|
||||
#include "SkCanvas.h"
|
||||
|
||||
static bool drawRectsIntoMask(const SkRect rects[], int count, SkMask* mask) {
|
||||
@ -150,6 +177,14 @@ static bool rect_exceeds(const SkRect& r, SkScalar v) {
|
||||
r.width() > v || r.height() > v;
|
||||
}
|
||||
|
||||
SK_CONF_DECLARE( bool, c_analyticBlurNinepatch, "mask.filter.analyticNinePatch",
|
||||
#ifdef SK_IGNORE_FAST_RECT_BLUR
|
||||
false,
|
||||
#else
|
||||
true,
|
||||
#endif
|
||||
"Use the faster analytic blur approach for ninepatch rects" );
|
||||
|
||||
SkMaskFilter::FilterReturn
|
||||
SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
|
||||
const SkMatrix& matrix,
|
||||
@ -177,7 +212,18 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
|
||||
srcM.fImage = NULL;
|
||||
srcM.fFormat = SkMask::kA8_Format;
|
||||
srcM.fRowBytes = 0;
|
||||
if (!this->filterMask(&dstM, srcM, matrix, &margin)) {
|
||||
|
||||
bool filterResult = false;
|
||||
if (count == 1 && c_analyticBlurNinepatch) {
|
||||
// special case for fast rect blur
|
||||
// don't actually do the blur the first time, just compute the correct size
|
||||
filterResult = this->filterRectMask(&dstM, rects[0], matrix, &margin,
|
||||
SkMask::kJustComputeBounds_CreateMode);
|
||||
} else {
|
||||
filterResult = this->filterMask(&dstM, srcM, matrix, &margin);
|
||||
}
|
||||
|
||||
if (!filterResult) {
|
||||
return kFalse_FilterReturn;
|
||||
}
|
||||
|
||||
@ -235,14 +281,21 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
|
||||
SkASSERT(!smallR[1].isEmpty());
|
||||
}
|
||||
|
||||
if (!drawRectsIntoMask(smallR, count, &srcM)) {
|
||||
return kFalse_FilterReturn;
|
||||
}
|
||||
if (count > 1 || !c_analyticBlurNinepatch) {
|
||||
if (!drawRectsIntoMask(smallR, count, &srcM)) {
|
||||
return kFalse_FilterReturn;
|
||||
}
|
||||
|
||||
SkAutoMaskFreeImage amf(srcM.fImage);
|
||||
SkAutoMaskFreeImage amf(srcM.fImage);
|
||||
|
||||
if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
|
||||
return kFalse_FilterReturn;
|
||||
if (!this->filterMask(&patch->fMask, srcM, matrix, &margin)) {
|
||||
return kFalse_FilterReturn;
|
||||
}
|
||||
} else {
|
||||
if (!this->filterRectMask(&patch->fMask, smallR[0], matrix, &margin,
|
||||
SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
|
||||
return kFalse_FilterReturn;
|
||||
}
|
||||
}
|
||||
patch->fMask.fBounds.offsetTo(0, 0);
|
||||
patch->fOuterRect = dstM.fBounds;
|
||||
|
Loading…
Reference in New Issue
Block a user