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>
This commit is contained in:
Ethan Nicholas 2017-12-20 12:00:11 -05:00 committed by Skia Commit-Bot
parent 5ade1f6fd9
commit 297d6efe85
7 changed files with 477 additions and 276 deletions

View File

@ -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",

View File

@ -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",

View File

@ -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,

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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) {