From 297d6efe852ebb98a324a71c79df8f7bbdcc3b94 Mon Sep 17 00:00:00 2001 From: Ethan Nicholas Date: Wed, 20 Dec 2017 12:00:11 -0500 Subject: [PATCH] converted GrRRectBlurEffect to SkSL Bug: skia: Change-Id: Ifd192db07e02d69d445277a361760ce4a452f603 Reviewed-on: https://skia-review.googlesource.com/87441 Reviewed-by: Greg Daniel Commit-Queue: Ethan Nicholas --- gn/gpu.gni | 2 + gn/sksl.gni | 1 + src/effects/SkBlurMaskFilter.cpp | 275 +------------------------ src/gpu/effects/GrRRectBlurEffect.cpp | 166 +++++++++++++++ src/gpu/effects/GrRRectBlurEffect.fp | 183 ++++++++++++++++ src/gpu/effects/GrRRectBlurEffect.h | 124 +++++++++++ src/gpu/glsl/GrGLSLFragmentProcessor.h | 2 - 7 files changed, 477 insertions(+), 276 deletions(-) create mode 100644 src/gpu/effects/GrRRectBlurEffect.cpp create mode 100644 src/gpu/effects/GrRRectBlurEffect.fp create mode 100644 src/gpu/effects/GrRRectBlurEffect.h diff --git a/gn/gpu.gni b/gn/gpu.gni index 87e3d9b22d..fb512bf10b 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -367,6 +367,8 @@ skia_gpu_sources = [ "$_src/gpu/effects/GrPremulInputFragmentProcessor.h", "$_src/gpu/effects/GrRectBlurEffect.cpp", "$_src/gpu/effects/GrRectBlurEffect.h", + "$_src/gpu/effects/GrRRectBlurEffect.cpp", + "$_src/gpu/effects/GrRRectBlurEffect.h", "$_src/gpu/effects/GrRRectEffect.cpp", "$_src/gpu/effects/GrRRectEffect.h", "$_src/gpu/effects/GrShadowGeoProc.cpp", diff --git a/gn/sksl.gni b/gn/sksl.gni index 9d992d181f..1bb57718c0 100644 --- a/gn/sksl.gni +++ b/gn/sksl.gni @@ -40,6 +40,7 @@ skia_gpu_processor_sources = [ "$_src/gpu/effects/GrMagnifierEffect.fp", "$_src/gpu/effects/GrPremulInputFragmentProcessor.fp", "$_src/gpu/effects/GrRectBlurEffect.fp", + "$_src/gpu/effects/GrRRectBlurEffect.fp", "$_src/gpu/effects/GrOverdrawFragmentProcessor.fp", "$_src/gpu/effects/GrSimpleTextureEffect.fp", "$_src/gpu/effects/GrUnpremulInputFragmentProcessor.fp", diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp index d3c4bb7e16..a7e0d24a45 100644 --- a/src/effects/SkBlurMaskFilter.cpp +++ b/src/effects/SkBlurMaskFilter.cpp @@ -27,6 +27,7 @@ #include "GrStyle.h" #include "GrTextureProxy.h" #include "effects/GrRectBlurEffect.h" +#include "effects/GrRRectBlurEffect.h" #include "effects/GrSimpleTextureEffect.h" #include "effects/GrTextureDomain.h" #include "glsl/GrGLSLFragmentProcessor.h" @@ -816,280 +817,6 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrContext* context, return true; } -////////////////////////////////////////////////////////////////////////////// - -class GrRRectBlurEffect : public GrFragmentProcessor { -public: - static std::unique_ptr Make(GrContext*, float sigma, float xformedSigma, - const SkRRect& srcRRect, - const SkRRect& devRRect); - - ~GrRRectBlurEffect() override {} - const char* name() const override { return "GrRRectBlur"; } - - const SkRRect& getRRect() const { return fRRect; } - float getSigma() const { return fSigma; } - - std::unique_ptr clone() const override; - -private: - GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - - GrRRectBlurEffect(float sigma, const SkRRect&, - sk_sp profileProxy); - - virtual void onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const override; - - bool onIsEqual(const GrFragmentProcessor& other) const override; - - SkRRect fRRect; - float fSigma; - TextureSampler fNinePatchSampler; - - GR_DECLARE_FRAGMENT_PROCESSOR_TEST - - typedef GrFragmentProcessor INHERITED; -}; - -static sk_sp find_or_create_rrect_blur_mask(GrContext* context, - const SkRRect& rrectToDraw, - const SkISize& size, - float xformedSigma) { - static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey key; - GrUniqueKey::Builder builder(&key, kDomain, 9); - builder[0] = SkScalarCeilToInt(xformedSigma-1/6.0f); - - int index = 1; - for (auto c : { SkRRect::kUpperLeft_Corner, SkRRect::kUpperRight_Corner, - SkRRect::kLowerRight_Corner, SkRRect::kLowerLeft_Corner }) { - SkASSERT(SkScalarIsInt(rrectToDraw.radii(c).fX) && SkScalarIsInt(rrectToDraw.radii(c).fY)); - builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fX); - builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fY); - } - builder.finish(); - - sk_sp mask(context->resourceProvider()->findOrCreateProxyByUniqueKey( - key, kBottomLeft_GrSurfaceOrigin)); - if (!mask) { - // TODO: this could be approx but the texture coords will need to be updated - sk_sp rtc(context->makeDeferredRenderTargetContextWithFallback( - SkBackingFit::kExact, size.fWidth, size.fHeight, kAlpha_8_GrPixelConfig, nullptr)); - if (!rtc) { - return nullptr; - } - - GrPaint paint; - - rtc->clear(nullptr, 0x0, GrRenderTargetContext::CanClearFullscreen::kYes); - rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw, - GrStyle::SimpleFill()); - - sk_sp srcProxy(rtc->asTextureProxyRef()); - if (!srcProxy) { - return nullptr; - } - sk_sp rtc2( - SkGpuBlurUtils::GaussianBlur(context, - std::move(srcProxy), - nullptr, - SkIRect::MakeWH(size.fWidth, size.fHeight), - SkIRect::EmptyIRect(), - xformedSigma, - xformedSigma, - GrTextureDomain::kIgnore_Mode, - SkBackingFit::kExact)); - if (!rtc2) { - return nullptr; - } - - mask = rtc2->asTextureProxyRef(); - if (!mask) { - return nullptr; - } - SkASSERT(mask->origin() == kBottomLeft_GrSurfaceOrigin); - context->resourceProvider()->assignUniqueKeyToProxy(key, mask.get()); - } - - return mask; -} - -std::unique_ptr GrRRectBlurEffect::Make(GrContext* context, float sigma, - float xformedSigma, - const SkRRect& srcRRect, - const SkRRect& devRRect) { - SkASSERT(!devRRect.isCircle() && !devRRect.isRect()); // Should've been caught up-stream - - // TODO: loosen this up - if (!devRRect.isSimpleCircular()) { - return nullptr; - } - - // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be - // sufficiently small relative to both the size of the corner radius and the - // width (and height) of the rrect. - SkRRect rrectToDraw; - SkISize size; - SkScalar ignored[SkBlurMaskFilter::kMaxDivisions]; - int ignoredSize; - uint32_t ignored32; - - bool ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(srcRRect, devRRect, - SkRect::MakeEmpty(), - sigma, xformedSigma, - &rrectToDraw, &size, - ignored, ignored, - ignored, ignored, - &ignoredSize, &ignoredSize, - &ignored32); - if (!ninePatchable) { - return nullptr; - } - - sk_sp mask(find_or_create_rrect_blur_mask(context, rrectToDraw, - size, xformedSigma)); - if (!mask) { - return nullptr; - } - - return std::unique_ptr( - new GrRRectBlurEffect(xformedSigma, devRRect, std::move(mask))); -} - -GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect, - sk_sp ninePatchProxy) - : INHERITED(kGrRRectBlurEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag) - , fRRect(rrect) - , fSigma(sigma) - , fNinePatchSampler(std::move(ninePatchProxy)) { - this->addTextureSampler(&fNinePatchSampler); -} - -std::unique_ptr GrRRectBlurEffect::clone() const { - return std::unique_ptr( - new GrRRectBlurEffect(fSigma, fRRect, sk_ref_sp(fNinePatchSampler.proxy()))); -} - -bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const { - const GrRRectBlurEffect& rrbe = other.cast(); - return fRRect.getSimpleRadii().fX == rrbe.fRRect.getSimpleRadii().fX && - fSigma == rrbe.fSigma && - fRRect.rect() == rrbe.fRRect.rect(); -} - -////////////////////////////////////////////////////////////////////////////// - -GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect); - -#if GR_TEST_UTILS -std::unique_ptr GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) { - SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f); - SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f); - SkScalar r = d->fRandom->nextRangeF(1.f, 9.f); - SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f); - SkRRect rrect; - rrect.setRectXY(SkRect::MakeWH(w, h), r, r); - return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect); -} -#endif - -////////////////////////////////////////////////////////////////////////////// - -class GrGLRRectBlurEffect : public GrGLSLFragmentProcessor { -public: - void emitCode(EmitArgs&) override; - -protected: - void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; - -private: - GrGLSLProgramDataManager::UniformHandle fProxyRectUniform; - GrGLSLProgramDataManager::UniformHandle fCornerRadiusUniform; - GrGLSLProgramDataManager::UniformHandle fBlurRadiusUniform; - typedef GrGLSLFragmentProcessor INHERITED; -}; - -void GrGLRRectBlurEffect::emitCode(EmitArgs& args) { - const char *rectName; - const char *cornerRadiusName; - const char *blurRadiusName; - - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - // The proxy rect has left, top, right, and bottom edges correspond to - // components x, y, z, and w, respectively. - - fProxyRectUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, - kHalf4_GrSLType, - "proxyRect", - &rectName); - fCornerRadiusUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, - kHalf_GrSLType, - "cornerRadius", - &cornerRadiusName); - fBlurRadiusUniform = uniformHandler->addUniform(kFragment_GrShaderFlag, - kHalf_GrSLType, - "blurRadius", - &blurRadiusName); - - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - - // warp the fragment position to the appropriate part of the 9patch blur texture - - fragBuilder->codeAppendf("half2 rectCenter = (%s.xy + %s.zw)/2.0;", rectName, rectName); - fragBuilder->codeAppendf("half2 translatedFragPos = sk_FragCoord.xy - %s.xy;", rectName); - fragBuilder->codeAppendf("half threshold = %s + 2.0*%s;", cornerRadiusName, blurRadiusName); - fragBuilder->codeAppendf("half2 middle = %s.zw - %s.xy - 2.0*threshold;", rectName, rectName); - - fragBuilder->codeAppendf( - "if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {"); - fragBuilder->codeAppendf("translatedFragPos.x = threshold;\n"); - fragBuilder->codeAppendf("} else if (translatedFragPos.x >= (middle.x + threshold)) {"); - fragBuilder->codeAppendf("translatedFragPos.x -= middle.x - 1.0;"); - fragBuilder->codeAppendf("}"); - - fragBuilder->codeAppendf( - "if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {"); - fragBuilder->codeAppendf("translatedFragPos.y = threshold;"); - fragBuilder->codeAppendf("} else if (translatedFragPos.y >= (middle.y + threshold)) {"); - fragBuilder->codeAppendf("translatedFragPos.y -= middle.y - 1.0;"); - fragBuilder->codeAppendf("}"); - - fragBuilder->codeAppendf("half2 proxyDims = half2(2.0*threshold+1.0);"); - fragBuilder->codeAppendf("half2 texCoord = translatedFragPos / proxyDims;"); - - fragBuilder->codeAppendf("%s = ", args.fOutputColor); - fragBuilder->appendTextureLookupAndModulate(args.fInputColor, args.fTexSamplers[0], "texCoord"); - fragBuilder->codeAppend(";"); -} - -void GrGLRRectBlurEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& proc) { - const GrRRectBlurEffect& brre = proc.cast(); - const SkRRect& rrect = brre.getRRect(); - - float blurRadius = 3.f*SkScalarCeilToScalar(brre.getSigma()-1/6.0f); - pdman.set1f(fBlurRadiusUniform, blurRadius); - - SkRect rect = rrect.getBounds(); - rect.outset(blurRadius, blurRadius); - pdman.set4f(fProxyRectUniform, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); - - SkScalar radius = 0; - SkASSERT(rrect.isSimpleCircular() || rrect.isRect()); - radius = rrect.getSimpleRadii().fX; - pdman.set1f(fCornerRadiusUniform, radius); -} - -void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const { - GrGLRRectBlurEffect::GenKey(*this, caps, b); -} - -GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const { - return new GrGLRRectBlurEffect; -} - bool SkBlurMaskFilterImpl::directFilterRRectMaskGPU(GrContext* context, GrRenderTargetContext* renderTargetContext, GrPaint&& paint, diff --git a/src/gpu/effects/GrRRectBlurEffect.cpp b/src/gpu/effects/GrRRectBlurEffect.cpp new file mode 100644 index 0000000000..32e9aef41c --- /dev/null +++ b/src/gpu/effects/GrRRectBlurEffect.cpp @@ -0,0 +1,166 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * This file was autogenerated from GrRRectBlurEffect.fp; do not modify. + */ +#include "GrRRectBlurEffect.h" +#if SK_SUPPORT_GPU + +std::unique_ptr GrRRectBlurEffect::Make(GrContext* context, float sigma, + float xformedSigma, + const SkRRect& srcRRect, + const SkRRect& devRRect) { + SkASSERT(!devRRect.isCircle() && !devRRect.isRect()); // Should've been caught up-stream + + // TODO: loosen this up + if (!devRRect.isSimpleCircular()) { + return nullptr; + } + + // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be + // sufficiently small relative to both the size of the corner radius and the + // width (and height) of the rrect. + SkRRect rrectToDraw; + SkISize size; + SkScalar ignored[SkBlurMaskFilter::kMaxDivisions]; + int ignoredSize; + uint32_t ignored32; + + bool ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams( + srcRRect, devRRect, SkRect::MakeEmpty(), sigma, xformedSigma, &rrectToDraw, &size, + ignored, ignored, ignored, ignored, &ignoredSize, &ignoredSize, &ignored32); + if (!ninePatchable) { + return nullptr; + } + + sk_sp mask( + find_or_create_rrect_blur_mask(context, rrectToDraw, size, xformedSigma)); + if (!mask) { + return nullptr; + } + + return std::unique_ptr(new GrRRectBlurEffect( + xformedSigma, devRRect.getBounds(), devRRect.getSimpleRadii().fX, std::move(mask))); +} +#include "glsl/GrGLSLFragmentProcessor.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" +#include "glsl/GrGLSLProgramBuilder.h" +#include "GrTexture.h" +#include "SkSLCPP.h" +#include "SkSLUtil.h" +class GrGLSLRRectBlurEffect : public GrGLSLFragmentProcessor { +public: + GrGLSLRRectBlurEffect() {} + void emitCode(EmitArgs& args) override { + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + const GrRRectBlurEffect& _outer = args.fFp.cast(); + (void)_outer; + auto sigma = _outer.sigma(); + (void)sigma; + auto rect = _outer.rect(); + (void)rect; + auto cornerRadius = _outer.cornerRadius(); + (void)cornerRadius; + fCornerRadiusVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType, + kDefault_GrSLPrecision, "cornerRadius"); + fProxyRectVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kFloat4_GrSLType, + kDefault_GrSLPrecision, "proxyRect"); + fBlurRadiusVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType, + kDefault_GrSLPrecision, "blurRadius"); + fragBuilder->codeAppendf( + "\nhalf2 translatedFragPos = half2(sk_FragCoord.xy - %s.xy);\nhalf threshold = " + "half(%s + 2.0 * float(%s));\nhalf2 middle = half2((%s.zw - %s.xy) - 2.0 * " + "float(threshold));\nif (translatedFragPos.x >= threshold && translatedFragPos.x < " + "middle.x + threshold) {\n translatedFragPos.x = threshold;\n} else if " + "(translatedFragPos.x >= middle.x + threshold) {\n translatedFragPos.x -= " + "float(middle.x) - 1.0;\n}\nif (translatedFragPos.y > threshold && " + "translatedFragPos.y < middle.y + threshold) {\n translatedFr", + args.fUniformHandler->getUniformCStr(fProxyRectVar), + args.fUniformHandler->getUniformCStr(fCornerRadiusVar), + args.fUniformHandler->getUniformCStr(fBlurRadiusVar), + args.fUniformHandler->getUniformCStr(fProxyRectVar), + args.fUniformHandler->getUniformCStr(fProxyRectVar)); + fragBuilder->codeAppendf( + "agPos.y = threshold;\n} else if (translatedFragPos.y >= middle.y + threshold) {\n " + " translatedFragPos.y -= float(middle.y) - 1.0;\n}\nhalf2 proxyDims = " + "half2(half(2.0 * float(threshold) + 1.0));\nhalf2 texCoord = translatedFragPos / " + "proxyDims;\n%s = %s * texture(%s, float2(texCoord)).%s;\n", + args.fOutputColor, args.fInputColor ? args.fInputColor : "half4(1)", + fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]).c_str(), + fragBuilder->getProgramBuilder()->samplerSwizzle(args.fTexSamplers[0]).c_str()); + } + +private: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& _proc) override { + const GrRRectBlurEffect& _outer = _proc.cast(); + { pdman.set1f(fCornerRadiusVar, _outer.cornerRadius()); } + auto sigma = _outer.sigma(); + (void)sigma; + auto rect = _outer.rect(); + (void)rect; + UniformHandle& cornerRadius = fCornerRadiusVar; + (void)cornerRadius; + GrSurfaceProxy& ninePatchSamplerProxy = *_outer.textureSampler(0).proxy(); + GrTexture& ninePatchSampler = *ninePatchSamplerProxy.priv().peekTexture(); + (void)ninePatchSampler; + UniformHandle& proxyRect = fProxyRectVar; + (void)proxyRect; + UniformHandle& blurRadius = fBlurRadiusVar; + (void)blurRadius; + + float blurRadiusValue = 3.f * SkScalarCeilToScalar(sigma - 1 / 6.0f); + pdman.set1f(blurRadius, blurRadiusValue); + + SkRect outset = rect; + outset.outset(blurRadiusValue, blurRadiusValue); + pdman.set4f(proxyRect, outset.fLeft, outset.fTop, outset.fRight, outset.fBottom); + } + UniformHandle fProxyRectVar; + UniformHandle fBlurRadiusVar; + UniformHandle fCornerRadiusVar; + UniformHandle fNinePatchSamplerVar; +}; +GrGLSLFragmentProcessor* GrRRectBlurEffect::onCreateGLSLInstance() const { + return new GrGLSLRRectBlurEffect(); +} +void GrRRectBlurEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const {} +bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const { + const GrRRectBlurEffect& that = other.cast(); + (void)that; + if (fSigma != that.fSigma) return false; + if (fRect != that.fRect) return false; + if (fCornerRadius != that.fCornerRadius) return false; + if (fNinePatchSampler != that.fNinePatchSampler) return false; + return true; +} +GrRRectBlurEffect::GrRRectBlurEffect(const GrRRectBlurEffect& src) + : INHERITED(kGrRRectBlurEffect_ClassID, src.optimizationFlags()) + , fSigma(src.fSigma) + , fRect(src.fRect) + , fCornerRadius(src.fCornerRadius) + , fNinePatchSampler(src.fNinePatchSampler) { + this->addTextureSampler(&fNinePatchSampler); +} +std::unique_ptr GrRRectBlurEffect::clone() const { + return std::unique_ptr(new GrRRectBlurEffect(*this)); +} +GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect); +#if GR_TEST_UTILS +std::unique_ptr GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) { + SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f); + SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f); + SkScalar r = d->fRandom->nextRangeF(1.f, 9.f); + SkScalar sigma = d->fRandom->nextRangeF(1.f, 10.f); + SkRRect rrect; + rrect.setRectXY(SkRect::MakeWH(w, h), r, r); + return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect); +} +#endif +#endif diff --git a/src/gpu/effects/GrRRectBlurEffect.fp b/src/gpu/effects/GrRRectBlurEffect.fp new file mode 100644 index 0000000000..c920efd581 --- /dev/null +++ b/src/gpu/effects/GrRRectBlurEffect.fp @@ -0,0 +1,183 @@ +in float sigma; +layout(ctype=SkRect) in float4 rect; +in uniform float cornerRadius; +in uniform sampler2D ninePatchSampler; +layout(ctype=SkRect) uniform float4 proxyRect; +uniform half blurRadius; + +@header { + #include "GrClip.h" + #include "GrContext.h" + #include "GrPaint.h" + #include "GrRenderTargetContext.h" + #include "GrStyle.h" + #include "SkBlurMaskFilter.h" + #include "SkGpuBlurUtils.h" +} + +@class { + static sk_sp find_or_create_rrect_blur_mask(GrContext* context, + const SkRRect& rrectToDraw, + const SkISize& size, + float xformedSigma) { + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); + GrUniqueKey key; + GrUniqueKey::Builder builder(&key, kDomain, 9); + builder[0] = SkScalarCeilToInt(xformedSigma-1/6.0f); + + int index = 1; + for (auto c : { SkRRect::kUpperLeft_Corner, SkRRect::kUpperRight_Corner, + SkRRect::kLowerRight_Corner, SkRRect::kLowerLeft_Corner }) { + SkASSERT(SkScalarIsInt(rrectToDraw.radii(c).fX) && + SkScalarIsInt(rrectToDraw.radii(c).fY)); + builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fX); + builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fY); + } + builder.finish(); + + sk_sp mask(context->resourceProvider()->findOrCreateProxyByUniqueKey( + key, kBottomLeft_GrSurfaceOrigin)); + if (!mask) { + // TODO: this could be approx but the texture coords will need to be updated + sk_sp rtc(context->makeDeferredRenderTargetContextWithFallback( + SkBackingFit::kExact, size.fWidth, size.fHeight, kAlpha_8_GrPixelConfig, nullptr)); + if (!rtc) { + return nullptr; + } + + GrPaint paint; + + rtc->clear(nullptr, 0x0, GrRenderTargetContext::CanClearFullscreen::kYes); + rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw, + GrStyle::SimpleFill()); + + sk_sp srcProxy(rtc->asTextureProxyRef()); + if (!srcProxy) { + return nullptr; + } + sk_sp rtc2( + SkGpuBlurUtils::GaussianBlur(context, + std::move(srcProxy), + nullptr, + SkIRect::MakeWH(size.fWidth, size.fHeight), + SkIRect::EmptyIRect(), + xformedSigma, + xformedSigma, + GrTextureDomain::kIgnore_Mode, + SkBackingFit::kExact)); + if (!rtc2) { + return nullptr; + } + + mask = rtc2->asTextureProxyRef(); + if (!mask) { + return nullptr; + } + SkASSERT(mask->origin() == kBottomLeft_GrSurfaceOrigin); + context->resourceProvider()->assignUniqueKeyToProxy(key, mask.get()); + } + + return mask; + } +} + +@optimizationFlags { + kCompatibleWithCoverageAsAlpha_OptimizationFlag +} + +@make { + static std::unique_ptr Make(GrContext* context, float sigma, + float xformedSigma, + const SkRRect& srcRRect, + const SkRRect& devRRect); +} + +@cpp { + std::unique_ptr GrRRectBlurEffect::Make(GrContext* context, float sigma, + float xformedSigma, + const SkRRect& srcRRect, + const SkRRect& devRRect) { + SkASSERT(!devRRect.isCircle() && !devRRect.isRect()); // Should've been caught up-stream + + // TODO: loosen this up + if (!devRRect.isSimpleCircular()) { + return nullptr; + } + + // Make sure we can successfully ninepatch this rrect -- the blur sigma has to be + // sufficiently small relative to both the size of the corner radius and the + // width (and height) of the rrect. + SkRRect rrectToDraw; + SkISize size; + SkScalar ignored[SkBlurMaskFilter::kMaxDivisions]; + int ignoredSize; + uint32_t ignored32; + + bool ninePatchable = SkBlurMaskFilter::ComputeBlurredRRectParams(srcRRect, devRRect, + SkRect::MakeEmpty(), + sigma, xformedSigma, + &rrectToDraw, &size, + ignored, ignored, + ignored, ignored, + &ignoredSize, &ignoredSize, + &ignored32); + if (!ninePatchable) { + return nullptr; + } + + sk_sp mask(find_or_create_rrect_blur_mask(context, rrectToDraw, + size, xformedSigma)); + if (!mask) { + return nullptr; + } + + return std::unique_ptr( + new GrRRectBlurEffect(xformedSigma, devRRect.getBounds(), + devRRect.getSimpleRadii().fX, std::move(mask))); + } +} + +@test(d) { + SkScalar w = d->fRandom->nextRangeScalar(100.f, 1000.f); + SkScalar h = d->fRandom->nextRangeScalar(100.f, 1000.f); + SkScalar r = d->fRandom->nextRangeF(1.f, 9.f); + SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f); + SkRRect rrect; + rrect.setRectXY(SkRect::MakeWH(w, h), r, r); + return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect); +} + +void main() { + // warp the fragment position to the appropriate part of the 9patch blur texture + + half2 rectCenter = (proxyRect.xy + proxyRect.zw) / 2.0; + half2 translatedFragPos = sk_FragCoord.xy - proxyRect.xy; + half threshold = cornerRadius + 2.0 * blurRadius; + half2 middle = proxyRect.zw - proxyRect.xy - 2.0 * threshold; + + if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x + threshold)) { + translatedFragPos.x = threshold; + } else if (translatedFragPos.x >= (middle.x + threshold)) { + translatedFragPos.x -= middle.x - 1.0; + } + + if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) { + translatedFragPos.y = threshold; + } else if (translatedFragPos.y >= (middle.y + threshold)) { + translatedFragPos.y -= middle.y - 1.0; + } + + half2 proxyDims = half2(2.0 * threshold + 1.0); + half2 texCoord = translatedFragPos / proxyDims; + + sk_OutColor = sk_InColor * texture(ninePatchSampler, texCoord); +} + +@setData(pdman) { + float blurRadiusValue = 3.f * SkScalarCeilToScalar(sigma - 1 / 6.0f); + pdman.set1f(blurRadius, blurRadiusValue); + + SkRect outset = rect; + outset.outset(blurRadiusValue, blurRadiusValue); + pdman.set4f(proxyRect, outset.fLeft, outset.fTop, outset.fRight, outset.fBottom); +} diff --git a/src/gpu/effects/GrRRectBlurEffect.h b/src/gpu/effects/GrRRectBlurEffect.h new file mode 100644 index 0000000000..def7244181 --- /dev/null +++ b/src/gpu/effects/GrRRectBlurEffect.h @@ -0,0 +1,124 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* + * This file was autogenerated from GrRRectBlurEffect.fp; do not modify. + */ +#ifndef GrRRectBlurEffect_DEFINED +#define GrRRectBlurEffect_DEFINED +#include "SkTypes.h" +#if SK_SUPPORT_GPU + +#include "GrClip.h" +#include "GrContext.h" +#include "GrPaint.h" +#include "GrRenderTargetContext.h" +#include "GrStyle.h" +#include "SkBlurMaskFilter.h" +#include "SkGpuBlurUtils.h" +#include "GrFragmentProcessor.h" +#include "GrCoordTransform.h" +class GrRRectBlurEffect : public GrFragmentProcessor { +public: + static sk_sp find_or_create_rrect_blur_mask(GrContext* context, + const SkRRect& rrectToDraw, + const SkISize& size, + float xformedSigma) { + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); + GrUniqueKey key; + GrUniqueKey::Builder builder(&key, kDomain, 9); + builder[0] = SkScalarCeilToInt(xformedSigma - 1 / 6.0f); + + int index = 1; + for (auto c : {SkRRect::kUpperLeft_Corner, SkRRect::kUpperRight_Corner, + SkRRect::kLowerRight_Corner, SkRRect::kLowerLeft_Corner}) { + SkASSERT(SkScalarIsInt(rrectToDraw.radii(c).fX) && + SkScalarIsInt(rrectToDraw.radii(c).fY)); + builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fX); + builder[index++] = SkScalarCeilToInt(rrectToDraw.radii(c).fY); + } + builder.finish(); + + sk_sp mask(context->resourceProvider()->findOrCreateProxyByUniqueKey( + key, kBottomLeft_GrSurfaceOrigin)); + if (!mask) { + // TODO: this could be approx but the texture coords will need to be updated + sk_sp rtc(context->makeDeferredRenderTargetContextWithFallback( + SkBackingFit::kExact, size.fWidth, size.fHeight, kAlpha_8_GrPixelConfig, + nullptr)); + if (!rtc) { + return nullptr; + } + + GrPaint paint; + + rtc->clear(nullptr, 0x0, GrRenderTargetContext::CanClearFullscreen::kYes); + rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw, + GrStyle::SimpleFill()); + + sk_sp srcProxy(rtc->asTextureProxyRef()); + if (!srcProxy) { + return nullptr; + } + sk_sp rtc2( + SkGpuBlurUtils::GaussianBlur(context, + std::move(srcProxy), + nullptr, + SkIRect::MakeWH(size.fWidth, size.fHeight), + SkIRect::EmptyIRect(), + xformedSigma, + xformedSigma, + GrTextureDomain::kIgnore_Mode, + SkBackingFit::kExact)); + if (!rtc2) { + return nullptr; + } + + mask = rtc2->asTextureProxyRef(); + if (!mask) { + return nullptr; + } + SkASSERT(mask->origin() == kBottomLeft_GrSurfaceOrigin); + context->resourceProvider()->assignUniqueKeyToProxy(key, mask.get()); + } + + return mask; + } + float sigma() const { return fSigma; } + SkRect rect() const { return fRect; } + float cornerRadius() const { return fCornerRadius; } + + static std::unique_ptr Make(GrContext* context, float sigma, + float xformedSigma, const SkRRect& srcRRect, + const SkRRect& devRRect); + GrRRectBlurEffect(const GrRRectBlurEffect& src); + std::unique_ptr clone() const override; + const char* name() const override { return "RRectBlurEffect"; } + +private: + GrRRectBlurEffect(float sigma, SkRect rect, float cornerRadius, + sk_sp ninePatchSampler) + : INHERITED(kGrRRectBlurEffect_ClassID, + (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag) + , fSigma(sigma) + , fRect(rect) + , fCornerRadius(cornerRadius) + , fNinePatchSampler(std::move(ninePatchSampler)) { + this->addTextureSampler(&fNinePatchSampler); + } + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; + bool onIsEqual(const GrFragmentProcessor&) const override; + GR_DECLARE_FRAGMENT_PROCESSOR_TEST + float fSigma; + SkRect fRect; + float fCornerRadius; + TextureSampler fNinePatchSampler; + typedef GrFragmentProcessor INHERITED; +}; +#endif +#endif diff --git a/src/gpu/glsl/GrGLSLFragmentProcessor.h b/src/gpu/glsl/GrGLSLFragmentProcessor.h index 74cfc4e044..0fed0ea6ef 100644 --- a/src/gpu/glsl/GrGLSLFragmentProcessor.h +++ b/src/gpu/glsl/GrGLSLFragmentProcessor.h @@ -134,8 +134,6 @@ public: void setData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& processor); - static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {} - int numChildProcessors() const { return fChildProcessors.count(); } GrGLSLFragmentProcessor* childProcessor(int index) {