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:
parent
5ade1f6fd9
commit
297d6efe85
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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,
|
||||
|
166
src/gpu/effects/GrRRectBlurEffect.cpp
Normal file
166
src/gpu/effects/GrRRectBlurEffect.cpp
Normal 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
|
183
src/gpu/effects/GrRRectBlurEffect.fp
Normal file
183
src/gpu/effects/GrRRectBlurEffect.fp
Normal 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);
|
||||
}
|
124
src/gpu/effects/GrRRectBlurEffect.h
Normal file
124
src/gpu/effects/GrRRectBlurEffect.h
Normal 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
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user