Remove GrTextureProducer::DetermineDomainMode.

We now rely on GrTextureEffect and GrBicbicEffect
to determine if shader-based tiling is required.

GrTextureProducer is still responsible for noticing that
the proxy is approximate because GrTextureEffect doesn't
consider that in its basic Make() factory (as opposed to
MakeSubset()).

Change-Id: I8e1aeb9edbcfa73ea0bf80b5256ee1ca21fe9c81
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/301985
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrTextureAdjuster.cpp b/src/gpu/GrTextureAdjuster.cpp
index e83ef0a..59e7cd8 100644
--- a/src/gpu/GrTextureAdjuster.cpp
+++ b/src/gpu/GrTextureAdjuster.cpp
@@ -94,27 +94,12 @@
     }
     SkASSERT(view.asTextureProxy());
 
-    SkRect domain;
-    DomainMode domainMode =
-        DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
-                            view.proxy(), filterOrNullForBicubic, &domain);
-    if (kTightCopy_DomainMode == domainMode) {
-        // TODO: Copy the texture and adjust the texture matrix (both parts need to consider
-        // non-int constraint rect)
-        // For now: treat as bilerp and ignore what goes on above level 0.
-
-        // We only expect MIP maps to require a tight copy.
-        SkASSERT(filterOrNullForBicubic &&
-                 GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic);
-        static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
-        domainMode =
-            DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
-                                view.proxy(), &kBilerp, &domain);
-        SkASSERT(kTightCopy_DomainMode != domainMode);
-    }
-    SkASSERT(kNoDomain_DomainMode == domainMode ||
-             (domain.fLeft <= domain.fRight && domain.fTop <= domain.fBottom));
-    return this->createFragmentProcessorForSubsetAndFilter(std::move(view), textureMatrix,
-                                                           domainMode, domain, wrapX, wrapY,
+    return this->createFragmentProcessorForSubsetAndFilter(std::move(view),
+                                                           textureMatrix,
+                                                           coordsLimitedToConstraintRect,
+                                                           filterConstraint,
+                                                           constraintRect,
+                                                           wrapX,
+                                                           wrapY,
                                                            filterOrNullForBicubic);
 }
diff --git a/src/gpu/GrTextureMaker.cpp b/src/gpu/GrTextureMaker.cpp
index 7db8b91..bddf275 100644
--- a/src/gpu/GrTextureMaker.cpp
+++ b/src/gpu/GrTextureMaker.cpp
@@ -30,18 +30,6 @@
         GrSamplerState::WrapMode wrapX,
         GrSamplerState::WrapMode wrapY,
         const GrSamplerState::Filter* filterOrNullForBicubic) {
-    const GrSamplerState::Filter* fmForDetermineDomain = filterOrNullForBicubic;
-    if (filterOrNullForBicubic && GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic &&
-        kYes_FilterConstraint == filterConstraint) {
-        // TODO: Here we should force a copy restricted to the constraintRect since MIP maps will
-        // read outside the constraint rect. However, as in the adjuster case, we aren't currently
-        // doing that.
-        // We instead we compute the domain as though were bilerping which is only correct if we
-        // only sample level 0.
-        static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
-        fmForDetermineDomain = &kBilerp;
-    }
-
     GrSurfaceProxyView view;
     if (filterOrNullForBicubic) {
         view = this->view(*filterOrNullForBicubic);
@@ -52,12 +40,12 @@
         return nullptr;
     }
 
-    SkRect domain;
-    DomainMode domainMode =
-        DetermineDomainMode(constraintRect, filterConstraint, coordsLimitedToConstraintRect,
-                            view.proxy(), fmForDetermineDomain, &domain);
-    SkASSERT(kTightCopy_DomainMode != domainMode);
-    return this->createFragmentProcessorForSubsetAndFilter(std::move(view), textureMatrix,
-                                                           domainMode, domain, wrapX, wrapY,
+    return this->createFragmentProcessorForSubsetAndFilter(std::move(view),
+                                                           textureMatrix,
+                                                           coordsLimitedToConstraintRect,
+                                                           filterConstraint,
+                                                           constraintRect,
+                                                           wrapX,
+                                                           wrapY,
                                                            filterOrNullForBicubic);
 }
diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp
index 8bc9427..2a1d6d6 100644
--- a/src/gpu/GrTextureProducer.cpp
+++ b/src/gpu/GrTextureProducer.cpp
@@ -20,148 +20,57 @@
 #include "src/gpu/effects/GrBicubicEffect.h"
 #include "src/gpu/effects/GrTextureEffect.h"
 
-/** Determines whether a texture domain is necessary and if so what domain to use. There are two
- *  rectangles to consider:
- *  - The first is the content area specified by the texture adjuster (i.e., textureContentArea).
- *    We can *never* allow filtering to cause bleed of pixels outside this rectangle.
- *  - The second rectangle is the constraint rectangle (i.e., constraintRect), which is known to
- *    be contained by the content area. The filterConstraint specifies whether we are allowed to
- *    bleed across this rect.
- *
- *  We want to avoid using a domain if possible. We consider the above rectangles, the filter type,
- *  and whether the coords generated by the draw would all fall within the constraint rect. If the
- *  latter is true we only need to consider whether the filter would extend beyond the rects.
- */
-GrTextureProducer::DomainMode GrTextureProducer::DetermineDomainMode(
-        const SkRect& constraintRect,
-        FilterConstraint filterConstraint,
-        bool coordsLimitedToConstraintRect,
-        GrSurfaceProxy* proxy,
-        const GrSamplerState::Filter* filterModeOrNullForBicubic,
-        SkRect* domainRect) {
-    const SkIRect proxyBounds = SkIRect::MakeSize(proxy->dimensions());
-
-    SkASSERT(proxyBounds.contains(constraintRect));
-
-    const bool proxyIsExact = proxy->isFunctionallyExact();
-
-    // If the constraint rectangle contains the whole proxy then no need for a domain.
-    if (constraintRect.contains(proxyBounds) && proxyIsExact) {
-        return kNoDomain_DomainMode;
-    }
-
-    bool restrictFilterToRect = (filterConstraint == GrTextureProducer::kYes_FilterConstraint);
-
-    // If we can filter outside the constraint rect, and there is no non-content area of the
-    // proxy, and we aren't going to generate sample coords outside the constraint rect then we
-    // don't need a domain.
-    if (!restrictFilterToRect && proxyIsExact && coordsLimitedToConstraintRect) {
-        return kNoDomain_DomainMode;
-    }
-
-    // Get the domain inset based on sampling mode (or bail if mipped). This is used
-    // to evaluate whether we will read outside a non-exact proxy's dimensions.
-    // TODO: Let GrTextureEffect handle this.
-    SkScalar filterHalfWidth = 0.f;
-    if (filterModeOrNullForBicubic) {
-        switch (*filterModeOrNullForBicubic) {
-            case GrSamplerState::Filter::kNearest:
-                if (coordsLimitedToConstraintRect) {
-                    return kNoDomain_DomainMode;
-                } else {
-                    filterHalfWidth = 0.f;
-                }
-                break;
-            case GrSamplerState::Filter::kBilerp:
-                filterHalfWidth = .5f;
-                break;
-            case GrSamplerState::Filter::kMipMap:
-                if (restrictFilterToRect || !proxyIsExact) {
-                    // No domain can save us here.
-                    return kTightCopy_DomainMode;
-                }
-                return kNoDomain_DomainMode;
-        }
-    } else {
-        // bicubic does nearest filtering internally.
-        filterHalfWidth = 1.5f;
-    }
-
-    if (restrictFilterToRect) {
-        *domainRect = constraintRect;
-    } else if (!proxyIsExact) {
-        // If we got here then: proxy is not exact, the coords are limited to the
-        // constraint rect, and we're allowed to filter across the constraint rect boundary. So
-        // we check whether the filter would reach across the edge of the proxy.
-        // We will only set the sides that are required.
-
-        *domainRect = SkRectPriv::MakeLargest();
-        if (coordsLimitedToConstraintRect) {
-            // We may be able to use the fact that the texture coords are limited to the constraint
-            // rect in order to avoid having to add a domain.
-            bool needContentAreaConstraint = false;
-            if (proxyBounds.fRight - filterHalfWidth < constraintRect.fRight) {
-                domainRect->fRight = proxyBounds.fRight;
-                needContentAreaConstraint = true;
-            }
-            if (proxyBounds.fBottom - filterHalfWidth < constraintRect.fBottom) {
-                domainRect->fBottom = proxyBounds.fBottom;
-                needContentAreaConstraint = true;
-            }
-            if (!needContentAreaConstraint) {
-                return kNoDomain_DomainMode;
-            }
-        }
-    } else {
-        return kNoDomain_DomainMode;
-    }
-
-    if (!filterModeOrNullForBicubic) {
-        // Bicubic doesn't yet rely on GrTextureEffect to do this insetting.
-        domainRect->inset(0.5f, 0.5f);
-        if (domainRect->fLeft > domainRect->fRight) {
-            domainRect->fLeft = domainRect->fRight =
-                    SkScalarAve(domainRect->fLeft, domainRect->fRight);
-        }
-        if (domainRect->fTop > domainRect->fBottom) {
-            domainRect->fTop = domainRect->fBottom =
-                    SkScalarAve(domainRect->fTop, domainRect->fBottom);
-        }
-    }
-
-    return kDomain_DomainMode;
-}
-
 std::unique_ptr<GrFragmentProcessor> GrTextureProducer::createFragmentProcessorForSubsetAndFilter(
         GrSurfaceProxyView view,
         const SkMatrix& textureMatrix,
-        DomainMode domainMode,
-        const SkRect& domain,
+        bool coordsLimitedToConstraintRect,
+        FilterConstraint filterConstraint,
+        const SkRect& constraintRect,
         GrSamplerState::WrapMode wrapX,
         GrSamplerState::WrapMode wrapY,
         const GrSamplerState::Filter* filterOrNullForBicubic) {
-    SkASSERT(kTightCopy_DomainMode != domainMode);
-    SkASSERT(view.asTextureProxy());
+    SkRect tempSubset;
+
+    const SkRect* subset = nullptr;
+    if (filterConstraint == kYes_FilterConstraint) {
+        subset = &constraintRect;
+    } else if (!view.proxy()->isFullyLazy() && !view.proxy()->isFunctionallyExact()) {
+        tempSubset = view.proxy()->getBoundsRect();
+        subset = &tempSubset;
+    }
+
     const auto& caps = *fContext->priv().caps();
-    SkAlphaType srcAlphaType = this->alphaType();
     if (filterOrNullForBicubic) {
         GrSamplerState samplerState(wrapX, wrapY, *filterOrNullForBicubic);
-        if (kNoDomain_DomainMode == domainMode) {
-            return GrTextureEffect::Make(std::move(view), srcAlphaType, textureMatrix, samplerState,
-                                         caps);
+        if (subset) {
+            if (coordsLimitedToConstraintRect) {
+                return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(),
+                                                   textureMatrix, samplerState, *subset,
+                                                   constraintRect, caps);
+            } else {
+                return GrTextureEffect::MakeSubset(std::move(view), this->alphaType(),
+                                                   textureMatrix, samplerState, *subset, caps);
+            }
+        } else {
+            return GrTextureEffect::Make(std::move(view), this->alphaType(), textureMatrix,
+                                         samplerState, caps);
         }
-        return GrTextureEffect::MakeSubset(std::move(view), srcAlphaType, textureMatrix,
-                                           samplerState, domain, caps);
     } else {
         static constexpr auto kDir    = GrBicubicEffect::Direction::kXY;
         static constexpr auto kKernel = GrBicubicEffect::Kernel::kMitchell;
-        const auto& caps = *fContext->priv().caps();
-        if (kDomain_DomainMode == domainMode) {
-            return GrBicubicEffect::MakeSubset(std::move(view), srcAlphaType, textureMatrix, wrapX,
-                                               wrapY, domain, kKernel, kDir, caps);
+        if (subset) {
+            if (coordsLimitedToConstraintRect) {
+                return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(),
+                                                   textureMatrix, wrapX, wrapY, *subset,
+                                                   constraintRect, kKernel, kDir, caps);
+            } else {
+                return GrBicubicEffect::MakeSubset(std::move(view), this->alphaType(),
+                                                   textureMatrix, wrapX, wrapY, *subset, kKernel,
+                                                   kDir, caps);
+            }
         } else {
-            return GrBicubicEffect::Make(std::move(view), srcAlphaType, textureMatrix, wrapX, wrapY,
-                                         kKernel, kDir, caps);
+            return GrBicubicEffect::Make(std::move(view), this->alphaType(), textureMatrix, wrapX,
+                                         wrapY, kKernel, kDir, caps);
         }
     }
 }
diff --git a/src/gpu/GrTextureProducer.h b/src/gpu/GrTextureProducer.h
index 4a13357..657553e 100644
--- a/src/gpu/GrTextureProducer.h
+++ b/src/gpu/GrTextureProducer.h
@@ -32,16 +32,16 @@
  */
 class GrTextureProducer : public SkNoncopyable {
 public:
-    virtual ~GrTextureProducer() {}
+    virtual ~GrTextureProducer() = default;
 
     enum FilterConstraint {
         kYes_FilterConstraint,
         kNo_FilterConstraint,
     };
 
-    /**
+   /**
      * Helper for creating a fragment processor to sample the texture with a given filtering mode.
-     * It attempts to avoid making texture copies or using domains whenever possible.
+     * It attempts to avoid making texture copies or using shader tiling whenever possible.
      *
      * @param textureMatrix                    Matrix used to access the texture. It is applied to
      *                                         the local coords. The post-transformed coords should
@@ -89,29 +89,15 @@
     virtual bool isPlanar() const { return false; }
 
 protected:
-    friend class GrTextureProducer_TestAccess;
-
     GrTextureProducer(GrRecordingContext* context, const GrImageInfo& imageInfo)
             : fContext(context), fImageInfo(imageInfo) {}
 
-    enum DomainMode {
-        kNoDomain_DomainMode,
-        kDomain_DomainMode,
-        kTightCopy_DomainMode
-    };
-
-    static DomainMode DetermineDomainMode(const SkRect& constraintRect,
-                                          FilterConstraint filterConstraint,
-                                          bool coordsLimitedToConstraintRect,
-                                          GrSurfaceProxy*,
-                                          const GrSamplerState::Filter* filterModeOrNullForBicubic,
-                                          SkRect* domainRect);
-
     std::unique_ptr<GrFragmentProcessor> createFragmentProcessorForSubsetAndFilter(
             GrSurfaceProxyView view,
             const SkMatrix& textureMatrix,
-            DomainMode,
-            const SkRect& domain,
+            bool coordsLimitedToConstraintRect,
+            FilterConstraint filterConstraint,
+            const SkRect& constraintRect,
             GrSamplerState::WrapMode wrapX,
             GrSamplerState::WrapMode wrapY,
             const GrSamplerState::Filter* filterOrNullForBicubic);
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index 1df8006..385dec0 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -14,6 +14,7 @@
 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
+#include <cmath>
 
 class GrBicubicEffect::Impl : public GrGLSLFragmentProcessor {
 public:
@@ -180,6 +181,34 @@
             new GrBicubicEffect(std::move(fp), kernel, direction, clamp)));
 }
 
+std::unique_ptr<GrFragmentProcessor> GrBicubicEffect::MakeSubset(
+        GrSurfaceProxyView view,
+        SkAlphaType alphaType,
+        const SkMatrix& matrix,
+        const GrSamplerState::WrapMode wrapX,
+        const GrSamplerState::WrapMode wrapY,
+        const SkRect& subset,
+        const SkRect& domain,
+        Kernel kernel,
+        Direction direction,
+        const GrCaps& caps) {
+    auto lowerBound = [](float x) { return std::floor(x - 1.5f) + 0.5f; };
+    auto upperBound = [](float x) { return std::floor(x + 1.5f) - 0.5f; };
+    SkRect expandedDomain {
+            lowerBound(domain.fLeft)  ,
+            upperBound(domain.fRight) ,
+            lowerBound(domain.fTop)   ,
+            upperBound(domain.fBottom)
+    };
+    GrSamplerState sampler(wrapX, wrapY, GrSamplerState::Filter::kNearest);
+    std::unique_ptr<GrFragmentProcessor> fp;
+    fp = GrTextureEffect::MakeSubset(
+            std::move(view), alphaType, SkMatrix::I(), sampler, subset, expandedDomain, caps);
+    auto clamp = kPremul_SkAlphaType == alphaType ? Clamp::kPremul : Clamp::kUnpremul;
+    return GrMatrixEffect::Make(matrix, std::unique_ptr<GrFragmentProcessor>(
+            new GrBicubicEffect(std::move(fp), kernel, direction, clamp)));
+}
+
 std::unique_ptr<GrFragmentProcessor> GrBicubicEffect::Make(std::unique_ptr<GrFragmentProcessor> fp,
                                                            SkAlphaType alphaType,
                                                            const SkMatrix& matrix,
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
index b9b420c..a0de090 100644
--- a/src/gpu/effects/GrBicubicEffect.h
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -75,6 +75,21 @@
                                                            const GrCaps&);
 
     /**
+     * Same as above but provides a known 'domain' that bounds the coords at which bicubic sampling
+     * occurs. Note that this is a bound on the coords after transformed by the matrix parameter.
+     */
+    static std::unique_ptr<GrFragmentProcessor> MakeSubset(GrSurfaceProxyView view,
+                                                           SkAlphaType,
+                                                           const SkMatrix&,
+                                                           const GrSamplerState::WrapMode wrapX,
+                                                           const GrSamplerState::WrapMode wrapY,
+                                                           const SkRect& subset,
+                                                           const SkRect& domain,
+                                                           Kernel,
+                                                           Direction,
+                                                           const GrCaps&);
+
+    /**
      * Make a bicubic filter of a another fragment processor. The bicubic filter assumes that the
      * discrete samples of the provided processor are at half-integer coords.
      */