Fix gaussian blur for small sigma.
authorsenorblanco <senorblanco@chromium.org>
Thu, 17 Dec 2015 16:10:17 +0000 (08:10 -0800)
committerCommit bot <commit-bot@chromium.org>
Thu, 17 Dec 2015 16:10:17 +0000 (08:10 -0800)
I broke this in https://skia.googlesource.com/skia/+/c57e0ded7d535523cfc6bf07c78e5f3479bb8c42.
That change added support for cropping during blur, but
did not do the correct thing for the small-sigma 2D matrix convolution
optimization when blurring from small-to-large textures.

The fix is pass the correct dstRect and srcOffset to convolve_gaussian_2d.
I also changed convolve_gaussian_1d() and convolve_gaussian_2d() to take
the original (non-negated) srcOffset, and to negate them when constructing
the local matrix.

Test: added a new (blur 0.3 0.3) column to imagefilterscropexpand, so that
GM will have to be rebaselined.

BUG=skia:4719,569883
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1529313003

Review URL: https://codereview.chromium.org/1529313003

gm/imagefilterscropexpand.cpp
src/effects/SkGpuBlurUtils.cpp

index b173648..4fa9b00 100644 (file)
@@ -35,7 +35,7 @@ protected:
         return SkString("imagefilterscropexpand");
     }
 
-    SkISize onISize() override { return SkISize::Make(570, 650); }
+    SkISize onISize() override { return SkISize::Make(650, 650); }
 
     void onDraw(SkCanvas* canvas) override {
         SkAutoTUnref<SkColorFilter> cf(
@@ -78,6 +78,9 @@ protected:
                 cfAlphaTrans, noopCropped.get(), &big_rect));
 
             Draw(canvas, checkerboard, rect, SkBlurImageFilter::Create(
+                0.3f, 0.3f, noopCropped.get(), &big_rect));
+
+            Draw(canvas, checkerboard, rect, SkBlurImageFilter::Create(
                 8.0f, 8.0f, noopCropped.get(), &big_rect));
 
             Draw(canvas, checkerboard, rect, SkDilateImageFilter::Create(
index 8ab05dd..13b6b0a 100644 (file)
@@ -60,21 +60,21 @@ static void convolve_gaussian_1d(GrDrawContext* drawContext,
         texture, direction, radius, sigma, useBounds, bounds));
     paint.addColorFragmentProcessor(conv);
     paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
-    SkMatrix localMatrix = SkMatrix::MakeTrans(srcOffset.x(), srcOffset.y());
+    SkMatrix localMatrix = SkMatrix::MakeTrans(-srcOffset.x(), -srcOffset.y());
     drawContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(), dstRect, localMatrix);
 }
 
 static void convolve_gaussian_2d(GrDrawContext* drawContext,
                                  const GrClip& clip,
-                                 const SkRect& srcRect,
+                                 const SkRect& dstRect,
+                                 const SkPoint& srcOffset,
                                  GrTexture* texture,
                                  int radiusX,
                                  int radiusY,
                                  SkScalar sigmaX,
                                  SkScalar sigmaY,
                                  const SkRect* srcBounds) {
-    SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
-    SkMatrix localMatrix = SkMatrix::MakeTrans(srcRect.x(), srcRect.y());
+    SkMatrix localMatrix = SkMatrix::MakeTrans(-srcOffset.x(), -srcOffset.y());
     SkISize size = SkISize::Make(2 * radiusX + 1,  2 * radiusY + 1);
     SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY);
     GrPaint paint;
@@ -148,15 +148,15 @@ static void convolve_gaussian(GrDrawContext* drawContext,
     }
     if (midRect.isEmpty()) {
         // Blur radius covers srcBounds; use bounds over entire draw
-        convolve_gaussian_1d(drawContext, clip, dstRect, -srcOffset, texture,
+        convolve_gaussian_1d(drawContext, clip, dstRect, srcOffset, texture,
                             direction, radius, sigma, true, bounds);
     } else {
         // Draw right and left margins with bounds; middle without.
-        convolve_gaussian_1d(drawContext, clip, leftRect, -srcOffset, texture,
+        convolve_gaussian_1d(drawContext, clip, leftRect, srcOffset, texture,
                              direction, radius, sigma, true, bounds);
-        convolve_gaussian_1d(drawContext, clip, rightRect, -srcOffset, texture,
+        convolve_gaussian_1d(drawContext, clip, rightRect, srcOffset, texture,
                              direction, radius, sigma, true, bounds);
-        convolve_gaussian_1d(drawContext, clip, midRect, -srcOffset, texture,
+        convolve_gaussian_1d(drawContext, clip, midRect, srcOffset, texture,
                              direction, radius, sigma, false, bounds);
     }
 }
@@ -269,6 +269,7 @@ GrTexture* GaussianBlur(GrContext* context,
 
     // 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;
     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
@@ -279,7 +280,7 @@ GrTexture* GaussianBlur(GrContext* context,
         if (!dstDrawContext) {
             return nullptr;
         }
-        convolve_gaussian_2d(dstDrawContext, clip, srcRect,
+        convolve_gaussian_2d(dstDrawContext, clip, srcRect, srcOffset,
                              srcTexture, radiusX, radiusY, sigmaX, sigmaY, srcBounds);
 
         srcDrawContext.swap(dstDrawContext);
@@ -288,7 +289,6 @@ GrTexture* GaussianBlur(GrContext* context,
         SkTSwap(dstTexture, tempTexture);
 
     } else {
-        srcRect = localDstBounds;
         scale_rect(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
         srcRect.roundOut(&srcRect);
         const SkIRect srcIRect = srcRect.roundOut();