123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- in float sigma;
- layout(ctype=SkRect) in float4 rect;
- in uniform half cornerRadius;
- in uniform sampler2D ninePatchSampler;
- layout(ctype=SkRect) uniform float4 proxyRect;
- uniform half blurRadius;
- @header {
- #include "include/effects/SkBlurMaskFilter.h"
- #include "include/gpu/GrContext.h"
- #include "include/private/GrRecordingContext.h"
- #include "src/core/SkBlurPriv.h"
- #include "src/core/SkGpuBlurUtils.h"
- #include "src/core/SkRRectPriv.h"
- #include "src/gpu/GrCaps.h"
- #include "src/gpu/GrClip.h"
- #include "src/gpu/GrPaint.h"
- #include "src/gpu/GrProxyProvider.h"
- #include "src/gpu/GrRecordingContextPriv.h"
- #include "src/gpu/GrRenderTargetContext.h"
- #include "src/gpu/GrStyle.h"
- }
- @class {
- static sk_sp<GrTextureProxy> find_or_create_rrect_blur_mask(GrRecordingContext* context,
- const SkRRect& rrectToDraw,
- const SkISize& size,
- float xformedSigma) {
- static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
- GrUniqueKey key;
- GrUniqueKey::Builder builder(&key, kDomain, 9, "RoundRect Blur Mask");
- 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();
- GrProxyProvider* proxyProvider = context->priv().proxyProvider();
- sk_sp<GrTextureProxy> mask(proxyProvider->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->priv().makeDeferredRenderTargetContextWithFallback(
- SkBackingFit::kExact, size.fWidth,
- size.fHeight, GrColorType::kAlpha_8, nullptr));
- if (!rtc) {
- return nullptr;
- }
- GrPaint paint;
- rtc->clear(nullptr, SK_PMColor4fTRANSPARENT,
- 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),
- SkIPoint::Make(0, 0),
- nullptr,
- SkIRect::MakeWH(size.fWidth, size.fHeight),
- SkIRect::EmptyIRect(),
- xformedSigma,
- xformedSigma,
- GrTextureDomain::kIgnore_Mode,
- kPremul_SkAlphaType,
- SkBackingFit::kExact));
- if (!rtc2) {
- return nullptr;
- }
- mask = rtc2->asTextureProxyRef();
- if (!mask) {
- return nullptr;
- }
- SkASSERT(mask->origin() == kBottomLeft_GrSurfaceOrigin);
- proxyProvider->assignUniqueKeyToProxy(key, mask.get());
- }
- return mask;
- }
- }
- @optimizationFlags {
- kCompatibleWithCoverageAsAlpha_OptimizationFlag
- }
- @make {
- static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext* context,
- float sigma,
- float xformedSigma,
- const SkRRect& srcRRect,
- const SkRRect& devRRect);
- }
- @cpp {
- std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make(GrRecordingContext* context,
- float sigma,
- float xformedSigma,
- const SkRRect& srcRRect,
- const SkRRect& devRRect) {
- SkASSERT(!SkRRectPriv::IsCircle(devRRect) && !devRRect.isRect()); // Should've been caught up-stream
- // TODO: loosen this up
- if (!SkRRectPriv::IsSimpleCircular(devRRect)) {
- 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[kSkBlurRRectMaxDivisions];
- int ignoredSize;
- uint32_t ignored32;
- bool ninePatchable = SkComputeBlurredRRectParams(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(),
- SkRRectPriv::GetSimpleRadii(devRRect).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 = half2((proxyRect.xy + proxyRect.zw) / 2.0);
- half2 translatedFragPos = half2(sk_FragCoord.xy - proxyRect.xy);
- half threshold = cornerRadius + 2.0 * blurRadius;
- half2 middle = half2(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);
- }
|