| Index: src/effects/SkGpuBlurUtils.cpp
|
| diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp
|
| index 58881087553cb8a7e20f2bd15ef5b99b0cb0819d..aa7f9952f92436137c19853bfb3f96ade4a939e9 100644
|
| --- a/src/effects/SkGpuBlurUtils.cpp
|
| +++ b/src/effects/SkGpuBlurUtils.cpp
|
| @@ -11,7 +11,7 @@
|
|
|
| #if SK_SUPPORT_GPU
|
| #include "effects/GrConvolutionEffect.h"
|
| -#include "effects/GrTextureDomain.h"
|
| +#include "effects/GrMatrixConvolutionEffect.h"
|
| #include "GrContext.h"
|
| #endif
|
|
|
| @@ -43,15 +43,15 @@ static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int
|
| 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]) {
|
| +static void convolve_gaussian_1d(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<GrEffect> conv(GrConvolutionEffect::CreateGaussian(
|
| @@ -61,6 +61,29 @@ static void convolve_gaussian_pass(GrContext* context,
|
| context->drawRectToRect(paint, dstRect, srcRect);
|
| }
|
|
|
| +static void convolve_gaussian_2d(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,
|
| + useBounds ? GrTextureDomain::kClamp_Mode : GrTextureDomain::kIgnore_Mode,
|
| + true, sigmaX, sigmaY));
|
| + paint.reset();
|
| + paint.addColorEffect(conv);
|
| + context->drawRectToRect(paint, dstRect, srcRect);
|
| +}
|
| +
|
| static void convolve_gaussian(GrContext* context,
|
| const SkRect& srcRect,
|
| const SkRect& dstRect,
|
| @@ -71,8 +94,8 @@ static void convolve_gaussian(GrContext* context,
|
| bool cropToSrcRect) {
|
| float bounds[2] = { 0.0f, 1.0f };
|
| if (!cropToSrcRect) {
|
| - convolve_gaussian_pass(context, srcRect, dstRect, texture,
|
| - direction, radius, sigma, false, bounds);
|
| + convolve_gaussian_1d(context, srcRect, dstRect, texture,
|
| + direction, radius, sigma, false, bounds);
|
| return;
|
| }
|
| SkRect lowerSrcRect = srcRect, lowerDstRect = dstRect;
|
| @@ -103,16 +126,16 @@ static void convolve_gaussian(GrContext* context,
|
| }
|
| 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);
|
| + convolve_gaussian_1d(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);
|
| + convolve_gaussian_1d(context, lowerSrcRect, lowerDstRect, texture,
|
| + direction, radius, sigma, true, bounds);
|
| + convolve_gaussian_1d(context, upperSrcRect, upperDstRect, texture,
|
| + direction, radius, sigma, true, bounds);
|
| + convolve_gaussian_1d(context, middleSrcRect, middleDstRect, texture,
|
| + direction, radius, sigma, false, bounds);
|
| }
|
| }
|
|
|
| @@ -196,39 +219,55 @@ GrTexture* GaussianBlur(GrContext* context,
|
| SkIRect srcIRect;
|
| srcRect.roundOut(&srcIRect);
|
|
|
| - 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);
|
| - }
|
| + // 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 &&
|
| + (2 * radiusX + 1) * (2 * radiusY + 1) <= MAX_KERNEL_SIZE) {
|
| + // We shouldn't be scaling because this is a small size blur
|
| + SkASSERT((scaleFactorX == scaleFactorY) == 1);
|
| context->setRenderTarget(dstTexture->asRenderTarget());
|
| SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
|
| - convolve_gaussian(context, srcRect, dstRect, srcTexture,
|
| - Gr1DKernelEffect::kX_Direction, radiusX, sigmaX, cropToRect);
|
| + convolve_gaussian_2d(context, srcRect, dstRect, srcTexture,
|
| + radiusX, radiusY, sigmaX, sigmaY, cropToRect, srcIRect);
|
| 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);
|
| + } else {
|
| + 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);
|
| }
|
|
|
| - 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 (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) {
|
|
|