diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkBlurImageFilter.cpp | 17 | ||||
-rw-r--r-- | src/core/SkBlurMF.cpp | 3 | ||||
-rw-r--r-- | src/core/SkGpuBlurUtils.cpp | 480 | ||||
-rw-r--r-- | src/core/SkGpuBlurUtils.h | 1 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice.cpp | 6 | ||||
-rw-r--r-- | src/gpu/effects/GrRRectBlurEffect.h | 1 |
6 files changed, 302 insertions, 206 deletions
diff --git a/src/core/SkBlurImageFilter.cpp b/src/core/SkBlurImageFilter.cpp index abdf8cdc48..aa566a49f6 100644 --- a/src/core/SkBlurImageFilter.cpp +++ b/src/core/SkBlurImageFilter.cpp @@ -650,14 +650,15 @@ sk_sp<SkSpecialImage> SkBlurImageFilterImpl::gpuFilter( // Then, when we create the output image later, we tag it with the input's color space, so // it will be tagged correctly, regardless of how we created the intermediate RTCs. sk_sp<GrRenderTargetContext> renderTargetContext(SkGpuBlurUtils::GaussianBlur( - context, - std::move(inputTexture), - outProps.colorSpace() ? sk_ref_sp(input->getColorSpace()) : nullptr, - dstBounds, - inputBounds, - sigma.x(), - sigma.y(), - to_texture_domain_mode(fTileMode))); + context, + std::move(inputTexture), + outProps.colorSpace() ? sk_ref_sp(input->getColorSpace()) : nullptr, + dstBounds, + inputBounds, + sigma.x(), + sigma.y(), + to_texture_domain_mode(fTileMode), + input->alphaType())); if (!renderTargetContext) { return nullptr; } diff --git a/src/core/SkBlurMF.cpp b/src/core/SkBlurMF.cpp index baa656597f..8bae1f05f1 100644 --- a/src/core/SkBlurMF.cpp +++ b/src/core/SkBlurMF.cpp @@ -954,7 +954,8 @@ sk_sp<GrTextureProxy> SkBlurMaskFilterImpl::filterMaskGPU(GrContext* context, SkIRect::EmptyIRect(), xformedSigma, xformedSigma, - GrTextureDomain::kIgnore_Mode)); + GrTextureDomain::kIgnore_Mode, + kPremul_SkAlphaType)); if (!renderTargetContext) { return nullptr; } diff --git a/src/core/SkGpuBlurUtils.cpp b/src/core/SkGpuBlurUtils.cpp index fe614bd0df..04ca7d9b48 100644 --- a/src/core/SkGpuBlurUtils.cpp +++ b/src/core/SkGpuBlurUtils.cpp @@ -18,6 +18,8 @@ #include "effects/GrGaussianConvolutionFragmentProcessor.h" #include "effects/GrMatrixConvolutionEffect.h" +#include "SkGr.h" + #define MAX_BLUR_SIGMA 4.0f using Direction = GrGaussianConvolutionFragmentProcessor::Direction; @@ -91,17 +93,48 @@ static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext, SkRect::Make(dstRect), localMatrix); } -static void convolve_gaussian_2d(GrRenderTargetContext* renderTargetContext, - const GrClip& clip, - const SkIRect& dstRect, - const SkIPoint& srcOffset, - sk_sp<GrTextureProxy> proxy, - int radiusX, - int radiusY, - SkScalar sigmaX, - SkScalar sigmaY, - const SkIRect& srcBounds, - GrTextureDomain::Mode mode) { +static GrPixelConfig get_blur_config(GrTextureProxy* proxy, SkColorSpace* cs) { + GrPixelConfig config = proxy->config(); + + if (GrPixelConfigIsSRGB(config) && !cs) { + // If the context doesn't have sRGB write control, and we make an sRGB RTC, we won't be + // able to suppress the linear -> sRGB conversion out of the shader. Not all GL drivers + // have that feature, and Vulkan is missing it entirely. To keep things simple, switch to + // a non-sRGB destination, to ensure correct blurring behavior. + config = kRGBA_8888_GrPixelConfig; + } + + SkASSERT(kBGRA_8888_GrPixelConfig == config || kRGBA_8888_GrPixelConfig == config || + kRGB_888_GrPixelConfig == config || kRGBA_4444_GrPixelConfig == config || + kRGB_565_GrPixelConfig == config || kSRGBA_8888_GrPixelConfig == config || + kSBGRA_8888_GrPixelConfig == config || kRGBA_half_GrPixelConfig == config || + kAlpha_8_GrPixelConfig == config || kRGBA_1010102_GrPixelConfig == config); + + return config; +} + +static sk_sp<GrRenderTargetContext> convolve_gaussian_2d(GrContext* context, + sk_sp<GrTextureProxy> proxy, + const SkIRect& srcBounds, + const SkIPoint& srcOffset, + int radiusX, + int radiusY, + SkScalar sigmaX, + SkScalar sigmaY, + GrTextureDomain::Mode mode, + const SkImageInfo& dstII, + SkBackingFit dstFit) { + + GrPixelConfig config = get_blur_config(proxy.get(), dstII.colorSpace()); + + sk_sp<GrRenderTargetContext> renderTargetContext; + renderTargetContext = context->contextPriv().makeDeferredRenderTargetContext( + dstFit, dstII.width(), dstII.height(), + config, dstII.refColorSpace()); + if (!renderTargetContext) { + return nullptr; + } + SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()), -SkIntToScalar(srcOffset.y())); SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); @@ -113,28 +146,50 @@ static void convolve_gaussian_2d(GrRenderTargetContext* renderTargetContext, kernelOffset, mode, true, sigmaX, sigmaY); paint.addColorFragmentProcessor(std::move(conv)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + GrFixedClip clip(dstII.bounds()); + renderTargetContext->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), - SkRect::Make(dstRect), localMatrix); + SkRect::Make(dstII.bounds()), localMatrix); + + return renderTargetContext; } -static void convolve_gaussian(GrRenderTargetContext* renderTargetContext, - const GrClip& clip, - const SkIRect& srcRect, - sk_sp<GrTextureProxy> proxy, - Direction direction, - int radius, - float sigma, - const SkIRect& srcBounds, - const SkIPoint& srcOffset, - GrTextureDomain::Mode mode) { +static sk_sp<GrRenderTargetContext> convolve_gaussian(GrContext* context, + sk_sp<GrTextureProxy> proxy, + const SkIRect& srcRect, + const SkIPoint& srcOffset, + Direction direction, + int radius, + float sigma, + const SkIRect& srcBounds, + GrTextureDomain::Mode mode, + const SkImageInfo& dstII, + SkBackingFit fit) { + SkASSERT(srcRect.width() <= dstII.width() && srcRect.height() <= dstII.height()); + + GrPixelConfig config = get_blur_config(proxy.get(), dstII.colorSpace()); + + sk_sp<GrRenderTargetContext> dstRenderTargetContext; + dstRenderTargetContext = context->contextPriv().makeDeferredRenderTargetContext( + fit, srcRect.width(), + srcRect.height(), + config, + dstII.refColorSpace()); + if (!dstRenderTargetContext) { + return nullptr; + } + + GrFixedClip clip(dstII.bounds()); + int bounds[2] = { 0, 0 }; SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height()); if (GrTextureDomain::kIgnore_Mode == mode) { - convolve_gaussian_1d(renderTargetContext, clip, dstRect, srcOffset, + convolve_gaussian_1d(dstRenderTargetContext.get(), clip, dstRect, srcOffset, std::move(proxy), direction, radius, sigma, GrTextureDomain::kIgnore_Mode, bounds); - return; + return dstRenderTargetContext; } + SkIRect midRect = srcBounds, leftRect, rightRect; midRect.offset(srcOffset); SkIRect topRect, bottomRect; @@ -162,31 +217,190 @@ static void convolve_gaussian(GrRenderTargetContext* renderTargetContext, dstRect.fRight = midRect.right(); } if (!topRect.isEmpty()) { - renderTargetContext->clear(&topRect, 0, GrRenderTargetContext::CanClearFullscreen::kNo); + dstRenderTargetContext->clear(&topRect, 0, GrRenderTargetContext::CanClearFullscreen::kNo); } if (!bottomRect.isEmpty()) { - renderTargetContext->clear(&bottomRect, 0, GrRenderTargetContext::CanClearFullscreen::kNo); + dstRenderTargetContext->clear(&bottomRect, 0, + GrRenderTargetContext::CanClearFullscreen::kNo); } if (midRect.isEmpty()) { // Blur radius covers srcBounds; use bounds over entire draw - convolve_gaussian_1d(renderTargetContext, clip, dstRect, srcOffset, + convolve_gaussian_1d(dstRenderTargetContext.get(), clip, dstRect, srcOffset, std::move(proxy), direction, radius, sigma, mode, bounds); } else { // Draw right and left margins with bounds; middle without. - convolve_gaussian_1d(renderTargetContext, clip, leftRect, srcOffset, + convolve_gaussian_1d(dstRenderTargetContext.get(), clip, leftRect, srcOffset, proxy, direction, radius, sigma, mode, bounds); - convolve_gaussian_1d(renderTargetContext, clip, rightRect, srcOffset, + convolve_gaussian_1d(dstRenderTargetContext.get(), clip, rightRect, srcOffset, proxy, direction, radius, sigma, mode, bounds); - convolve_gaussian_1d(renderTargetContext, clip, midRect, srcOffset, + convolve_gaussian_1d(dstRenderTargetContext.get(), clip, midRect, srcOffset, std::move(proxy), direction, radius, sigma, GrTextureDomain::kIgnore_Mode, bounds); } + + return dstRenderTargetContext; +} + +static sk_sp<GrTextureProxy> decimate(GrContext* context, + sk_sp<GrTextureProxy> src, + SkIRect* srcRect, SkIPoint* srcOffset, + const SkIRect& localSrcBounds, + int scaleFactorX, int scaleFactorY, + bool willBeXFiltering, bool willBeYFiltering, + int radiusX, int radiusY, + GrTextureDomain::Mode mode, + const SkImageInfo& dstII, + SkBackingFit fit) { + SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY)); + SkASSERT(scaleFactorX > 1 ||scaleFactorY > 1); + + GrPixelConfig config = get_blur_config(src.get(), dstII.colorSpace()); + + // GrTextureDomainEffect does not support kRepeat_Mode with GrSamplerState::Filter. + GrTextureDomain::Mode modeForScaling = GrTextureDomain::kRepeat_Mode == mode + ? GrTextureDomain::kDecal_Mode + : mode; + + sk_sp<GrRenderTargetContext> dstRenderTargetContext; + + for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { + SkIRect dstRect(*srcRect); + shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY); + + dstRenderTargetContext = context->contextPriv().makeDeferredRenderTargetContext( + fit, + SkTMin(dstRect.fRight, dstII.width()), + SkTMin(dstRect.fBottom, dstII.height()), + config, dstII.refColorSpace()); + if (!dstRenderTargetContext) { + return nullptr; + } + + GrPaint paint; + paint.setGammaCorrect(dstRenderTargetContext->colorSpaceInfo().isGammaCorrect()); + + if (GrTextureDomain::kIgnore_Mode != mode && i == 1) { + SkRect domain = SkRect::Make(localSrcBounds); + domain.inset((i < scaleFactorX) ? SK_ScalarHalf : 0.0f, + (i < scaleFactorY) ? SK_ScalarHalf : 0.0f); + auto fp = GrTextureDomainEffect::Make(std::move(src), + SkMatrix::I(), + domain, + modeForScaling, + GrSamplerState::Filter::kBilerp); + paint.addColorFragmentProcessor(std::move(fp)); + srcRect->offset(-(*srcOffset)); + srcOffset->set(0, 0); + } else { + paint.addColorTextureProcessor(std::move(src), SkMatrix::I(), + GrSamplerState::ClampBilerp()); + } + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + + dstRenderTargetContext->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, + SkMatrix::I(), SkRect::Make(dstRect), + SkRect::Make(*srcRect)); + + src = dstRenderTargetContext->asTextureProxyRef(); + if (!src) { + return nullptr; + } + *srcRect = dstRect; + } + + SkASSERT(dstRenderTargetContext); + + if (willBeXFiltering) { + if (scaleFactorX > 1) { + // Clear out a radius to the right of the srcRect to prevent the + // X convolution from reading garbage. + SkIRect clearRect = SkIRect::MakeXYWH(srcRect->fRight, srcRect->fTop, + radiusX, srcRect->height()); + dstRenderTargetContext->priv().absClear(&clearRect, 0x0); + } + } else { + if (scaleFactorY > 1) { + // Clear out a radius below the srcRect to prevent the Y + // convolution from reading garbage. + SkIRect clearRect = SkIRect::MakeXYWH(srcRect->fLeft, srcRect->fBottom, + srcRect->width(), radiusY); + dstRenderTargetContext->priv().absClear(&clearRect, 0x0); + } + } + + return dstRenderTargetContext->asTextureProxyRef(); +} + +static sk_sp<GrRenderTargetContext> reexpand(GrContext* context, + sk_sp<GrRenderTargetContext> dstRenderTargetContext, + const SkIRect& srcRect, + const SkIRect& localSrcBounds, + int scaleFactorX, int scaleFactorY, + GrTextureDomain::Mode mode, + const SkImageInfo& dstII, + SkBackingFit fit) { + sk_sp<GrTextureProxy> srcProxy = dstRenderTargetContext->asTextureProxyRef(); + if (!srcProxy) { + return nullptr; + } + + GrPixelConfig config = get_blur_config(srcProxy.get(), dstII.colorSpace()); + + // GrTextureDomainEffect does not support kRepeat_Mode with GrSamplerState::Filter. + GrTextureDomain::Mode modeForScaling = GrTextureDomain::kRepeat_Mode == mode + ? GrTextureDomain::kDecal_Mode + : mode; + + // Clear one pixel to the right and below, to accommodate bilinear upsampling. + // TODO: it seems like we should actually be clamping here rather than darkening + // the bottom right edges. + SkIRect clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1); + dstRenderTargetContext->priv().absClear(&clearRect, 0x0); + clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, 1, srcRect.height()); + dstRenderTargetContext->priv().absClear(&clearRect, 0x0); + + SkIRect dstRect(srcRect); + scale_irect(&dstRect, scaleFactorX, scaleFactorY); + + dstRenderTargetContext = context->contextPriv().makeDeferredRenderTargetContext( + fit, + SkTMin(dstRect.width(), dstII.width()), + SkTMin(dstRect.height(), dstII.height()), + config, dstII.refColorSpace()); + if (!dstRenderTargetContext) { + return nullptr; + } + + GrPaint paint; + paint.setGammaCorrect(dstRenderTargetContext->colorSpaceInfo().isGammaCorrect()); + + if (GrTextureDomain::kIgnore_Mode != mode) { + SkRect domain = SkRect::Make(localSrcBounds); + auto fp = GrTextureDomainEffect::Make(std::move(srcProxy), + SkMatrix::I(), + domain, + modeForScaling, + GrSamplerState::Filter::kBilerp); + paint.addColorFragmentProcessor(std::move(fp)); + } else { + // FIXME: this should be mitchell, not bilinear. + paint.addColorTextureProcessor(std::move(srcProxy), SkMatrix::I(), + GrSamplerState::ClampBilerp()); + } + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + GrFixedClip clip(dstII.bounds()); + + dstRenderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstRect), SkRect::Make(srcRect)); + + return dstRenderTargetContext; } namespace SkGpuBlurUtils { +// TODO: the 'fit' field actually only needs to apply to the final, returned GrRenderTargetContext sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context, sk_sp<GrTextureProxy> srcProxy, sk_sp<SkColorSpace> colorSpace, @@ -195,9 +409,19 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context, float sigmaX, float sigmaY, GrTextureDomain::Mode mode, + SkAlphaType at, SkBackingFit fit) { SkASSERT(context); - SkIRect clearRect; + + const GrPixelConfig config = get_blur_config(srcProxy.get(), colorSpace.get()); + SkColorType ct; + if (!GrPixelConfigToColorType(config, &ct)) { + return nullptr; + } + + const SkImageInfo finalDestII = SkImageInfo::Make(dstBounds.width(), dstBounds.height(), + ct, at, std::move(colorSpace)); + int scaleFactorX, radiusX; int scaleFactorY, radiusY; int maxTextureSize = context->caps()->maxTextureSize(); @@ -206,11 +430,10 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context, SkASSERT(sigmaX || sigmaY); SkIPoint srcOffset = SkIPoint::Make(-dstBounds.x(), -dstBounds.y()); - SkIRect localDstBounds = SkIRect::MakeWH(dstBounds.width(), dstBounds.height()); SkIRect localSrcBounds; SkIRect srcRect; if (GrTextureDomain::kIgnore_Mode == mode) { - srcRect = localDstBounds; + srcRect = finalDestII.bounds(); } else { srcRect = localSrcBounds = srcBounds; srcRect.offset(srcOffset); @@ -219,30 +442,6 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context, scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); scale_irect(&srcRect, scaleFactorX, scaleFactorY); - // setup new clip - GrFixedClip clip(localDstBounds); - - GrPixelConfig config = srcProxy->config(); - - if (GrPixelConfigIsSRGB(config) && !colorSpace) { - // If the context doesn't have sRGB write control, and we make an sRGB RTC, we won't be - // able to suppress the linear -> sRGB conversion out of the shader. Not all GL drivers - // have that feature, and Vulkan is missing it entirely. To keep things simple, switch to - // a non-sRGB destination, to ensure correct blurring behavior. - config = kRGBA_8888_GrPixelConfig; - } - - SkASSERT(kBGRA_8888_GrPixelConfig == config || kRGBA_8888_GrPixelConfig == config || - kRGB_888_GrPixelConfig == config || kRGBA_4444_GrPixelConfig == config || - kRGB_565_GrPixelConfig == config || kSRGBA_8888_GrPixelConfig == config || - kSBGRA_8888_GrPixelConfig == config || kRGBA_half_GrPixelConfig == config || - kAlpha_8_GrPixelConfig == config || kRGBA_1010102_GrPixelConfig == config); - - const int width = dstBounds.width(); - const int height = dstBounds.height(); - - sk_sp<GrRenderTargetContext> dstRenderTargetContext; - // For really small blurs (certainly no wider than 5x5 on desktop gpus) it is faster to just // launch a single non separable kernel vs two launches if (sigmaX > 0.0f && sigmaY > 0.0f && @@ -250,98 +449,48 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context, // We shouldn't be scaling because this is a small size blur SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY)); - dstRenderTargetContext = context->contextPriv().makeDeferredRenderTargetContext( - fit, width, height, config, colorSpace); - if (!dstRenderTargetContext) { - return nullptr; - } - - convolve_gaussian_2d(dstRenderTargetContext.get(), - clip, localDstBounds, srcOffset, std::move(srcProxy), - radiusX, radiusY, sigmaX, sigmaY, srcBounds, mode); - - return dstRenderTargetContext; + return convolve_gaussian_2d(context, std::move(srcProxy), srcBounds, srcOffset, + radiusX, radiusY, sigmaX, sigmaY, + mode, finalDestII, fit); } - SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY)); - - // GrTextureDomainEffect does not support kRepeat_Mode with GrSamplerState::Filter. - GrTextureDomain::Mode modeForScaling = - GrTextureDomain::kRepeat_Mode == mode ? GrTextureDomain::kDecal_Mode : mode; - for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { - SkIRect dstRect(srcRect); - shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY); - - dstRenderTargetContext = context->contextPriv().makeDeferredRenderTargetContext( - fit, - SkTMin(dstRect.fRight, width), - SkTMin(dstRect.fBottom, height), - config, colorSpace); - if (!dstRenderTargetContext) { - return nullptr; - } - - GrPaint paint; - paint.setGammaCorrect(dstRenderTargetContext->colorSpaceInfo().isGammaCorrect()); - - if (GrTextureDomain::kIgnore_Mode != mode && i == 1) { - SkRect domain = SkRect::Make(localSrcBounds); - domain.inset((i < scaleFactorX) ? SK_ScalarHalf : 0.0f, - (i < scaleFactorY) ? SK_ScalarHalf : 0.0f); - auto fp = GrTextureDomainEffect::Make(std::move(srcProxy), - SkMatrix::I(), - domain, - modeForScaling, - GrSamplerState::Filter::kBilerp); - paint.addColorFragmentProcessor(std::move(fp)); - srcRect.offset(-srcOffset); - srcOffset.set(0, 0); - } else { - paint.addColorTextureProcessor(std::move(srcProxy), SkMatrix::I(), - GrSamplerState::ClampBilerp()); - } - paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - - dstRenderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), - SkRect::Make(dstRect), SkRect::Make(srcRect)); - - srcProxy = dstRenderTargetContext->asTextureProxyRef(); + if (scaleFactorX > 1 || scaleFactorY > 1) { + srcProxy = decimate(context, std::move(srcProxy), &srcRect, &srcOffset, localSrcBounds, + scaleFactorX, scaleFactorY, + sigmaX > 0.0f, sigmaY > 0.0f, radiusX, radiusY, + mode, finalDestII, fit); if (!srcProxy) { return nullptr; } - srcRect = dstRect; + localSrcBounds = srcRect; } - srcRect = localDstBounds; + sk_sp<GrRenderTargetContext> dstRenderTargetContext; + + srcRect = finalDestII.bounds(); scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); if (sigmaX > 0.0f) { - if (scaleFactorX > 1) { - SkASSERT(dstRenderTargetContext); - - // Clear out a radius to the right of the srcRect to prevent the - // X convolution from reading garbage. - clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, - radiusX, srcRect.height()); - dstRenderTargetContext->priv().absClear(&clearRect, 0x0); - } - - SkASSERT(srcRect.width() <= width && srcRect.height() <= height); - dstRenderTargetContext = context->contextPriv().makeDeferredRenderTargetContext( - fit, srcRect.width(), - srcRect.height(), - config, colorSpace); + dstRenderTargetContext = convolve_gaussian(context, std::move(srcProxy), srcRect, srcOffset, + Direction::kX, radiusX, sigmaX, localSrcBounds, + mode, finalDestII, fit); if (!dstRenderTargetContext) { return nullptr; } - convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect, std::move(srcProxy), - Direction::kX, radiusX, sigmaX, localSrcBounds, srcOffset, mode); + if (sigmaY > 0.0f) { + // Clear out a radius below the srcRect to prevent the Y + // convolution from reading garbage. + SkIRect clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, + srcRect.width(), radiusY); + dstRenderTargetContext->priv().absClear(&clearRect, 0x0); + } srcProxy = dstRenderTargetContext->asTextureProxyRef(); if (!srcProxy) { return nullptr; } + srcRect.offsetTo(0, 0); localSrcBounds = srcRect; if (GrTextureDomain::kClamp_Mode == mode) { @@ -352,84 +501,29 @@ sk_sp<GrRenderTargetContext> GaussianBlur(GrContext* context, } if (sigmaY > 0.0f) { - if (scaleFactorY > 1 || sigmaX > 0.0f) { - SkASSERT(dstRenderTargetContext); - - // Clear out a radius below the srcRect to prevent the Y - // convolution from reading garbage. - clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, - srcRect.width(), radiusY); - dstRenderTargetContext->priv().absClear(&clearRect, 0x0); - } - - SkASSERT(srcRect.width() <= width && srcRect.height() <= height); - dstRenderTargetContext = context->contextPriv().makeDeferredRenderTargetContext( - fit, srcRect.width(), - srcRect.height(), - config, colorSpace); + dstRenderTargetContext = convolve_gaussian(context, std::move(srcProxy), srcRect, srcOffset, + Direction::kY, radiusY, sigmaY, localSrcBounds, + mode, finalDestII, fit); if (!dstRenderTargetContext) { return nullptr; } - convolve_gaussian(dstRenderTargetContext.get(), clip, srcRect, std::move(srcProxy), - Direction::kY, radiusY, sigmaY, localSrcBounds, srcOffset, mode); - srcProxy = dstRenderTargetContext->asTextureProxyRef(); if (!srcProxy) { return nullptr; } + srcRect.offsetTo(0, 0); + srcOffset.set(0, 0); } SkASSERT(dstRenderTargetContext); SkASSERT(srcProxy.get() == dstRenderTargetContext->asTextureProxy()); if (scaleFactorX > 1 || scaleFactorY > 1) { - // Clear one pixel to the right and below, to accommodate bilinear upsampling. - // TODO: it seems like we should actually be clamping here rather than darkening - // the bottom right edges. - clearRect = SkIRect::MakeXYWH(srcRect.fLeft, srcRect.fBottom, srcRect.width() + 1, 1); - dstRenderTargetContext->priv().absClear(&clearRect, 0x0); - clearRect = SkIRect::MakeXYWH(srcRect.fRight, srcRect.fTop, 1, srcRect.height()); - dstRenderTargetContext->priv().absClear(&clearRect, 0x0); - - SkIRect dstRect(srcRect); - scale_irect(&dstRect, scaleFactorX, scaleFactorY); - - dstRenderTargetContext = context->contextPriv().makeDeferredRenderTargetContext( - fit, SkTMin(dstRect.width(), width), - SkTMin(dstRect.height(), height), - config, colorSpace); - if (!dstRenderTargetContext) { - return nullptr; - } - - GrPaint paint; - paint.setGammaCorrect(dstRenderTargetContext->colorSpaceInfo().isGammaCorrect()); - - if (GrTextureDomain::kIgnore_Mode != mode) { - SkRect domain = SkRect::Make(localSrcBounds); - auto fp = GrTextureDomainEffect::Make(std::move(srcProxy), - SkMatrix::I(), - domain, - modeForScaling, - GrSamplerState::Filter::kBilerp); - paint.addColorFragmentProcessor(std::move(fp)); - } else { - // FIXME: this should be mitchell, not bilinear. - paint.addColorTextureProcessor(std::move(srcProxy), SkMatrix::I(), - GrSamplerState::ClampBilerp()); - } - paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - - dstRenderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), - SkRect::Make(dstRect), SkRect::Make(srcRect)); - - srcProxy = dstRenderTargetContext->asTextureProxyRef(); - if (!srcProxy) { - return nullptr; - } - srcRect = dstRect; + dstRenderTargetContext = reexpand(context, std::move(dstRenderTargetContext), srcRect, + localSrcBounds, scaleFactorX, scaleFactorY, + mode, finalDestII, fit); } return dstRenderTargetContext; diff --git a/src/core/SkGpuBlurUtils.h b/src/core/SkGpuBlurUtils.h index 8a6f7b1922..e06dc8ba2d 100644 --- a/src/core/SkGpuBlurUtils.h +++ b/src/core/SkGpuBlurUtils.h @@ -44,6 +44,7 @@ namespace SkGpuBlurUtils { float sigmaX, float sigmaY, GrTextureDomain::Mode mode, + SkAlphaType at, SkBackingFit fit = SkBackingFit::kApprox); }; diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 138d41f26a..7600a8f1c6 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -1052,7 +1052,7 @@ void SkGpuDevice::drawSprite(const SkBitmap& bitmap, void SkGpuDevice::drawSpecial(SkSpecialImage* special1, int left, int top, const SkPaint& paint, - SkImage* clipImage,const SkMatrix& clipMatrix) { + SkImage* clipImage, const SkMatrix& clipMatrix) { ASSERT_SINGLE_OWNER GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawSpecial", fContext.get()); @@ -1062,9 +1062,7 @@ void SkGpuDevice::drawSpecial(SkSpecialImage* special1, int left, int top, const sk_sp<SkSpecialImage> result; if (paint.getImageFilter()) { - result = this->filterTexture(special1, left, top, - &offset, - paint.getImageFilter()); + result = this->filterTexture(special1, left, top, &offset, paint.getImageFilter()); if (!result) { return; } diff --git a/src/gpu/effects/GrRRectBlurEffect.h b/src/gpu/effects/GrRRectBlurEffect.h index d1316e8a5b..04af1273f7 100644 --- a/src/gpu/effects/GrRRectBlurEffect.h +++ b/src/gpu/effects/GrRRectBlurEffect.h @@ -79,6 +79,7 @@ public: xformedSigma, xformedSigma, GrTextureDomain::kIgnore_Mode, + kPremul_SkAlphaType, SkBackingFit::kExact)); if (!rtc2) { return nullptr; |