aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Ethan Nicholas <ethannicholas@google.com>2017-12-20 12:00:11 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2017-12-20 19:56:36 +0000
commit297d6efe852ebb98a324a71c79df8f7bbdcc3b94 (patch)
treeb5757cfba889257ea6f5ef6cb749f69d20e9296c
parent5ade1f6fd91371a2b985986ff099cc37836a443d (diff)
converted GrRRectBlurEffect to SkSL
Bug: skia: Change-Id: Ifd192db07e02d69d445277a361760ce4a452f603 Reviewed-on: https://skia-review.googlesource.com/87441 Reviewed-by: Greg Daniel <egdaniel@google.com> Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
-rw-r--r--gn/gpu.gni2
-rw-r--r--gn/sksl.gni1
-rw-r--r--src/effects/SkBlurMaskFilter.cpp275
-rw-r--r--src/gpu/effects/GrRRectBlurEffect.cpp166
-rw-r--r--src/gpu/effects/GrRRectBlurEffect.fp183
-rw-r--r--src/gpu/effects/GrRRectBlurEffect.h124
-rw-r--r--src/gpu/glsl/GrGLSLFragmentProcessor.h2
7 files changed, 477 insertions, 276 deletions
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<GrFragmentProcessor> 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<GrFragmentProcessor> clone() const override;
-
-private:
- GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
-
- GrRRectBlurEffect(float sigma, const SkRRect&,
- sk_sp<GrTextureProxy> 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<GrTextureProxy> 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<GrTextureProxy> 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<GrRenderTargetContext> 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<GrTextureProxy> srcProxy(rtc->asTextureProxyRef());
- if (!srcProxy) {
- return nullptr;
- }
- sk_sp<GrRenderTargetContext> 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<GrFragmentProcessor> 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<GrTextureProxy> mask(find_or_create_rrect_blur_mask(context, rrectToDraw,
- size, xformedSigma));
- if (!mask) {
- return nullptr;
- }
-
- return std::unique_ptr<GrFragmentProcessor>(
- new GrRRectBlurEffect(xformedSigma, devRRect, std::move(mask)));
-}
-
-GrRRectBlurEffect::GrRRectBlurEffect(float sigma, const SkRRect& rrect,
- sk_sp<GrTextureProxy> ninePatchProxy)
- : INHERITED(kGrRRectBlurEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag)
- , fRRect(rrect)
- , fSigma(sigma)
- , fNinePatchSampler(std::move(ninePatchProxy)) {
- this->addTextureSampler(&fNinePatchSampler);
-}
-
-std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::clone() const {
- return std::unique_ptr<GrFragmentProcessor>(
- new GrRRectBlurEffect(fSigma, fRRect, sk_ref_sp(fNinePatchSampler.proxy())));
-}
-
-bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const {
- const GrRRectBlurEffect& rrbe = other.cast<GrRRectBlurEffect>();
- 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<GrFragmentProcessor> 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<GrRRectBlurEffect>();
- 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<GrFragmentProcessor> 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<GrTextureProxy> mask(
+ find_or_create_rrect_blur_mask(context, rrectToDraw, size, xformedSigma));
+ if (!mask) {
+ return nullptr;
+ }
+
+ return std::unique_ptr<GrFragmentProcessor>(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<GrRRectBlurEffect>();
+ (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<GrRRectBlurEffect>();
+ { 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<GrRRectBlurEffect>();
+ (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<GrFragmentProcessor> GrRRectBlurEffect::clone() const {
+ return std::unique_ptr<GrFragmentProcessor>(new GrRRectBlurEffect(*this));
+}
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect);
+#if GR_TEST_UTILS
+std::unique_ptr<GrFragmentProcessor> 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<GrTextureProxy> 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<GrTextureProxy> 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<GrRenderTargetContext> 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<GrTextureProxy> srcProxy(rtc->asTextureProxyRef());
+ if (!srcProxy) {
+ return nullptr;
+ }
+ sk_sp<GrRenderTargetContext> 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<GrFragmentProcessor> Make(GrContext* context, float sigma,
+ float xformedSigma,
+ const SkRRect& srcRRect,
+ const SkRRect& devRRect);
+}
+
+@cpp {
+ std::unique_ptr<GrFragmentProcessor> 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<GrTextureProxy> mask(find_or_create_rrect_blur_mask(context, rrectToDraw,
+ size, xformedSigma));
+ if (!mask) {
+ return nullptr;
+ }
+
+ return std::unique_ptr<GrFragmentProcessor>(
+ 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<GrTextureProxy> 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<GrTextureProxy> 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<GrRenderTargetContext> 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<GrTextureProxy> srcProxy(rtc->asTextureProxyRef());
+ if (!srcProxy) {
+ return nullptr;
+ }
+ sk_sp<GrRenderTargetContext> 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<GrFragmentProcessor> Make(GrContext* context, float sigma,
+ float xformedSigma, const SkRRect& srcRRect,
+ const SkRRect& devRRect);
+ GrRRectBlurEffect(const GrRRectBlurEffect& src);
+ std::unique_ptr<GrFragmentProcessor> clone() const override;
+ const char* name() const override { return "RRectBlurEffect"; }
+
+private:
+ GrRRectBlurEffect(float sigma, SkRect rect, float cornerRadius,
+ sk_sp<GrTextureProxy> 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) {