Fix quickReject computation for blurs

https://codereview.chromium.org/17035007/



git-svn-id: http://skia.googlecode.com/svn/trunk@10428 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
robertphillips@google.com 2013-07-30 12:15:19 +00:00
parent 641cce90c9
commit 17ad2bd077
5 changed files with 118 additions and 15 deletions

82
gm/blurquickreject.cpp Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "gm.h"
#include "SkCanvas.h"
#include "SkBlurMaskFilter.h"
// This GM tests out the quick reject bounds of the blur mask filter. It draws
// four blurred rects around a central clip. The blurred rect geometry outset
// by the blur radius does not overlap the clip rect so, if the blur clipping
// just uses the radius, they will be clipped out (and the result will differ
// from the result if quick reject were disabled. If the blur clipping uses
// the correct 3 sigma bound then the images with and without quick rejecting
// will be the same.
class BlurQuickRejectGM : public skiagm::GM {
public:
BlurQuickRejectGM() {}
protected:
virtual SkString onShortName() SK_OVERRIDE {
return SkString("blurquickreject");
}
virtual SkISize onISize() SK_OVERRIDE {
return SkISize::Make(kWidth, kHeight);
}
virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
static const SkScalar kBlurRadius = SkIntToScalar(20);
static const SkScalar kBoxSize = SkIntToScalar(100);
SkRect clipRect = SkRect::MakeXYWH(0, 0, kBoxSize, kBoxSize);
SkRect blurRects[] = {
{ -kBoxSize - (kBlurRadius+1), 0, -(kBlurRadius+1), kBoxSize },
{ 0, -kBoxSize - (kBlurRadius+1), kBoxSize, -(kBlurRadius+1) },
{ kBoxSize+kBlurRadius+1, 0, 2*kBoxSize+kBlurRadius+1, kBoxSize },
{ 0, kBoxSize+kBlurRadius+1, kBoxSize, 2*kBoxSize+kBlurRadius+1 }
};
SkColor colors[] = {
SK_ColorRED,
SK_ColorGREEN,
SK_ColorBLUE,
SK_ColorYELLOW,
};
SkASSERT(SK_ARRAY_COUNT(colors) == SK_ARRAY_COUNT(blurRects));
SkPaint hairlinePaint;
hairlinePaint.setStyle(SkPaint::kStroke_Style);
hairlinePaint.setColor(SK_ColorWHITE);
hairlinePaint.setStrokeWidth(0);
SkPaint blurPaint;
blurPaint.setFilterBitmap(true);
SkMaskFilter* mf = SkBlurMaskFilter::Create(kBlurRadius,
SkBlurMaskFilter::kNormal_BlurStyle);
blurPaint.setMaskFilter(mf)->unref();
canvas->clear(SK_ColorBLACK);
canvas->save();
canvas->translate(kBoxSize, kBoxSize);
canvas->drawRect(clipRect, hairlinePaint);
canvas->clipRect(clipRect);
for (int i = 0; i < SK_ARRAY_COUNT(blurRects); ++i) {
blurPaint.setColor(colors[i]);
canvas->drawRect(blurRects[i], blurPaint);
canvas->drawRect(blurRects[i], hairlinePaint);
}
canvas->restore();
}
private:
static const int kWidth = 300;
static const int kHeight = 300;
typedef GM INHERITED;
};
DEF_GM( return new BlurQuickRejectGM(); )

View File

@ -18,6 +18,7 @@
'../gm/bleed.cpp',
'../gm/blend.cpp',
'../gm/blurs.cpp',
'../gm/blurquickreject.cpp',
'../gm/blurrect.cpp',
'../gm/circles.cpp',
'../gm/colorfilterimagefilter.cpp',

View File

@ -12,13 +12,7 @@
#include "SkTemplates.h"
#include "SkEndian.h"
// scale factor for the blur radius to match the behavior of the all existing blur
// code (both on the CPU and the GPU). This magic constant is 1/sqrt(3).
// TODO: get rid of this fudge factor and move any required fudging up into
// the calling library
#define kBlurRadiusFudgeFactor SkFloatToScalar( .57735f )
const SkScalar SkBlurMask::kBlurRadiusFudgeFactor = SkFloatToScalar(.57735f);
#define UNROLL_SEPARABLE_LOOPS

View File

@ -43,6 +43,13 @@ public:
static bool BlurGroundTruth(SkMask* dst, const SkMask& src,
SkScalar provided_radius, Style style,
SkIPoint* margin = NULL);
// scale factor for the blur radius to match the behavior of the all existing blur
// code (both on the CPU and the GPU). This magic constant is 1/sqrt(3).
// TODO: get rid of this fudge factor and move any required fudging up into
// the calling library
static const SkScalar kBlurRadiusFudgeFactor;
};
#endif

View File

@ -60,7 +60,7 @@ private:
// 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 kMAX_RADIUS;
static const SkScalar kMAX_BLUR_RADIUS;
// This constant approximates the scaling done in the software path's
// "high quality" mode, in SkBlurMask::Blur() (1 / sqrt(3)).
// IMHO, it actually should be 1: we blur "less" than we should do
@ -82,15 +82,15 @@ private:
SkScalar xformedRadius = ignoreTransform ? fRadius
: ctm.mapRadius(fRadius);
return SkMinScalar(xformedRadius, kMAX_RADIUS);
return SkMinScalar(xformedRadius, kMAX_BLUR_RADIUS);
}
#endif
typedef SkMaskFilter INHERITED;
};
const SkScalar SkBlurMaskFilterImpl::kMAX_RADIUS = SkIntToScalar(128);
const SkScalar SkBlurMaskFilterImpl::kBLUR_SIGMA_SCALE = 0.6f;
const SkScalar SkBlurMaskFilterImpl::kMAX_BLUR_RADIUS = SkIntToScalar(128);
const SkScalar SkBlurMaskFilterImpl::kBLUR_SIGMA_SCALE = SkFloatToScalar(0.6f);
SkMaskFilter* SkBlurMaskFilter::Create(SkScalar radius,
SkBlurMaskFilter::BlurStyle style,
@ -139,7 +139,7 @@ bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src,
radius = matrix.mapRadius(fRadius);
}
radius = SkMinScalar(radius, kMAX_RADIUS);
radius = SkMinScalar(radius, kMAX_BLUR_RADIUS);
SkBlurMask::Quality blurQuality =
(fBlurFlags & SkBlurMaskFilter::kHighQuality_BlurFlag) ?
SkBlurMask::kHigh_Quality : SkBlurMask::kLow_Quality;
@ -158,7 +158,7 @@ bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r,
radius = matrix.mapRadius(fRadius);
}
radius = SkMinScalar(radius, kMAX_RADIUS);
radius = SkMinScalar(radius, kMAX_BLUR_RADIUS);
return SkBlurMask::BlurRect(dst, r, radius, (SkBlurMask::Style)fBlurStyle,
margin, createMode);
@ -334,8 +334,27 @@ SkBlurMaskFilterImpl::filterRectsToNine(const SkRect rects[], int count,
void SkBlurMaskFilterImpl::computeFastBounds(const SkRect& src,
SkRect* dst) const {
dst->set(src.fLeft - fRadius, src.fTop - fRadius,
src.fRight + fRadius, src.fBottom + fRadius);
SkScalar gpuPad, rasterPad;
{
// GPU path
SkScalar sigma = SkScalarMul(fRadius, kBLUR_SIGMA_SCALE);
gpuPad = sigma * 3.0f;
}
{
// raster path
SkScalar radius = SkScalarMul(fRadius, SkBlurMask::kBlurRadiusFudgeFactor);
radius = (radius + .5f) * 2.f;
rasterPad = SkIntToScalar(SkScalarRoundToInt(radius * 3)/2);
}
SkScalar pad = SkMaxScalar(gpuPad, rasterPad);
dst->set(src.fLeft - pad, src.fTop - pad,
src.fRight + pad, src.fBottom + pad);
}
SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkFlattenableReadBuffer& buffer)