diff options
author | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-07-30 21:11:05 +0000 |
---|---|---|
committer | senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-07-30 21:11:05 +0000 |
commit | d71732a5baf4a0a1d912b27ded5360c7e82656c3 (patch) | |
tree | 7d47107b9db8e4f2c8e8cfa09383c35f96283994 | |
parent | 2faef552ffe93a0b3f3c1df3ce4583fde602b651 (diff) |
Optimize the blur convolution by only applying domain clamping where necessary. Split the blur convolution into left and right margins which have clamping applied and a center portion which doesn't. Also reorder the convolve_gaussian() parameters to match GrConvolutionEffect params. Correctness is covered by existing tests; performance is covered by BlurImageFilter bench.
R=bsalomon@google.com
Review URL: https://codereview.chromium.org/21224003
git-svn-id: http://skia.googlecode.com/svn/trunk@10444 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | src/effects/SkGpuBlurUtils.cpp | 96 |
1 files changed, 69 insertions, 27 deletions
diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp index 28ccd4589b..5fc51811aa 100644 --- a/src/effects/SkGpuBlurUtils.cpp +++ b/src/effects/SkGpuBlurUtils.cpp @@ -39,35 +39,77 @@ static float adjust_sigma(float sigma, int *scaleFactor, int *radius) { return sigma; } +static void convolve_gaussian_pass(GrContext* context, + const SkRect& srcRect, + const SkRect& dstRect, + GrTexture* texture, + Gr1DKernelEffect::Direction direction, + int radius, + float sigma, + bool useBounds, + float bounds[2]) { + GrPaint paint; + paint.reset(); + SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian( + texture, direction, radius, sigma, useBounds, bounds)); + paint.reset(); + paint.addColorEffect(conv); + context->drawRectToRect(paint, dstRect, srcRect); +} + static void convolve_gaussian(GrContext* context, - GrTexture* texture, const SkRect& srcRect, const SkRect& dstRect, - bool cropToSrcRect, - float sigma, + GrTexture* texture, + Gr1DKernelEffect::Direction direction, int radius, - Gr1DKernelEffect::Direction direction) { - GrPaint paint; - paint.reset(); + float sigma, + bool cropToSrcRect) { float bounds[2] = { 0.0f, 1.0f }; - if (cropToSrcRect) { - if (direction == Gr1DKernelEffect::kX_Direction) { - bounds[0] = SkScalarToFloat(srcRect.left()) / texture->width(); - bounds[1] = SkScalarToFloat(srcRect.right()) / texture->width(); - } else { - bounds[0] = SkScalarToFloat(srcRect.top()) / texture->height(); - bounds[1] = SkScalarToFloat(srcRect.bottom()) / texture->height(); - } + if (!cropToSrcRect) { + convolve_gaussian_pass(context, srcRect, dstRect, texture, + direction, radius, sigma, false, bounds); + return; + } + SkRect lowerSrcRect = srcRect, lowerDstRect = dstRect; + SkRect middleSrcRect = srcRect, middleDstRect = dstRect; + SkRect upperSrcRect = srcRect, upperDstRect = dstRect; + SkScalar size; + SkScalar rad = SkIntToScalar(radius); + if (direction == Gr1DKernelEffect::kX_Direction) { + bounds[0] = SkScalarToFloat(srcRect.left()) / texture->width(); + bounds[1] = SkScalarToFloat(srcRect.right()) / texture->width(); + size = srcRect.width(); + lowerSrcRect.fRight = srcRect.left() + rad; + lowerDstRect.fRight = dstRect.left() + rad; + upperSrcRect.fLeft = srcRect.right() - rad; + upperDstRect.fLeft = dstRect.right() - rad; + middleSrcRect.inset(rad, 0); + middleDstRect.inset(rad, 0); + } else { + bounds[0] = SkScalarToFloat(srcRect.top()) / texture->height(); + bounds[1] = SkScalarToFloat(srcRect.bottom()) / texture->height(); + size = srcRect.height(); + lowerSrcRect.fBottom = srcRect.top() + rad; + lowerDstRect.fBottom = dstRect.top() + rad; + upperSrcRect.fTop = srcRect.bottom() - rad; + upperDstRect.fTop = dstRect.bottom() - rad; + middleSrcRect.inset(0, rad); + middleDstRect.inset(0, rad); + } + if (radius >= size * SK_ScalarHalf) { + // Blur radius covers srcRect; use bounds over entire draw + convolve_gaussian_pass(context, srcRect, dstRect, texture, + direction, radius, sigma, true, bounds); + } else { + // Draw upper and lower margins with bounds; middle without. + convolve_gaussian_pass(context, lowerSrcRect, lowerDstRect, texture, + direction, radius, sigma, true, bounds); + convolve_gaussian_pass(context, upperSrcRect, upperDstRect, texture, + direction, radius, sigma, true, bounds); + convolve_gaussian_pass(context, middleSrcRect, middleDstRect, texture, + direction, radius, sigma, false, bounds); } - - SkAutoTUnref<GrEffectRef> conv(GrConvolutionEffect::CreateGaussian(texture, - direction, - radius, - sigma, - cropToSrcRect, - bounds)); - paint.addColorEffect(conv); - context->drawRectToRect(paint, dstRect, srcRect); } GrTexture* GaussianBlur(GrContext* context, @@ -159,8 +201,8 @@ GrTexture* GaussianBlur(GrContext* context, } context->setRenderTarget(dstTexture->asRenderTarget()); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); - convolve_gaussian(context, srcTexture, srcRect, dstRect, cropToRect, - sigmaX, radiusX, Gr1DKernelEffect::kX_Direction); + convolve_gaussian(context, srcRect, dstRect, srcTexture, + Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, cropToRect); srcTexture = dstTexture; srcRect = dstRect; SkTSwap(dstTexture, tempTexture); @@ -177,8 +219,8 @@ GrTexture* GaussianBlur(GrContext* context, context->setRenderTarget(dstTexture->asRenderTarget()); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); - convolve_gaussian(context, srcTexture, srcRect, dstRect, cropToRect, - sigmaY, radiusY, Gr1DKernelEffect::kY_Direction); + convolve_gaussian(context, srcRect, dstRect, srcTexture, + Gr1DKernelEffect::kY_Direction, radiusY, sigmaY, cropToRect); srcTexture = dstTexture; srcRect = dstRect; SkTSwap(dstTexture, tempTexture); |