aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-30 21:11:05 +0000
committerGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-30 21:11:05 +0000
commitd71732a5baf4a0a1d912b27ded5360c7e82656c3 (patch)
tree7d47107b9db8e4f2c8e8cfa09383c35f96283994
parent2faef552ffe93a0b3f3c1df3ce4583fde602b651 (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.cpp96
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);