Chromium Code Reviews| Index: src/effects/SkGpuBlurUtils.cpp |
| diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp |
| index 58881087553cb8a7e20f2bd15ef5b99b0cb0819d..b54c2d5d341fc871181773dc3830504da36527d8 100644 |
| --- a/src/effects/SkGpuBlurUtils.cpp |
| +++ b/src/effects/SkGpuBlurUtils.cpp |
| @@ -11,6 +11,7 @@ |
| #if SK_SUPPORT_GPU |
| #include "effects/GrConvolutionEffect.h" |
| +#include "effects/GrMatrixConvolutionEffect.h" |
| #include "effects/GrTextureDomain.h" |
| #include "GrContext.h" |
| #endif |
| @@ -61,6 +62,29 @@ static void convolve_gaussian_pass(GrContext* context, |
| context->drawRectToRect(paint, dstRect, srcRect); |
| } |
| +// a 2d gaussian convolution pass |
|
bsalomon
2014/07/28 15:20:41
Maybe we should give both these functions symmetri
|
| +static void convolve_gaussian_pass(GrContext* context, |
| + const SkRect& srcRect, |
| + const SkRect& dstRect, |
| + GrTexture* texture, |
| + int radiusX, |
| + int radiusY, |
| + SkScalar sigmaX, |
| + SkScalar sigmaY, |
| + bool useBounds, |
| + SkIRect bounds) { |
| + SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); |
| + SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); |
| + GrPaint paint; |
| + paint.reset(); |
| + SkAutoTUnref<GrEffect> conv(GrMatrixConvolutionEffect::CreateGaussian( |
| + texture, bounds, size, 1.0, 0.0, kernelOffset, GrMatrixConvolutionEffect::kClamp_TileMode, |
| + true, useBounds, sigmaX, sigmaY)); |
| + paint.reset(); |
| + paint.addColorEffect(conv); |
| + context->drawRectToRect(paint, dstRect, srcRect); |
| +} |
| + |
| static void convolve_gaussian(GrContext* context, |
| const SkRect& srcRect, |
| const SkRect& dstRect, |
| @@ -196,7 +220,10 @@ GrTexture* GaussianBlur(GrContext* context, |
| SkIRect srcIRect; |
| srcRect.roundOut(&srcIRect); |
| - if (sigmaX > 0.0f) { |
| + // if square, and small than do one pass instead of 2, actually small rectangular blocks |
| + // are okay too but for simplicity only handle the square case for now |
|
bsalomon
2014/07/28 15:20:41
is the squareness enforced here?
|
| + if (sigmaX > 0.0f && sigmaY > 0 && |
| + (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) { |
| if (scaleFactorX > 1) { |
| // Clear out a radius to the right of the srcRect to prevent the |
| // X convolution from reading garbage. |
| @@ -204,32 +231,60 @@ GrTexture* GaussianBlur(GrContext* context, |
| radiusX, srcIRect.height()); |
| context->clear(&clearRect, 0x0, false); |
| } |
| - context->setRenderTarget(dstTexture->asRenderTarget()); |
| - SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
| - convolve_gaussian(context, srcRect, dstRect, srcTexture, |
| - Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, cropToRect); |
| - srcTexture = dstTexture; |
| - srcRect = dstRect; |
| - SkTSwap(dstTexture, tempTexture); |
| - } |
| - |
| - if (sigmaY > 0.0f) { |
| - if (scaleFactorY > 1 || sigmaX > 0.0f) { |
| + if (scaleFactorY > 1) { |
|
bsalomon
2014/07/28 15:20:41
Can we get here with scaleFactorY > 1? I thought t
|
| // 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); |
| context->clear(&clearRect, 0x0, false); |
| } |
| - |
| context->setRenderTarget(dstTexture->asRenderTarget()); |
| SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
| - convolve_gaussian(context, srcRect, dstRect, srcTexture, |
| - Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, cropToRect); |
| + // TODO we have a ton of perf verification to do here, but its an open question if we should |
| + // do 4 draw calls with bounds then 1 without, or 1 with bounds, or just fall back to |
| + // separable when we have to crop to src rect |
| + convolve_gaussian_pass(context, srcRect, dstRect, srcTexture, |
| + radiusX, radiusY, sigmaX, sigmaY, cropToRect, srcIRect); |
| srcTexture = dstTexture; |
| srcRect = dstRect; |
| SkTSwap(dstTexture, tempTexture); |
| } |
| + else { |
|
bsalomon
2014/07/28 15:20:41
style nit, else goes with }
|
| + if (sigmaX > 0.0f) { |
| + if (scaleFactorX > 1) { |
| + // 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()); |
| + context->clear(&clearRect, 0x0, false); |
| + } |
| + context->setRenderTarget(dstTexture->asRenderTarget()); |
| + SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
| + convolve_gaussian(context, srcRect, dstRect, srcTexture, |
| + Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, cropToRect); |
| + srcTexture = dstTexture; |
| + srcRect = dstRect; |
| + SkTSwap(dstTexture, tempTexture); |
| + } |
| + |
| + if (sigmaY > 0.0f) { |
| + if (scaleFactorY > 1 || sigmaX > 0.0f) { |
| + // 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); |
| + context->clear(&clearRect, 0x0, false); |
| + } |
| + |
| + context->setRenderTarget(dstTexture->asRenderTarget()); |
| + SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); |
| + convolve_gaussian(context, srcRect, dstRect, srcTexture, |
| + Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, cropToRect); |
| + srcTexture = dstTexture; |
| + srcRect = dstRect; |
| + SkTSwap(dstTexture, tempTexture); |
| + } |
| + } |
| if (scaleFactorX > 1 || scaleFactorY > 1) { |
| // Clear one pixel to the right and below, to accommodate bilinear |