Make SkGpuBlurUtils take SkTileMode

This is to get ready for moving all of our texture domain
implementation into GrTextureEffect.

This may cause a short term perf regression we might make GrDomainEffect
with unnecessary shader clamping.

Change-Id: I04d9c4c6999539cfd35bda07b943c3b7eb224df8
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/264397
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
diff --git a/src/core/SkBlurMF.cpp b/src/core/SkBlurMF.cpp
index aa00e50..30be330 100644
--- a/src/core/SkBlurMF.cpp
+++ b/src/core/SkBlurMF.cpp
@@ -883,17 +883,18 @@
     // If we're doing a normal blur, we can clobber the pathTexture in the
     // gaussianBlur.  Otherwise, we need to save it for later compositing.
     bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle);
-    auto renderTargetContext = SkGpuBlurUtils::GaussianBlur(context,
-                                                            srcProxy,
-                                                            srcColorType,
-                                                            srcAlphaType,
-                                                            SkIPoint::Make(0, 0),
-                                                            nullptr,
-                                                            clipRect,
-                                                            SkIRect::MakeEmpty(),
-                                                            xformedSigma,
-                                                            xformedSigma,
-                                                            GrTextureDomain::kIgnore_Mode);
+    auto renderTargetContext =
+            SkGpuBlurUtils::GaussianBlur(context,
+                                         srcProxy,
+                                         srcColorType,
+                                         srcAlphaType,
+                                         SkIPoint::Make(0, 0),
+                                         nullptr,
+                                         clipRect,
+                                         SkIRect::MakeSize(srcProxy->dimensions()),
+                                         xformedSigma,
+                                         xformedSigma,
+                                         SkTileMode::kClamp);
     if (!renderTargetContext) {
         return nullptr;
     }
diff --git a/src/core/SkGpuBlurUtils.cpp b/src/core/SkGpuBlurUtils.cpp
index b4d265b..28105c8 100644
--- a/src/core/SkGpuBlurUtils.cpp
+++ b/src/core/SkGpuBlurUtils.cpp
@@ -71,6 +71,21 @@
     return sigma;
 }
 
+static GrTextureDomain::Mode to_texture_domain_mode(SkTileMode tileMode) {
+    switch (tileMode) {
+        case SkTileMode::kClamp:
+            return GrTextureDomain::kClamp_Mode;
+        case SkTileMode::kDecal:
+            return GrTextureDomain::kDecal_Mode;
+        case SkTileMode::kMirror:
+            // TODO (michaelludwig) - Support mirror mode, treat as repeat for now
+        case SkTileMode::kRepeat:
+            return GrTextureDomain::kRepeat_Mode;
+        default:
+            SK_ABORT("Unsupported tile mode.");
+    }
+}
+
 static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext,
                                  const GrClip& clip,
                                  const SkIRect& dstRect,
@@ -80,11 +95,12 @@
                                  Direction direction,
                                  int radius,
                                  float sigma,
-                                 GrTextureDomain::Mode mode,
+                                 SkTileMode mode,
                                  int bounds[2]) {
     GrPaint paint;
+    auto domainMode = to_texture_domain_mode(mode);
     std::unique_ptr<GrFragmentProcessor> conv(GrGaussianConvolutionFragmentProcessor::Make(
-            std::move(proxy), srcAlphaType, direction, radius, sigma, mode, bounds));
+            std::move(proxy), srcAlphaType, direction, radius, sigma, domainMode, bounds));
     paint.addColorFragmentProcessor(std::move(conv));
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()),
@@ -102,7 +118,7 @@
                                                                    int radiusY,
                                                                    SkScalar sigmaX,
                                                                    SkScalar sigmaY,
-                                                                   GrTextureDomain::Mode mode,
+                                                                   SkTileMode mode,
                                                                    int finalW,
                                                                    int finalH,
                                                                    sk_sp<SkColorSpace> finalCS,
@@ -119,8 +135,9 @@
     SkISize size = SkISize::Make(2 * radiusX + 1,  2 * radiusY + 1);
     SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY);
     GrPaint paint;
+    auto domainMode = to_texture_domain_mode(mode);
     auto conv = GrMatrixConvolutionEffect::MakeGaussian(std::move(srcProxy), srcBounds, size,
-                                                        1.0, 0.0, kernelOffset, mode, true,
+                                                        1.0, 0.0, kernelOffset, domainMode, true,
                                                         sigmaX, sigmaY);
     paint.addColorFragmentProcessor(std::move(conv));
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
@@ -150,7 +167,7 @@
                                                                 int radius,
                                                                 float sigma,
                                                                 SkIRect* contentRect,
-                                                                GrTextureDomain::Mode mode,
+                                                                SkTileMode mode,
                                                                 int finalW,
                                                                 int finalH,
                                                                 sk_sp<SkColorSpace> finalCS,
@@ -169,11 +186,14 @@
     int bounds[2] = { 0, 0 };
     SkIRect dstRect = SkIRect::MakeWH(srcRect.width(), srcRect.height());
     SkIPoint netOffset = srcOffset - proxyOffset;
-    if (GrTextureDomain::kIgnore_Mode == mode) {
+    if (SkTileMode::kClamp == mode && proxyOffset.isZero() &&
+        contentRect->contains(SkIRect::MakeSize(srcProxy->backingStoreDimensions()))) {
+        bounds[0] = direction == Direction::kX ? contentRect->left() : contentRect->top();
+        bounds[1] = direction == Direction::kX ? contentRect->right() : contentRect->bottom();
         *contentRect = dstRect;
         convolve_gaussian_1d(dstRenderTargetContext.get(), clip, dstRect, netOffset,
                              std::move(srcProxy), srcAlphaType, direction, radius, sigma,
-                             GrTextureDomain::kIgnore_Mode, bounds);
+                             SkTileMode::kClamp, bounds);
         return dstRenderTargetContext;
     }
     // These destination rects need to be adjusted by srcOffset, but should *not* be adjusted by
@@ -235,9 +255,11 @@
                              srcAlphaType, direction, radius, sigma, mode, bounds);
         convolve_gaussian_1d(dstRenderTargetContext.get(), clip, rightRect, netOffset, srcProxy,
                              srcAlphaType, direction, radius, sigma, mode, bounds);
+        bounds[0] = 0;
+        bounds[1] = direction == Direction::kX ? srcProxy->width() : srcProxy->height();
         convolve_gaussian_1d(dstRenderTargetContext.get(), clip, midRect, netOffset,
                              std::move(srcProxy), srcAlphaType, direction, radius, sigma,
-                             GrTextureDomain::kIgnore_Mode, bounds);
+                             SkTileMode::kClamp, bounds);
     }
 
     return dstRenderTargetContext;
@@ -253,22 +275,15 @@
                                       const SkIPoint& proxyOffset,
                                       SkIPoint* srcOffset,
                                       SkIRect* contentRect,
-                                      int scaleFactorX, int scaleFactorY,
-                                      int radiusX, int radiusY,
-                                      GrTextureDomain::Mode mode,
-                                      int finalW,
-                                      int finalH,
+                                      int scaleFactorX,
+                                      int scaleFactorY,
+                                      SkTileMode mode,
                                       sk_sp<SkColorSpace> finalCS) {
     SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY));
     SkASSERT(scaleFactorX > 1 || scaleFactorY > 1);
 
-    SkIRect srcRect;
-    if (GrTextureDomain::kIgnore_Mode == mode) {
-        srcRect = SkIRect::MakeWH(finalW, finalH);
-    } else {
-        srcRect = *contentRect;
-        srcRect.offset(*srcOffset);
-    }
+    SkIRect srcRect = *contentRect;
+    srcRect.offset(*srcOffset);
 
     scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
     scale_irect(&srcRect, scaleFactorX, scaleFactorY);
@@ -294,13 +309,16 @@
         GrPaint paint;
         auto fp = GrTextureEffect::Make(std::move(srcProxy), srcAlphaType, SkMatrix::I(),
                                         GrSamplerState::Filter::kBilerp);
-        if (GrTextureDomain::kIgnore_Mode != mode && i == 1) {
+        if (i == 1) {
             // GrDomainEffect does not support kRepeat_Mode with GrSamplerState::Filter.
-            GrTextureDomain::Mode modeForScaling = (GrTextureDomain::kRepeat_Mode == mode ||
-                                                    GrTextureDomain::kMirrorRepeat_Mode == mode)
-                                                           ? GrTextureDomain::kDecal_Mode
-                                                           : mode;
-
+            GrTextureDomain::Mode domainMode;
+            if (mode == SkTileMode::kClamp) {
+                domainMode = GrTextureDomain::kClamp_Mode;
+            } else {
+                // GrDomainEffect does not support k[Mirror]Repeat with GrSamplerState::Filter.
+                // So we use decal.
+                domainMode = GrTextureDomain::kDecal_Mode;
+            }
             SkRect domain = SkRect::Make(*contentRect);
             domain.inset((i < scaleFactorX) ? SK_ScalarHalf + SK_ScalarNearlyZero : 0.0f,
                          (i < scaleFactorY) ? SK_ScalarHalf + SK_ScalarNearlyZero : 0.0f);
@@ -312,7 +330,7 @@
                 domain.fTop = domain.fBottom = SkScalarAve(domain.fTop, domain.fBottom);
             }
             domain.offset(proxyOffset.x(), proxyOffset.y());
-            fp = GrDomainEffect::Make(std::move(fp), domain, modeForScaling, true);
+            fp = GrDomainEffect::Make(std::move(fp), domain, domainMode, true);
             srcRect.offset(-(*srcOffset));
             // TODO: consume the srcOffset in both first draws and always set it to zero
             // back in GaussianBlur
@@ -403,7 +421,7 @@
                                                     const SkIRect& srcBounds,
                                                     float sigmaX,
                                                     float sigmaY,
-                                                    GrTextureDomain::Mode mode,
+                                                    SkTileMode mode,
                                                     SkBackingFit fit) {
     SkASSERT(context);
 
@@ -445,21 +463,14 @@
         xFit = SkBackingFit::kApprox;         // the y-pass will be last
     }
 
-    GrTextureDomain::Mode currDomainMode = mode;
     if (scaleFactorX > 1 || scaleFactorY > 1) {
-        srcProxy =
-                decimate(context, std::move(srcProxy), srcColorType, srcAlphaType, localProxyOffset,
-                         &srcOffset, &localSrcBounds, scaleFactorX, scaleFactorY, radiusX, radiusY,
-                         currDomainMode, finalW, finalH, colorSpace);
+        srcProxy = decimate(context, std::move(srcProxy), srcColorType, srcAlphaType,
+                            localProxyOffset, &srcOffset, &localSrcBounds, scaleFactorX,
+                            scaleFactorY, mode, colorSpace);
         if (!srcProxy) {
             return nullptr;
         }
         localProxyOffset.set(0, 0);
-        if (GrTextureDomain::kIgnore_Mode == currDomainMode) {
-            // decimate() always returns an approx texture, possibly with garbage after the image.
-            // We can't ignore the domain anymore.
-            currDomainMode = GrTextureDomain::kClamp_Mode;
-        }
     }
 
     std::unique_ptr<GrRenderTargetContext> dstRenderTargetContext;
@@ -467,10 +478,10 @@
     auto srcRect = SkIRect::MakeWH(finalW, finalH);
     scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY);
     if (sigmaX > 0.0f) {
-        dstRenderTargetContext = convolve_gaussian(
-                context, std::move(srcProxy), srcColorType, srcAlphaType, localProxyOffset, srcRect,
-                srcOffset, Direction::kX, radiusX, sigmaX, &localSrcBounds, currDomainMode, finalW,
-                finalH, colorSpace, xFit);
+        dstRenderTargetContext =
+                convolve_gaussian(context, std::move(srcProxy), srcColorType, srcAlphaType,
+                                  localProxyOffset, srcRect, srcOffset, Direction::kX, radiusX,
+                                  sigmaX, &localSrcBounds, mode, finalW, finalH, colorSpace, xFit);
         if (!dstRenderTargetContext) {
             return nullptr;
         }
@@ -483,18 +494,13 @@
         srcRect.offsetTo(0, 0);
         srcOffset.set(0, 0);
         localProxyOffset.set(0, 0);
-        if (SkBackingFit::kApprox == xFit && GrTextureDomain::kIgnore_Mode == currDomainMode) {
-            // srcProxy is now an approx texture, possibly with garbage after the image. We can't
-            // ignore the domain anymore.
-            currDomainMode = GrTextureDomain::kClamp_Mode;
-        }
     }
 
     if (sigmaY > 0.0f) {
-        dstRenderTargetContext = convolve_gaussian(
-                context, std::move(srcProxy), srcColorType, srcAlphaType, localProxyOffset, srcRect,
-                srcOffset, Direction::kY, radiusY, sigmaY, &localSrcBounds, currDomainMode, finalW,
-                finalH, colorSpace, yFit);
+        dstRenderTargetContext =
+                convolve_gaussian(context, std::move(srcProxy), srcColorType, srcAlphaType,
+                                  localProxyOffset, srcRect, srcOffset, Direction::kY, radiusY,
+                                  sigmaY, &localSrcBounds, mode, finalW, finalH, colorSpace, yFit);
         if (!dstRenderTargetContext) {
             return nullptr;
         }
diff --git a/src/core/SkGpuBlurUtils.h b/src/core/SkGpuBlurUtils.h
index 9143518..a1b3308 100644
--- a/src/core/SkGpuBlurUtils.h
+++ b/src/core/SkGpuBlurUtils.h
@@ -18,32 +18,32 @@
 struct SkRect;
 
 namespace SkGpuBlurUtils {
-  /**
-    * Applies a 2D Gaussian blur to a given texture. The blurred result is returned
-    * as a renderTargetContext in case the caller wishes to draw into the result.
-    *
-    * The 'proxyOffset' is kept separate form 'srcBounds' because they exist in different
-    * coordinate spaces. 'srcBounds' exists in the content space of the special image, and
-    * 'proxyOffset' maps from the content space to the proxy's space.
-    *
-    * Note: one of sigmaX and sigmaY should be non-zero!
-    * @param context         The GPU context
-    * @param srcProxy        The source to be blurred.
-    * @param srcColorType    The colorType of srcProxy
-    * @param srcAlphaType    The alphaType of srcProxy
-    * @param proxyOffset     The offset from the top-left corner to valid texels in 'srcProxy',
-                             which should come from the subset of the owning SkSpecialImage.
-    * @param colorSpace      Color space of the source (used for the renderTargetContext result,
-    *                        too).
-    * @param dstBounds       The destination bounds, relative to the source texture.
-    * @param srcBounds       The source bounds, relative to the source texture's offset. No pixels
-    *                        will be sampled outside of this rectangle.
-    * @param sigmaX          The blur's standard deviation in X.
-    * @param sigmaY          The blur's standard deviation in Y.
-    * @param mode            The mode to handle samples outside bounds.
-    * @param fit             backing fit for the returned render target context
-    * @return                The renderTargetContext containing the blurred result.
-    */
+/**
+  * Applies a 2D Gaussian blur to a given texture. The blurred result is returned
+  * as a renderTargetContext in case the caller wishes to draw into the result.
+  *
+  * The 'proxyOffset' is kept separate form 'srcBounds' because they exist in different
+  * coordinate spaces. 'srcBounds' exists in the content space of the special image, and
+  * 'proxyOffset' maps from the content space to the proxy's space.
+  *
+  * Note: one of sigmaX and sigmaY should be non-zero!
+  * @param context         The GPU context
+  * @param srcProxy        The source to be blurred.
+  * @param srcColorType    The colorType of srcProxy
+  * @param srcAlphaType    The alphaType of srcProxy
+  * @param proxyOffset     The offset from the top-left corner to valid texels in 'srcProxy',
+                           which should come from the subset of the owning SkSpecialImage.
+  * @param colorSpace      Color space of the source (used for the renderTargetContext result,
+  *                        too).
+  * @param dstBounds       The destination bounds, relative to the source texture.
+  * @param srcBounds       The source bounds, relative to the source texture's offset. No pixels
+  *                        will be sampled outside of this rectangle.
+  * @param sigmaX          The blur's standard deviation in X.
+  * @param sigmaY          The blur's standard deviation in Y.
+  * @param tileMode        The mode to handle samples outside bounds.
+  * @param fit             backing fit for the returned render target context
+  * @return                The renderTargetContext containing the blurred result.
+  */
 std::unique_ptr<GrRenderTargetContext> GaussianBlur(GrRecordingContext* context,
                                                     sk_sp<GrTextureProxy> srcProxy,
                                                     GrColorType srcColorType,
@@ -54,7 +54,7 @@
                                                     const SkIRect& srcBounds,
                                                     float sigmaX,
                                                     float sigmaY,
-                                                    GrTextureDomain::Mode mode,
+                                                    SkTileMode mode,
                                                     SkBackingFit fit = SkBackingFit::kApprox);
 };
 
diff --git a/src/effects/imagefilters/SkBlurImageFilter.cpp b/src/effects/imagefilters/SkBlurImageFilter.cpp
index 2dde5e2..2bfd8e8 100644
--- a/src/effects/imagefilters/SkBlurImageFilter.cpp
+++ b/src/effects/imagefilters/SkBlurImageFilter.cpp
@@ -131,23 +131,6 @@
     buffer.writeInt(static_cast<int>(fTileMode));
 }
 
-#if SK_SUPPORT_GPU
-static GrTextureDomain::Mode to_texture_domain_mode(SkTileMode tileMode) {
-    switch (tileMode) {
-        case SkTileMode::kClamp:
-            return GrTextureDomain::kClamp_Mode;
-        case SkTileMode::kDecal:
-            return GrTextureDomain::kDecal_Mode;
-        case SkTileMode::kMirror:
-            // TODO (michaelludwig) - Support mirror mode, treat as repeat for now
-        case SkTileMode::kRepeat:
-            return GrTextureDomain::kRepeat_Mode;
-        default:
-            SK_ABORT("Unsupported tile mode.");
-    }
-}
-#endif
-
 // This is defined by the SVG spec:
 // https://drafts.fxtf.org/filter-effects/#feGaussianBlurElement
 static int calculate_window(double sigma) {
@@ -677,7 +660,7 @@
             inputBounds,
             sigma.x(),
             sigma.y(),
-            to_texture_domain_mode(fTileMode));
+            fTileMode);
     if (!renderTargetContext) {
         return nullptr;
     }
diff --git a/src/gpu/GrFragmentProcessor.h b/src/gpu/GrFragmentProcessor.h
index 4150dca..b7206de 100644
--- a/src/gpu/GrFragmentProcessor.h
+++ b/src/gpu/GrFragmentProcessor.h
@@ -502,12 +502,13 @@
 
     bool isInitialized() const { return SkToBool(this->proxy()); }
 
+    GrSurfaceProxy* proxy() const { return fView.proxy(); }
+
 #if GR_TEST_UTILS
     void set(GrSurfaceProxyView, GrSamplerState);
 #endif
-private:
-    GrSurfaceProxy* proxy() const { return fView.proxy(); }
 
+private:
     GrSurfaceProxyView    fView;
     GrSamplerState        fSamplerState;
 };
diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
index 9a66a07..35dfcd0 100644
--- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
+++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
@@ -229,15 +229,49 @@
         , fRadius(radius)
         , fDirection(direction)
         , fMode(mode) {
-    // Make sure the sampler's ctor uses the clamp wrap mode
-    SkASSERT(fTextureSampler.samplerState().wrapModeX() == GrSamplerState::WrapMode::kClamp &&
-             fTextureSampler.samplerState().wrapModeY() == GrSamplerState::WrapMode::kClamp);
     this->addCoordTransform(&fCoordTransform);
     this->setTextureSamplerCnt(1);
     SkASSERT(radius <= kMaxKernelRadius);
 
     fill_in_1D_gaussian_kernel(fKernel, this->width(), gaussianSigma, this->radius());
-
+    // SkGpuBlurUtils is not as aggressive as it once was about avoiding domains. So we check
+    // here if we can omit the domain. TODO: remove this when this effect uses a child to
+    // sample the texture.
+    auto samplerProxy = fTextureSampler.proxy();
+    if (!samplerProxy->isFullyLazy()) {
+        int wh = (fDirection == Direction::kX) ? samplerProxy->backingStoreDimensions().width()
+                                               : samplerProxy->backingStoreDimensions().height();
+        if (bounds[0] == 0 && bounds[1] == wh) {
+            bool useSampler = false;
+            GrSamplerState::WrapMode samplerMode = GrSamplerState::WrapMode::kClamp;
+            switch (fMode) {
+                case GrTextureDomain::kClamp_Mode:
+                case GrTextureDomain::kIgnore_Mode:
+                    useSampler = true;
+                    break;
+                case GrTextureDomain::kRepeat_Mode:
+                    useSampler = true;
+                    samplerMode = GrSamplerState::WrapMode::kRepeat;
+                    break;
+                case GrTextureDomain::kMirrorRepeat_Mode:
+                    useSampler = true;
+                    samplerMode = GrSamplerState::WrapMode::kMirrorRepeat;
+                    break;
+                case GrTextureDomain::kDecal_Mode:
+                    // Not sure if we support this in HW without having GrCaps here.
+                    // Just wait until we replace this with GrTextureEffect.
+                    break;
+            }
+            if (useSampler) {
+                fMode = GrTextureDomain::kIgnore_Mode;
+                if (fDirection == Direction::kX) {
+                    fTextureSampler.samplerState().setWrapModeX(samplerMode);
+                } else {
+                    fTextureSampler.samplerState().setWrapModeY(samplerMode);
+                }
+            }
+        }
+    }
     memcpy(fBounds, bounds, sizeof(fBounds));
 }
 
diff --git a/src/gpu/effects/GrRRectBlurEffect.fp b/src/gpu/effects/GrRRectBlurEffect.fp
index 290295b..9234ac6 100644
--- a/src/gpu/effects/GrRRectBlurEffect.fp
+++ b/src/gpu/effects/GrRRectBlurEffect.fp
@@ -80,10 +80,10 @@
                                                    SkIPoint::Make(0, 0),
                                                    nullptr,
                                                    SkIRect::MakeSize(dimensions),
-                                                   SkIRect::MakeEmpty(),
+                                                   SkIRect::MakeSize(dimensions),
                                                    xformedSigma,
                                                    xformedSigma,
-                                                   GrTextureDomain::kIgnore_Mode,
+                                                   SkTileMode::kClamp,
                                                    SkBackingFit::kExact);
             if (!rtc2) {
                 return nullptr;
diff --git a/src/gpu/effects/generated/GrRRectBlurEffect.h b/src/gpu/effects/generated/GrRRectBlurEffect.h
index 94b6ca1..1985277 100644
--- a/src/gpu/effects/generated/GrRRectBlurEffect.h
+++ b/src/gpu/effects/generated/GrRRectBlurEffect.h
@@ -80,10 +80,10 @@
                                                      SkIPoint::Make(0, 0),
                                                      nullptr,
                                                      SkIRect::MakeSize(dimensions),
-                                                     SkIRect::MakeEmpty(),
+                                                     SkIRect::MakeSize(dimensions),
                                                      xformedSigma,
                                                      xformedSigma,
-                                                     GrTextureDomain::kIgnore_Mode,
+                                                     SkTileMode::kClamp,
                                                      SkBackingFit::kExact);
             if (!rtc2) {
                 return nullptr;