diff options
author | humper@google.com <humper@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-03-11 20:16:28 +0000 |
---|---|---|
committer | humper@google.com <humper@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-03-11 20:16:28 +0000 |
commit | 7c5d7b781385c47e5be9a343d60c5b7d33b5b8cd (patch) | |
tree | f37dcfa88e288ccd682879eedb597e8470934208 | |
parent | ed268bfed3205347a90557c5029f37e90cc01956 (diff) |
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
-rw-r--r-- | src/effects/SkBlurMask.cpp | 58 | ||||
-rw-r--r-- | src/effects/SkBlurMask.h | 4 | ||||
-rw-r--r-- | src/effects/SkBlurMaskFilter.cpp | 67 |
3 files changed, 100 insertions, 29 deletions
diff --git a/src/effects/SkBlurMask.cpp b/src/effects/SkBlurMask.cpp index 413e8c0690..19a538a91d 100644 --- a/src/effects/SkBlurMask.cpp +++ b/src/effects/SkBlurMask.cpp @@ -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; diff --git a/src/effects/SkBlurMask.h b/src/effects/SkBlurMask.h index 5179b4b2b7..4849ee77a9 100644 --- a/src/effects/SkBlurMask.h +++ b/src/effects/SkBlurMask.h @@ -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); diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index c49a785024..3273325570 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -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; |