Chromium Code Reviews| Index: src/effects/SkBlurMaskFilter.cpp |
| diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp |
| index 421573349260ac7d03c2d09a768dd15502fdd371..af58f6a9549e945a749a48145150beeb9bab8e14 100644 |
| --- a/src/effects/SkBlurMaskFilter.cpp |
| +++ b/src/effects/SkBlurMaskFilter.cpp |
| @@ -22,7 +22,7 @@ |
| #include "GrTexture.h" |
| #include "GrFragmentProcessor.h" |
| #include "GrInvariantOutput.h" |
| -#include "SkDraw.h" |
| +#include "GrStyle.h" |
| #include "effects/GrSimpleTextureEffect.h" |
| #include "glsl/GrGLSLFragmentProcessor.h" |
| #include "glsl/GrGLSLFragmentShaderBuilder.h" |
| @@ -56,7 +56,7 @@ public: |
| const SkMatrix& viewMatrix, |
| const SkStrokeRec& strokeRec, |
| const SkPath& path) const override; |
| - bool directFilterRRectMaskGPU(GrTextureProvider* texProvider, |
| + bool directFilterRRectMaskGPU(GrContext*, |
| GrDrawContext* drawContext, |
| GrPaint* grp, |
| const GrClip&, |
| @@ -136,6 +136,64 @@ sk_sp<SkMaskFilter> SkBlurMaskFilter::Make(SkBlurStyle style, SkScalar sigma, ui |
| return sk_sp<SkMaskFilter>(new SkBlurMaskFilterImpl(sigma, style, flags)); |
| } |
| +bool SkBlurMaskFilter::ComputeBlurredRRectParams(const SkRRect& rrect, |
| + SkScalar sigma, |
| + SkRRect* rrectToDraw, |
| + SkISize* widthHeight, |
| + SkScalar xs[4], |
| + int* numXs, |
| + SkScalar ys[4], |
| + int* numYs) { |
| + unsigned int blurRadius = 3*SkScalarCeilToInt(sigma-1/6.0f); |
| + |
| + const SkRect& orig = rrect.getBounds(); |
| + const SkVector& radiiUL = rrect.radii(SkRRect::kUpperLeft_Corner); |
| + const SkVector& radiiUR = rrect.radii(SkRRect::kUpperRight_Corner); |
| + const SkVector& radiiLR = rrect.radii(SkRRect::kLowerRight_Corner); |
| + const SkVector& radiiLL = rrect.radii(SkRRect::kLowerLeft_Corner); |
| + |
| + const int left = SkScalarCeilToInt(SkTMax<SkScalar>(radiiUL.fX, radiiLL.fX)); |
| + const int top = SkScalarCeilToInt(SkTMax<SkScalar>(radiiUL.fY, radiiUR.fY)); |
| + const int right = SkScalarCeilToInt(SkTMax<SkScalar>(radiiUR.fX, radiiLR.fX)); |
| + const int bot = SkScalarCeilToInt(SkTMax<SkScalar>(radiiLL.fY, radiiLR.fY)); |
| + |
| + // This is a conservative check for nine-patchability |
| + if (orig.fLeft + left + blurRadius >= orig.fRight - right - blurRadius || |
| + orig.fTop + top + blurRadius >= orig.fBottom - bot - blurRadius) { |
| + return false; |
| + } |
| + |
| + int newRRWidth, newRRHeight; |
| + |
| + // 3x3 case |
| + newRRWidth = 2*blurRadius + left + right + 1; |
| + newRRHeight = 2*blurRadius + top + bot + 1; |
| + widthHeight->fWidth = newRRWidth + 2 * blurRadius; |
| + widthHeight->fHeight = newRRHeight + 2 * blurRadius; |
| + // TODO: need to return non-normalized indices |
| + xs[0] = 0.0f; |
| + xs[1] = (blurRadius + left) / (float) widthHeight->fWidth; |
| + xs[2] = (blurRadius + left + 1.0f) / widthHeight->fWidth; |
| + xs[3] = 1.0f; |
| + *numXs = 4; |
| + ys[0] = 0.0f; |
| + ys[1] = (blurRadius + top) / (float) widthHeight->fHeight; |
| + ys[2] = (blurRadius + top + 1.0f) / widthHeight->fHeight; |
| + ys[3] = 1.0f; |
| + *numYs = 4; |
| + |
| + const SkRect newRect = SkRect::MakeXYWH(SkIntToScalar(blurRadius), SkIntToScalar(blurRadius), |
| + SkIntToScalar(newRRWidth), SkIntToScalar(newRRHeight)); |
| + SkVector newRadii[4]; |
| + newRadii[0] = { SkScalarCeilToScalar(radiiUL.fX), SkScalarCeilToScalar(radiiUL.fY) }; |
| + newRadii[1] = { SkScalarCeilToScalar(radiiUR.fX), SkScalarCeilToScalar(radiiUR.fY) }; |
| + newRadii[2] = { SkScalarCeilToScalar(radiiLR.fX), SkScalarCeilToScalar(radiiLR.fY) }; |
| + newRadii[3] = { SkScalarCeilToScalar(radiiLL.fX), SkScalarCeilToScalar(radiiLL.fY) }; |
| + |
| + rrectToDraw->setRectRadii(newRect, newRadii); |
| + return true; |
| +} |
| + |
| /////////////////////////////////////////////////////////////////////////////// |
| SkBlurMaskFilterImpl::SkBlurMaskFilterImpl(SkScalar sigma, SkBlurStyle style, uint32_t flags) |
| @@ -599,6 +657,7 @@ void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const { |
| buffer.writeUInt(fBlurFlags); |
| } |
| + |
| #if SK_SUPPORT_GPU |
| class GrGLRectBlurEffect; |
| @@ -910,7 +969,7 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider, |
| class GrRRectBlurEffect : public GrFragmentProcessor { |
| public: |
| - static sk_sp<GrFragmentProcessor> Make(GrTextureProvider*, float sigma, const SkRRect&); |
| + static sk_sp<GrFragmentProcessor> Make(GrContext*, float sigma, const SkRRect&); |
| virtual ~GrRRectBlurEffect() {}; |
| const char* name() const override { return "GrRRectBlur"; } |
| @@ -939,13 +998,54 @@ private: |
| typedef GrFragmentProcessor INHERITED; |
| }; |
| +static sk_sp<GrTexture> make_rrect_blur_mask(GrContext* context, |
| + const SkRRect& rrect, |
| + float sigma, |
| + bool doAA) { |
| + SkRRect rrectToDraw; |
| + SkISize size; |
| + SkScalar xs[4], ys[4]; |
| + int numXs, numYs; |
| + |
| + SkBlurMaskFilter::ComputeBlurredRRectParams(rrect, sigma, &rrectToDraw, &size, |
| + xs, &numXs, ys, &numYs); |
| + |
| + // TODO: this could be approx but the texture coords will need to be updated |
| + sk_sp<GrDrawContext> dc(context->makeDrawContext(SkBackingFit::kExact, |
| + size.fWidth, size.fHeight, |
| + kAlpha_8_GrPixelConfig, nullptr)); |
| + if (!dc) { |
| + return nullptr; |
| + } |
| + |
| + GrPaint grPaint; |
| + grPaint.setAntiAlias(doAA); |
| + |
| + dc->clear(nullptr, SK_ColorTRANSPARENT, true); |
|
bsalomon
2016/08/10 17:43:19
I think this takes a GrColor
robertphillips
2016/08/10 18:31:45
Done.
|
| + dc->drawRRect(GrNoClip(), grPaint, SkMatrix::I(), rrectToDraw, GrStyle::SimpleFill()); |
| + |
| + sk_sp<GrDrawContext> dc2(SkGpuBlurUtils::GaussianBlur(context, |
| + dc->asTexture().release(), |
| + nullptr, |
| + SkIRect::MakeWH(size.fWidth, |
| + size.fHeight), |
| + nullptr, |
| + sigma, sigma, SkBackingFit::kExact)); |
| + if (!dc2) { |
| + return nullptr; |
| + } |
| -sk_sp<GrFragmentProcessor> GrRRectBlurEffect::Make(GrTextureProvider* texProvider, float sigma, |
| - const SkRRect& rrect) { |
| + return dc2->asTexture(); |
| +} |
| + |
| +sk_sp<GrFragmentProcessor> GrRRectBlurEffect::Make(GrContext* context, float sigma, |
| + const SkRRect& rrect) { |
| if (rrect.isCircle()) { |
| - return GrCircleBlurFragmentProcessor::Make(texProvider, rrect.rect(), sigma); |
| + return GrCircleBlurFragmentProcessor::Make(context->textureProvider(), |
| + rrect.rect(), sigma); |
| } |
| + // TODO: loosen this up |
| if (!rrect.isSimpleCircular()) { |
| return nullptr; |
| } |
| @@ -968,55 +1068,17 @@ sk_sp<GrFragmentProcessor> GrRRectBlurEffect::Make(GrTextureProvider* texProvide |
| builder[1] = cornerRadius; |
| builder.finish(); |
| - SkAutoTUnref<GrTexture> blurNinePatchTexture(texProvider->findAndRefTextureByUniqueKey(key)); |
| + sk_sp<GrTexture> blurNinePatchTexture( |
| + context->textureProvider()->findAndRefTextureByUniqueKey(key)); |
| if (!blurNinePatchTexture) { |
| - SkMask mask; |
| - |
| - unsigned int smallRectSide = 2*(blurRadius + cornerRadius) + 1; |
| - |
| - mask.fBounds = SkIRect::MakeWH(smallRectSide, smallRectSide); |
| - mask.fFormat = SkMask::kA8_Format; |
| - mask.fRowBytes = mask.fBounds.width(); |
| - mask.fImage = SkMask::AllocImage(mask.computeTotalImageSize()); |
| - SkAutoMaskFreeImage amfi(mask.fImage); |
| - |
| - memset(mask.fImage, 0, mask.computeTotalImageSize()); |
| - |
| - SkRect smallRect; |
| - smallRect.setWH(SkIntToScalar(smallRectSide), SkIntToScalar(smallRectSide)); |
| - |
| - SkRRect smallRRect; |
| - smallRRect.setRectXY(smallRect, SkIntToScalar(cornerRadius), SkIntToScalar(cornerRadius)); |
| - |
| - SkPath path; |
| - path.addRRect(smallRRect); |
| - |
| - SkDraw::DrawToMask(path, &mask.fBounds, nullptr, nullptr, &mask, |
| - SkMask::kJustRenderImage_CreateMode, SkStrokeRec::kFill_InitStyle); |
| - |
| - SkMask blurredMask; |
| - if (!SkBlurMask::BoxBlur(&blurredMask, mask, sigma, kNormal_SkBlurStyle, |
| - kHigh_SkBlurQuality, nullptr, true)) { |
| - return nullptr; |
| - } |
| - |
| - unsigned int texSide = smallRectSide + 2*blurRadius; |
| - GrSurfaceDesc texDesc; |
| - texDesc.fWidth = texSide; |
| - texDesc.fHeight = texSide; |
| - texDesc.fConfig = kAlpha_8_GrPixelConfig; |
| - texDesc.fIsMipMapped = false; |
| - |
| - blurNinePatchTexture.reset( |
| - texProvider->createTexture(texDesc, SkBudgeted::kYes , blurredMask.fImage, 0)); |
| - SkMask::FreeImage(blurredMask.fImage); |
| + blurNinePatchTexture = make_rrect_blur_mask(context, rrect, sigma, true); |
| if (!blurNinePatchTexture) { |
| return nullptr; |
| } |
| - texProvider->assignUniqueKeyToTexture(key, blurNinePatchTexture); |
| + context->textureProvider()->assignUniqueKeyToTexture(key, blurNinePatchTexture.get()); |
| } |
| - return sk_sp<GrFragmentProcessor>(new GrRRectBlurEffect(sigma, rrect, blurNinePatchTexture)); |
| + return sk_sp<GrFragmentProcessor>(new GrRRectBlurEffect(sigma, rrect, blurNinePatchTexture.get())); |
| } |
| void GrRRectBlurEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const { |
| @@ -1050,7 +1112,7 @@ sk_sp<GrFragmentProcessor> GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) |
| SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f); |
| SkRRect rrect; |
| rrect.setRectXY(SkRect::MakeWH(w, h), r, r); |
| - return GrRRectBlurEffect::Make(d->fContext->textureProvider(), sigma, rrect); |
| + return GrRRectBlurEffect::Make(d->fContext, sigma, rrect); |
| } |
| ////////////////////////////////////////////////////////////////////////////// |
| @@ -1153,7 +1215,7 @@ GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const { |
| return new GrGLRRectBlurEffect; |
| } |
| -bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrTextureProvider* texProvider, |
| +bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, |
| GrDrawContext* drawContext, |
| GrPaint* grp, |
| const GrClip& clip, |
| @@ -1172,12 +1234,14 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrTextureProvider* texProvid |
| SkScalar xformedSigma = this->computeXformedSigma(viewMatrix); |
| - sk_sp<GrFragmentProcessor> fp(GrRRectBlurEffect::Make(texProvider, xformedSigma, rrect)); |
| + sk_sp<GrFragmentProcessor> fp(GrRRectBlurEffect::Make(context, xformedSigma, rrect)); |
| if (!fp) { |
| return false; |
| } |
| - grp->addCoverageFragmentProcessor(std::move(fp)); |
| + GrPaint newPaint(*grp); |
| + newPaint.addCoverageFragmentProcessor(std::move(fp)); |
| + newPaint.setAntiAlias(false); |
| SkMatrix inverse; |
| if (!viewMatrix.invert(&inverse)) { |
| @@ -1189,7 +1253,7 @@ bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrTextureProvider* texProvid |
| SkRect proxyRect = rrect.rect(); |
| proxyRect.outset(extra, extra); |
| - drawContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), proxyRect, inverse); |
| + drawContext->fillRectWithLocalMatrix(clip, newPaint, SkMatrix::I(), proxyRect, inverse); |
| return true; |
| } |