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:
parent
641cce90c9
commit
17ad2bd077
82
gm/blurquickreject.cpp
Normal file
82
gm/blurquickreject.cpp
Normal 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(); )
|
@ -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',
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user