Index: src/effects/SkBlurMaskFilter.cpp |
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp |
index 2ef86b016291eb0ef721a7471ad40045dc532d05..58242b701715eb472b74cac641eb120e83abd818 100644 |
--- a/src/effects/SkBlurMaskFilter.cpp |
+++ b/src/effects/SkBlurMaskFilter.cpp |
@@ -18,6 +18,7 @@ |
#include "SkStrokeRec.h" |
#if SK_SUPPORT_GPU |
+#include "GrCircleBlurFragmentProcessor.h" |
#include "GrContext.h" |
#include "GrDrawContext.h" |
#include "GrTexture.h" |
@@ -44,7 +45,7 @@ public: |
SkIPoint* margin) const override; |
#if SK_SUPPORT_GPU |
- bool canFilterMaskGPU(const SkRect& devBounds, |
+ bool canFilterMaskGPU(const SkRRect& devRRect, |
const SkIRect& clipBounds, |
const SkMatrix& ctm, |
SkRect* maskRect) const override; |
@@ -166,27 +167,25 @@ bool SkBlurMaskFilterImpl::asABlur(BlurRec* rec) const { |
bool SkBlurMaskFilterImpl::filterMask(SkMask* dst, const SkMask& src, |
const SkMatrix& matrix, |
- SkIPoint* margin) const{ |
+ SkIPoint* margin) const { |
SkScalar sigma = this->computeXformedSigma(matrix); |
return SkBlurMask::BoxBlur(dst, src, sigma, fBlurStyle, this->getQuality(), margin); |
} |
bool SkBlurMaskFilterImpl::filterRectMask(SkMask* dst, const SkRect& r, |
const SkMatrix& matrix, |
- SkIPoint* margin, SkMask::CreateMode createMode) const{ |
+ SkIPoint* margin, SkMask::CreateMode createMode) const { |
SkScalar sigma = computeXformedSigma(matrix); |
- return SkBlurMask::BlurRect(sigma, dst, r, fBlurStyle, |
- margin, createMode); |
+ return SkBlurMask::BlurRect(sigma, dst, r, fBlurStyle, margin, createMode); |
} |
bool SkBlurMaskFilterImpl::filterRRectMask(SkMask* dst, const SkRRect& r, |
const SkMatrix& matrix, |
- SkIPoint* margin, SkMask::CreateMode createMode) const{ |
+ SkIPoint* margin, SkMask::CreateMode createMode) const { |
SkScalar sigma = computeXformedSigma(matrix); |
- return SkBlurMask::BlurRRect(sigma, dst, r, fBlurStyle, |
- margin, createMode); |
+ return SkBlurMask::BlurRRect(sigma, dst, r, fBlurStyle, margin, createMode); |
} |
#include "SkCanvas.h" |
@@ -607,51 +606,42 @@ class GrGLRectBlurEffect; |
class GrRectBlurEffect : public GrFragmentProcessor { |
public: |
- virtual ~GrRectBlurEffect(); |
+ ~GrRectBlurEffect() override { } |
const char* name() const override { return "RectBlur"; } |
- /** |
- * Create a simple filter effect with custom bicubic coefficients. |
- */ |
- static GrFragmentProcessor* Create(GrTextureProvider *textureProvider, const SkRect& rect, |
- float sigma) { |
- GrTexture *blurProfileTexture = nullptr; |
+ static GrFragmentProcessor* Create(GrTextureProvider *textureProvider, |
+ const SkRect& rect, float sigma) { |
int doubleProfileSize = SkScalarCeilToInt(12*sigma); |
if (doubleProfileSize >= rect.width() || doubleProfileSize >= rect.height()) { |
// if the blur sigma is too large so the gaussian overlaps the whole |
// rect in either direction, fall back to CPU path for now. |
- |
return nullptr; |
} |
- bool createdBlurProfileTexture = CreateBlurProfileTexture( |
- textureProvider, sigma, &blurProfileTexture); |
- SkAutoTUnref<GrTexture> hunref(blurProfileTexture); |
- if (!createdBlurProfileTexture) { |
+ SkAutoTUnref<GrTexture> blurProfile(CreateBlurProfileTexture(textureProvider, sigma)); |
+ if (!blurProfile) { |
return nullptr; |
} |
- return new GrRectBlurEffect(rect, sigma, blurProfileTexture); |
+ return new GrRectBlurEffect(rect, sigma, blurProfile); |
} |
const SkRect& getRect() const { return fRect; } |
float getSigma() const { return fSigma; } |
private: |
- GrGLFragmentProcessor* onCreateGLInstance() const override; |
+ GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile); |
- GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blur_profile); |
+ GrGLFragmentProcessor* onCreateGLInstance() const override; |
- virtual void onGetGLProcessorKey(const GrGLSLCaps& caps, |
- GrProcessorKeyBuilder* b) const override; |
+ void onGetGLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override; |
bool onIsEqual(const GrFragmentProcessor&) const override; |
void onComputeInvariantOutput(GrInvariantOutput* inout) const override; |
- static bool CreateBlurProfileTexture(GrTextureProvider*, float sigma, |
- GrTexture **blurProfileTexture); |
+ static GrTexture* CreateBlurProfileTexture(GrTextureProvider*, float sigma); |
SkRect fRect; |
float fSigma; |
@@ -665,7 +655,7 @@ private: |
class GrGLRectBlurEffect : public GrGLFragmentProcessor { |
public: |
GrGLRectBlurEffect(const GrProcessor&) {} |
- virtual void emitCode(EmitArgs&) override; |
+ void emitCode(EmitArgs&) override; |
protected: |
void onSetData(const GrGLProgramDataManager&, const GrProcessor&) override; |
@@ -738,7 +728,7 @@ void GrGLRectBlurEffect::emitCode(EmitArgs& args) { |
} |
void GrGLRectBlurEffect::onSetData(const GrGLProgramDataManager& pdman, |
- const GrProcessor& proc) { |
+ const GrProcessor& proc) { |
const GrRectBlurEffect& rbe = proc.cast<GrRectBlurEffect>(); |
SkRect rect = rbe.getRect(); |
@@ -746,8 +736,8 @@ void GrGLRectBlurEffect::onSetData(const GrGLProgramDataManager& pdman, |
pdman.set1f(fProfileSizeUniform, SkScalarCeilToScalar(6*rbe.getSigma())); |
} |
-bool GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* textureProvider, float sigma, |
- GrTexture **blurProfileTexture) { |
+GrTexture* GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* textureProvider, |
+ float sigma) { |
GrSurfaceDesc texDesc; |
unsigned int profileSize = SkScalarCeilToInt(6*sigma); |
@@ -762,40 +752,29 @@ bool GrRectBlurEffect::CreateBlurProfileTexture(GrTextureProvider* textureProvid |
builder[0] = profileSize; |
builder.finish(); |
- uint8_t *profile = nullptr; |
- SkAutoTDeleteArray<uint8_t> ada(nullptr); |
- |
- *blurProfileTexture = textureProvider->findAndRefTextureByUniqueKey(key); |
+ GrTexture *blurProfile = textureProvider->findAndRefTextureByUniqueKey(key); |
- if (nullptr == *blurProfileTexture) { |
+ if (!blurProfile) { |
+ SkAutoTDeleteArray<uint8_t> profile(SkBlurMask::ComputeBlurProfile(sigma)); |
- SkBlurMask::ComputeBlurProfile(sigma, &profile); |
- ada.reset(profile); |
- |
- *blurProfileTexture = textureProvider->createTexture(texDesc, true, profile, 0); |
- |
- if (nullptr == *blurProfileTexture) { |
- return false; |
+ blurProfile = textureProvider->createTexture(texDesc, true, profile.get(), 0); |
+ if (blurProfile) { |
+ textureProvider->assignUniqueKeyToTexture(key, blurProfile); |
} |
- textureProvider->assignUniqueKeyToTexture(key, *blurProfileTexture); |
} |
- return true; |
+ return blurProfile; |
} |
-GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, |
- GrTexture *blur_profile) |
- : fRect(rect), |
- fSigma(sigma), |
- fBlurProfileAccess(blur_profile) { |
+GrRectBlurEffect::GrRectBlurEffect(const SkRect& rect, float sigma, GrTexture *blurProfile) |
+ : fRect(rect) |
+ , fSigma(sigma) |
+ , fBlurProfileAccess(blurProfile) { |
this->initClassID<GrRectBlurEffect>(); |
this->addTextureAccess(&fBlurProfileAccess); |
this->setWillReadFragmentPosition(); |
} |
-GrRectBlurEffect::~GrRectBlurEffect() { |
-} |
- |
void GrRectBlurEffect::onGetGLProcessorKey(const GrGLSLCaps& caps, |
GrProcessorKeyBuilder* b) const { |
GrGLRectBlurEffect::GenKey(*this, caps, b); |
@@ -839,22 +818,31 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider, |
return false; |
} |
- SkRect rect; |
- if (!path.isRect(&rect)) { |
- return false; |
- } |
- |
+ // TODO: we could handle blurred stroked circles |
if (!strokeRec.isFillStyle()) { |
return false; |
} |
SkScalar xformedSigma = this->computeXformedSigma(viewMatrix); |
- int pad = SkScalarCeilToInt(6*xformedSigma)/2; |
- rect.outset(SkIntToScalar(pad), SkIntToScalar(pad)); |
+ SkAutoTUnref<const GrFragmentProcessor> fp; |
+ |
+ SkRect rect; |
+ if (path.isRect(&rect)) { |
+ int pad = SkScalarCeilToInt(6*xformedSigma)/2; |
+ rect.outset(SkIntToScalar(pad), SkIntToScalar(pad)); |
+ |
+ fp.reset(GrRectBlurEffect::Create(texProvider, rect, xformedSigma)); |
+ } else if (path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height())) { |
+ fp.reset(GrCircleBlurFragmentProcessor::Create(texProvider, rect, xformedSigma)); |
+ |
+ // expand the rect for the coverage geometry |
+ int pad = SkScalarCeilToInt(6*xformedSigma)/2; |
+ rect.outset(SkIntToScalar(pad), SkIntToScalar(pad)); |
+ } else { |
+ return false; |
+ } |
- SkAutoTUnref<GrFragmentProcessor> fp(GrRectBlurEffect::Create( |
- texProvider, rect, xformedSigma)); |
if (!fp) { |
return false; |
} |
@@ -870,10 +858,12 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider, |
return true; |
} |
+////////////////////////////////////////////////////////////////////////////// |
+ |
class GrRRectBlurEffect : public GrFragmentProcessor { |
public: |
- static GrFragmentProcessor* Create(GrTextureProvider*, float sigma, const SkRRect&); |
+ static const GrFragmentProcessor* Create(GrTextureProvider*, float sigma, const SkRRect&); |
virtual ~GrRRectBlurEffect() {}; |
const char* name() const override { return "GrRRectBlur"; } |
@@ -903,8 +893,12 @@ private: |
}; |
-GrFragmentProcessor* GrRRectBlurEffect::Create(GrTextureProvider* texProvider, float sigma, |
- const SkRRect& rrect) { |
+const GrFragmentProcessor* GrRRectBlurEffect::Create(GrTextureProvider* texProvider, float sigma, |
+ const SkRRect& rrect) { |
+ if (rrect.isCircle()) { |
+ return GrCircleBlurFragmentProcessor::Create(texProvider, rrect.rect(), sigma); |
+ } |
+ |
if (!rrect.isSimpleCircular()) { |
return nullptr; |
} |
@@ -1129,8 +1123,8 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrTextureProvider* texProvid |
SkRect proxyRect = rrect.rect(); |
proxyRect.outset(extra, extra); |
- SkAutoTUnref<GrFragmentProcessor> fp(GrRRectBlurEffect::Create(texProvider, |
- xformedSigma, rrect)); |
+ SkAutoTUnref<const GrFragmentProcessor> fp(GrRRectBlurEffect::Create(texProvider, |
+ xformedSigma, rrect)); |
if (!fp) { |
return false; |
} |
@@ -1146,7 +1140,7 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrTextureProvider* texProvid |
return true; |
} |
-bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds, |
+bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect, |
const SkIRect& clipBounds, |
const SkMatrix& ctm, |
SkRect* maskRect) const { |
@@ -1155,14 +1149,17 @@ bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds, |
return false; |
} |
- static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64); |
- static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32); |
+ // We always do circles on the GPU |
+ if (!devRRect.isCircle()) { |
+ static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64); |
+ static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32); |
- if (srcBounds.width() <= kMIN_GPU_BLUR_SIZE && |
- srcBounds.height() <= kMIN_GPU_BLUR_SIZE && |
- xformedSigma <= kMIN_GPU_BLUR_SIGMA) { |
- // We prefer to blur small rect with small radius via CPU. |
- return false; |
+ if (devRRect.width() <= kMIN_GPU_BLUR_SIZE && |
+ devRRect.height() <= kMIN_GPU_BLUR_SIZE && |
+ xformedSigma <= kMIN_GPU_BLUR_SIGMA) { |
+ // We prefer to blur small rects with small radii on the CPU. |
+ return false; |
+ } |
} |
if (nullptr == maskRect) { |
@@ -1173,7 +1170,7 @@ bool SkBlurMaskFilterImpl::canFilterMaskGPU(const SkRect& srcBounds, |
float sigma3 = 3 * SkScalarToFloat(xformedSigma); |
SkRect clipRect = SkRect::Make(clipBounds); |
- SkRect srcRect(srcBounds); |
+ SkRect srcRect(devRRect.rect()); |
// Outset srcRect and clipRect by 3 * sigma, to compute affected blur area. |
srcRect.outset(sigma3, sigma3); |