| Index: src/effects/SkGpuBlurUtils.cpp
|
| diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp
|
| index 1cb2d1dd125692b5e348491aa6eb81254b119761..c3681faca55f0b0a96d22a1835f882d2ff324070 100644
|
| --- a/src/effects/SkGpuBlurUtils.cpp
|
| +++ b/src/effects/SkGpuBlurUtils.cpp
|
| @@ -165,6 +165,7 @@
|
|
|
| GrTexture* GaussianBlur(GrContext* context,
|
| GrTexture* srcTexture,
|
| + bool canClobberSrc,
|
| bool gammaCorrect,
|
| const SkRect& dstBounds,
|
| const SkRect* srcBounds,
|
| @@ -204,38 +205,11 @@
|
| kSBGRA_8888_GrPixelConfig == srcTexture->config() ||
|
| kAlpha_8_GrPixelConfig == srcTexture->config());
|
|
|
| - const int width = SkScalarFloorToInt(dstBounds.width());
|
| - const int height = SkScalarFloorToInt(dstBounds.height());
|
| - const GrPixelConfig config = srcTexture->config();
|
| -
|
| - const SkSurfaceProps props(gammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0,
|
| - SkSurfaceProps::kLegacyFontHost_InitType);
|
| -
|
| - // 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 &&
|
| - (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) {
|
| - // We shouldn't be scaling because this is a small size blur
|
| - SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY));
|
| -
|
| - sk_sp<GrDrawContext> dstDrawContext(context->newDrawContext(SkBackingFit::kApprox,
|
| - width, height, config,
|
| - 0, kDefault_GrSurfaceOrigin,
|
| - &props));
|
| - if (!dstDrawContext) {
|
| - return nullptr;
|
| - }
|
| - convolve_gaussian_2d(dstDrawContext.get(), clip, localDstBounds, srcOffset,
|
| - srcTexture, radiusX, radiusY, sigmaX, sigmaY, srcBounds);
|
| -
|
| - return dstDrawContext->asTexture().release();
|
| - }
|
| -
|
| GrSurfaceDesc desc;
|
| desc.fFlags = kRenderTarget_GrSurfaceFlag;
|
| - desc.fWidth = width;
|
| - desc.fHeight = height;
|
| - desc.fConfig = config;
|
| + desc.fWidth = SkScalarFloorToInt(dstBounds.width());
|
| + desc.fHeight = SkScalarFloorToInt(dstBounds.height());
|
| + desc.fConfig = srcTexture->config();
|
|
|
| GrTexture* dstTexture;
|
| GrTexture* tempTexture;
|
| @@ -243,10 +217,14 @@
|
|
|
| temp1.reset(context->textureProvider()->createApproxTexture(desc));
|
| dstTexture = temp1.get();
|
| - temp2.reset(context->textureProvider()->createApproxTexture(desc));
|
| - tempTexture = temp2.get();
|
| -
|
| - if (!dstTexture || !tempTexture) {
|
| + if (canClobberSrc) {
|
| + tempTexture = srcTexture;
|
| + } else {
|
| + temp2.reset(context->textureProvider()->createApproxTexture(desc));
|
| + tempTexture = temp2.get();
|
| + }
|
| +
|
| + if (nullptr == dstTexture || nullptr == tempTexture) {
|
| return nullptr;
|
| }
|
|
|
| @@ -263,13 +241,13 @@
|
| matrix.mapRect(&domain, *srcBounds);
|
| domain.inset((i < scaleFactorX) ? SK_ScalarHalf / srcTexture->width() : 0.0f,
|
| (i < scaleFactorY) ? SK_ScalarHalf / srcTexture->height() : 0.0f);
|
| - sk_sp<const GrFragmentProcessor> fp(GrTextureDomainEffect::Create(
|
| - srcTexture,
|
| - matrix,
|
| - domain,
|
| - GrTextureDomain::kDecal_Mode,
|
| - GrTextureParams::kBilerp_FilterMode));
|
| - paint.addColorFragmentProcessor(fp.get());
|
| + SkAutoTUnref<const GrFragmentProcessor> fp(GrTextureDomainEffect::Create(
|
| + srcTexture,
|
| + matrix,
|
| + domain,
|
| + GrTextureDomain::kDecal_Mode,
|
| + GrTextureParams::kBilerp_FilterMode));
|
| + paint.addColorFragmentProcessor(fp);
|
| srcRect.offset(-srcOffset);
|
| srcOffset.set(0, 0);
|
| } else {
|
| @@ -294,77 +272,100 @@
|
| localSrcBounds = srcRect;
|
| }
|
|
|
| + SkSurfaceProps props(gammaCorrect ? SkSurfaceProps::kGammaCorrect_Flag : 0,
|
| + SkSurfaceProps::kLegacyFontHost_InitType);
|
| +
|
| + // 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
|
| srcRect = localDstBounds;
|
| -
|
| - scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
|
| - srcRect.roundOut(&srcRect);
|
| - SkIRect srcIRect = srcRect.roundOut();
|
| - if (sigmaX > 0.0f) {
|
| - if (scaleFactorX > 1) {
|
| - // TODO: if we pass in the source draw context we don't need this here
|
| - if (!srcDrawContext) {
|
| - srcDrawContext = context->drawContext(sk_ref_sp(srcTexture->asRenderTarget()));
|
| - if (!srcDrawContext) {
|
| - return nullptr;
|
| - }
|
| - }
|
| -
|
| - // Clear out a radius to the right of the srcRect to prevent the
|
| - // X convolution from reading garbage.
|
| - clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
|
| - radiusX, srcIRect.height());
|
| - srcDrawContext->clear(&clearRect, 0x0, false);
|
| - }
|
| + if (sigmaX > 0.0f && sigmaY > 0.0f &&
|
| + (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) {
|
| + // We shouldn't be scaling because this is a small size blur
|
| + SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY));
|
|
|
| sk_sp<GrDrawContext> dstDrawContext(
|
| context->drawContext(sk_ref_sp(dstTexture->asRenderTarget()), &props));
|
| if (!dstDrawContext) {
|
| return nullptr;
|
| }
|
| - convolve_gaussian(dstDrawContext.get(), clip, srcRect,
|
| - srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, sigmaX,
|
| - srcBounds, srcOffset);
|
| + convolve_gaussian_2d(dstDrawContext.get(), clip, srcRect, srcOffset,
|
| + srcTexture, radiusX, radiusY, sigmaX, sigmaY, srcBounds);
|
| +
|
| srcDrawContext.swap(dstDrawContext);
|
| + srcRect.offsetTo(0, 0);
|
| srcTexture = dstTexture;
|
| - srcRect.offsetTo(0, 0);
|
| SkTSwap(dstTexture, tempTexture);
|
| - localSrcBounds = srcRect;
|
| - srcOffset.set(0, 0);
|
| - }
|
| -
|
| - if (sigmaY > 0.0f) {
|
| - if (scaleFactorY > 1 || sigmaX > 0.0f) {
|
| - // TODO: if we pass in the source draw context we don't need this here
|
| - if (!srcDrawContext) {
|
| - srcDrawContext = context->drawContext(sk_ref_sp(srcTexture->asRenderTarget()));
|
| +
|
| + } else {
|
| + scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
|
| + srcRect.roundOut(&srcRect);
|
| + const SkIRect srcIRect = srcRect.roundOut();
|
| + if (sigmaX > 0.0f) {
|
| + if (scaleFactorX > 1) {
|
| + // TODO: if we pass in the source draw context we don't need this here
|
| if (!srcDrawContext) {
|
| - return nullptr;
|
| + srcDrawContext = context->drawContext(sk_ref_sp(srcTexture->asRenderTarget()));
|
| + if (!srcDrawContext) {
|
| + return nullptr;
|
| + }
|
| }
|
| +
|
| + // Clear out a radius to the right of the srcRect to prevent the
|
| + // X convolution from reading garbage.
|
| + clearRect = SkIRect::MakeXYWH(srcIRect.fRight, srcIRect.fTop,
|
| + radiusX, srcIRect.height());
|
| + srcDrawContext->clear(&clearRect, 0x0, false);
|
| }
|
|
|
| - // Clear out a radius below the srcRect to prevent the Y
|
| - // convolution from reading garbage.
|
| - clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
|
| - srcIRect.width(), radiusY);
|
| - srcDrawContext->clear(&clearRect, 0x0, false);
|
| - }
|
| -
|
| - sk_sp<GrDrawContext> dstDrawContext(
|
| - context->drawContext(sk_ref_sp(dstTexture->asRenderTarget()), &props));
|
| - if (!dstDrawContext) {
|
| - return nullptr;
|
| - }
|
| - convolve_gaussian(dstDrawContext.get(), clip, srcRect,
|
| - srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, sigmaY,
|
| - srcBounds, srcOffset);
|
| -
|
| - srcDrawContext.swap(dstDrawContext);
|
| - srcTexture = dstTexture;
|
| - srcRect.offsetTo(0, 0);
|
| - SkTSwap(dstTexture, tempTexture);
|
| - }
|
| -
|
| - srcIRect = srcRect.roundOut();
|
| + sk_sp<GrDrawContext> dstDrawContext(
|
| + context->drawContext(sk_ref_sp(dstTexture->asRenderTarget()), &props));
|
| + if (!dstDrawContext) {
|
| + return nullptr;
|
| + }
|
| + convolve_gaussian(dstDrawContext.get(), clip, srcRect,
|
| + srcTexture, Gr1DKernelEffect::kX_Direction, radiusX, sigmaX,
|
| + srcBounds, srcOffset);
|
| + srcDrawContext.swap(dstDrawContext);
|
| + srcTexture = dstTexture;
|
| + srcRect.offsetTo(0, 0);
|
| + SkTSwap(dstTexture, tempTexture);
|
| + localSrcBounds = srcRect;
|
| + srcOffset.set(0, 0);
|
| + }
|
| +
|
| + if (sigmaY > 0.0f) {
|
| + if (scaleFactorY > 1 || sigmaX > 0.0f) {
|
| + // TODO: if we pass in the source draw context we don't need this here
|
| + if (!srcDrawContext) {
|
| + srcDrawContext = context->drawContext(sk_ref_sp(srcTexture->asRenderTarget()));
|
| + if (!srcDrawContext) {
|
| + return nullptr;
|
| + }
|
| + }
|
| +
|
| + // Clear out a radius below the srcRect to prevent the Y
|
| + // convolution from reading garbage.
|
| + clearRect = SkIRect::MakeXYWH(srcIRect.fLeft, srcIRect.fBottom,
|
| + srcIRect.width(), radiusY);
|
| + srcDrawContext->clear(&clearRect, 0x0, false);
|
| + }
|
| +
|
| + sk_sp<GrDrawContext> dstDrawContext(
|
| + context->drawContext(sk_ref_sp(dstTexture->asRenderTarget()), &props));
|
| + if (!dstDrawContext) {
|
| + return nullptr;
|
| + }
|
| + convolve_gaussian(dstDrawContext.get(), clip, srcRect,
|
| + srcTexture, Gr1DKernelEffect::kY_Direction, radiusY, sigmaY,
|
| + srcBounds, srcOffset);
|
| +
|
| + srcDrawContext.swap(dstDrawContext);
|
| + srcTexture = dstTexture;
|
| + srcRect.offsetTo(0, 0);
|
| + SkTSwap(dstTexture, tempTexture);
|
| + }
|
| + }
|
| + const SkIRect srcIRect = srcRect.roundOut();
|
|
|
| if (scaleFactorX > 1 || scaleFactorY > 1) {
|
| SkASSERT(srcDrawContext);
|
|
|