diff options
author | 2017-12-20 12:00:11 -0500 | |
---|---|---|
committer | 2017-12-20 19:56:36 +0000 | |
commit | 297d6efe852ebb98a324a71c79df8f7bbdcc3b94 (patch) | |
tree | b5757cfba889257ea6f5ef6cb749f69d20e9296c /src/gpu/effects/GrRRectBlurEffect.fp | |
parent | 5ade1f6fd91371a2b985986ff099cc37836a443d (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>
Diffstat (limited to 'src/gpu/effects/GrRRectBlurEffect.fp')
-rw-r--r-- | src/gpu/effects/GrRRectBlurEffect.fp | 183 |
1 files changed, 183 insertions, 0 deletions
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); +} |