Push GrTextureProxy down to more effects

Change-Id: Ie3f32a88f25af082c25bc6daf3fe24e303e80f9e
Reviewed-on: https://skia-review.googlesource.com/7616
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/effects/Gr1DKernelEffect.h b/src/gpu/effects/Gr1DKernelEffect.h
index 67cc771..24c94fc 100644
--- a/src/gpu/effects/Gr1DKernelEffect.h
+++ b/src/gpu/effects/Gr1DKernelEffect.h
@@ -28,13 +28,23 @@
         kY_Direction,
     };
 
-    Gr1DKernelEffect(GrTexture* texture, Direction direction, int radius,
+    Gr1DKernelEffect(GrTexture* texture,
+                     Direction direction,
+                     int radius,
                      OptimizationFlags optFlags)
-            : INHERITED(texture, nullptr, SkMatrix::I(), optFlags)
-            , fDirection(direction)
-            , fRadius(radius) {}
+        : INHERITED(texture, nullptr, SkMatrix::I(), optFlags)
+        , fDirection(direction)
+        , fRadius(radius) {
+    }
 
-    virtual ~Gr1DKernelEffect() {}
+    Gr1DKernelEffect(GrContext* ctx, OptimizationFlags optFlags, sk_sp<GrTextureProxy> proxy,
+                     Direction direction, int radius)
+        : INHERITED(ctx, optFlags, std::move(proxy), nullptr, SkMatrix::I())
+        , fDirection(direction)
+        , fRadius(radius) {
+    }
+
+    ~Gr1DKernelEffect() override {}
 
     static int WidthFromRadius(int radius) { return 2 * radius + 1; }
 
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index cf3d2b5..cb58995 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -7,6 +7,7 @@
 
 #include "GrBicubicEffect.h"
 #include "GrInvariantOutput.h"
+#include "GrProxyMove.h"
 #include "glsl/GrGLSLColorSpaceXformHelper.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
@@ -152,6 +153,31 @@
     this->initClassID<GrBicubicEffect>();
 }
 
+GrBicubicEffect::GrBicubicEffect(GrContext* context, sk_sp<GrTextureProxy> proxy,
+                                 sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                 const SkMatrix &matrix,
+                                 const SkShader::TileMode tileModes[2])
+  : INHERITED{context,
+              ModulationFlags(proxy->config()),
+              GR_PROXY_MOVE(proxy),
+              std::move(colorSpaceXform),
+              matrix,
+              GrSamplerParams(tileModes, GrSamplerParams::kNone_FilterMode)}
+  , fDomain(GrTextureDomain::IgnoredDomain()) {
+    this->initClassID<GrBicubicEffect>();
+}
+
+GrBicubicEffect::GrBicubicEffect(GrContext* context, sk_sp<GrTextureProxy> proxy,
+                                 sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                 const SkMatrix &matrix,
+                                 const SkRect& domain)
+  : INHERITED(context, ModulationFlags(proxy->config()), proxy,
+              std::move(colorSpaceXform), matrix,
+              GrSamplerParams(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode))
+  , fDomain(proxy.get(), domain, GrTextureDomain::kClamp_Mode) {
+    this->initClassID<GrBicubicEffect>();
+}
+
 GrBicubicEffect::~GrBicubicEffect() {
 }
 
@@ -177,12 +203,12 @@
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrBicubicEffect);
 
 sk_sp<GrFragmentProcessor> GrBicubicEffect::TestCreate(GrProcessorTestData* d) {
-    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
-                                          GrProcessorUnitTest::kAlphaTextureIdx;
-    auto colorSpaceXform = GrTest::TestColorXform(d->fRandom);
+    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
+                                        : GrProcessorUnitTest::kAlphaTextureIdx;
+    sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(d->fRandom);
     static const SkShader::TileMode kClampClamp[] =
         { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode };
-    return GrBicubicEffect::Make(d->fTextures[texIdx], colorSpaceXform,
+    return GrBicubicEffect::Make(d->context(), d->textureProxy(texIdx), std::move(colorSpaceXform),
                                  SkMatrix::I(), kClampClamp);
 }
 
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
index d0f5f41..a51aad8 100644
--- a/src/gpu/effects/GrBicubicEffect.h
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -49,6 +49,30 @@
     }
 
     /**
+     * Create a Mitchell filter effect with specified texture matrix and x/y tile modes.
+     */
+    static sk_sp<GrFragmentProcessor> Make(GrContext* context, sk_sp<GrTextureProxy> proxy,
+                                           sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                           const SkMatrix& matrix,
+                                           const SkShader::TileMode tileModes[2]) {
+        return sk_sp<GrFragmentProcessor>(new GrBicubicEffect(context, std::move(proxy),
+                                                              std::move(colorSpaceXform),
+                                                              matrix, tileModes));
+    }
+
+    /**
+     * Create a Mitchell filter effect with a texture matrix and a domain.
+     */
+    static sk_sp<GrFragmentProcessor> Make(GrContext* context, sk_sp<GrTextureProxy> proxy,
+                                           sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                           const SkMatrix& matrix,
+                                           const SkRect& domain) {
+        return sk_sp<GrFragmentProcessor>(new GrBicubicEffect(context, std::move(proxy),
+                                                              std::move(colorSpaceXform),
+                                                              matrix, domain));
+    }
+
+    /**
      * Determines whether the bicubic effect should be used based on the transformation from the
      * local coords to the device. Returns true if the bicubic effect should be used. filterMode
      * is set to appropriate filtering mode to use regardless of the return result (e.g. when this
@@ -64,6 +88,11 @@
     GrBicubicEffect(GrTexture*, sk_sp<GrColorSpaceXform>, const SkMatrix &matrix,
                     const SkRect& domain);
 
+    GrBicubicEffect(GrContext*, sk_sp<GrTextureProxy>, sk_sp<GrColorSpaceXform>,
+                    const SkMatrix &matrix, const SkShader::TileMode tileModes[2]);
+    GrBicubicEffect(GrContext*, sk_sp<GrTextureProxy>, sk_sp<GrColorSpaceXform>,
+                    const SkMatrix &matrix, const SkRect& domain);
+
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
index be6d4d8..c5f554f 100644
--- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
+++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "GrGaussianConvolutionFragmentProcessor.h"
+#include "GrProxyMove.h"
 #include "../private/GrGLSL.h"
 #include "glsl/GrGLSLFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
@@ -144,6 +145,25 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+
+static void fill_in_1D_guassian_kernel(float* kernel, int width, float gaussianSigma, int radius) {
+    const float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma);
+
+    float sum = 0.0f;
+    for (int i = 0; i < width; ++i) {
+        float x = static_cast<float>(i - radius);
+        // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
+        // is dropped here, since we renormalize the kernel below.
+        kernel[i] = sk_float_exp(-x * x * denom);
+        sum += kernel[i];
+    }
+    // Normalize the kernel
+    float scale = 1.0f / sum;
+    for (int i = 0; i < width; ++i) {
+        kernel[i] *= scale;
+    }
+}
+
 GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor(GrTexture* texture,
                                                                                Direction direction,
                                                                                int radius,
@@ -154,22 +174,31 @@
         , fUseBounds(useBounds) {
     this->initClassID<GrGaussianConvolutionFragmentProcessor>();
     SkASSERT(radius <= kMaxKernelRadius);
-    int width = this->width();
 
-    float sum = 0.0f;
-    float denom = 1.0f / (2.0f * gaussianSigma * gaussianSigma);
-    for (int i = 0; i < width; ++i) {
-        float x = static_cast<float>(i - this->radius());
-        // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
-        // is dropped here, since we renormalize the kernel below.
-        fKernel[i] = sk_float_exp(-x * x * denom);
-        sum += fKernel[i];
-    }
-    // Normalize the kernel
-    float scale = 1.0f / sum;
-    for (int i = 0; i < width; ++i) {
-        fKernel[i] *= scale;
-    }
+    fill_in_1D_guassian_kernel(fKernel, this->width(), gaussianSigma, this->radius());
+
+    memcpy(fBounds, bounds, sizeof(fBounds));
+}
+
+GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor(
+                                                                    GrContext* context,
+                                                                    sk_sp<GrTextureProxy> proxy,
+                                                                    Direction direction,
+                                                                    int radius,
+                                                                    float gaussianSigma,
+                                                                    bool useBounds,
+                                                                    float bounds[2])
+        : INHERITED{context,
+                    ModulationFlags(proxy->config()),
+                    GR_PROXY_MOVE(proxy),
+                    direction,
+                    radius}
+        , fUseBounds(useBounds) {
+    this->initClassID<GrGaussianConvolutionFragmentProcessor>();
+    SkASSERT(radius <= kMaxKernelRadius);
+
+    fill_in_1D_guassian_kernel(fKernel, this->width(), gaussianSigma, this->radius());
+
     memcpy(fBounds, bounds, sizeof(fBounds));
 }
 
@@ -212,5 +241,5 @@
 
     float sigma = radius / 3.f;
     return GrGaussianConvolutionFragmentProcessor::Make(
-            d->fTextures[texIdx], dir, radius, sigma, useBounds, bounds);
+            d->context(), d->textureProxy(texIdx), dir, radius, sigma, useBounds, bounds);
 }
diff --git a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h
index da40ec2..b4f5cb7 100644
--- a/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h
+++ b/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h
@@ -29,7 +29,18 @@
                 tex, dir, halfWidth, gaussianSigma, useBounds, bounds));
     }
 
-    virtual ~GrGaussianConvolutionFragmentProcessor();
+    static sk_sp<GrFragmentProcessor> Make(GrContext* context,
+                                           sk_sp<GrTextureProxy> proxy,
+                                           Direction dir,
+                                           int halfWidth,
+                                           float gaussianSigma,
+                                           bool useBounds,
+                                           float* bounds) {
+        return sk_sp<GrFragmentProcessor>(new GrGaussianConvolutionFragmentProcessor(
+                context, std::move(proxy), dir, halfWidth, gaussianSigma, useBounds, bounds));
+    }
+
+    ~GrGaussianConvolutionFragmentProcessor() override;
 
     const float* kernel() const { return fKernel; }
 
@@ -52,6 +63,10 @@
     GrGaussianConvolutionFragmentProcessor(GrTexture*, Direction, int halfWidth,
                                            float gaussianSigma, bool useBounds, float bounds[2]);
 
+    GrGaussianConvolutionFragmentProcessor(GrContext*, sk_sp<GrTextureProxy>, Direction,
+                                           int halfWidth, float gaussianSigma, bool useBounds,
+                                           float bounds[2]);
+
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
@@ -69,7 +84,7 @@
     // TODO: Inline the kernel constants into the generated shader code. This may involve pulling
     // some of the logic from SkGpuBlurUtils into this class related to radius/sigma calculations.
     float fKernel[kMaxKernelWidth];
-    bool fUseBounds;
+    bool  fUseBounds;
     float fBounds[2];
 
     typedef Gr1DKernelEffect INHERITED;
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
index 9b670e1..86fd565 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
@@ -172,6 +172,32 @@
     fKernelOffset[1] = static_cast<float>(kernelOffset.y());
 }
 
+GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrContext* context,
+                                                     sk_sp<GrTextureProxy> proxy,
+                                                     const SkIRect& bounds,
+                                                     const SkISize& kernelSize,
+                                                     const SkScalar* kernel,
+                                                     SkScalar gain,
+                                                     SkScalar bias,
+                                                     const SkIPoint& kernelOffset,
+                                                     GrTextureDomain::Mode tileMode,
+                                                     bool convolveAlpha)
+    // To advertise either the modulation or opaqueness optimizations we'd have to examine the
+    // parameters.
+    : INHERITED(context, kNone_OptimizationFlags, proxy, nullptr, SkMatrix::I())
+    , fKernelSize(kernelSize)
+    , fGain(SkScalarToFloat(gain))
+    , fBias(SkScalarToFloat(bias) / 255.0f)
+    , fConvolveAlpha(convolveAlpha)
+    , fDomain(proxy.get(), GrTextureDomain::MakeTexelDomainForMode(bounds, tileMode), tileMode) {
+    this->initClassID<GrMatrixConvolutionEffect>();
+    for (int i = 0; i < kernelSize.width() * kernelSize.height(); i++) {
+        fKernel[i] = SkScalarToFloat(kernel[i]);
+    }
+    fKernelOffset[0] = static_cast<float>(kernelOffset.x());
+    fKernelOffset[1] = static_cast<float>(kernelOffset.y());
+}
+
 void GrMatrixConvolutionEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                                       GrProcessorKeyBuilder* b) const {
     GrGLMatrixConvolutionEffect::GenKey(*this, caps, b);
@@ -193,49 +219,75 @@
            fDomain == s.domain();
 }
 
-// Static function to create a 2D convolution
-sk_sp<GrFragmentProcessor>
-GrMatrixConvolutionEffect::MakeGaussian(GrTexture* texture,
-                                        const SkIRect& bounds,
-                                        const SkISize& kernelSize,
-                                        SkScalar gain,
-                                        SkScalar bias,
-                                        const SkIPoint& kernelOffset,
-                                        GrTextureDomain::Mode tileMode,
-                                        bool convolveAlpha,
-                                        SkScalar sigmaX,
-                                        SkScalar sigmaY) {
-    float kernel[MAX_KERNEL_SIZE];
-    int width = kernelSize.width();
-    int height = kernelSize.height();
+static void fill_in_2D_gaussian_kernel(float* kernel, int width, int height,
+                                       SkScalar sigmaX, SkScalar sigmaY) {
     SkASSERT(width * height <= MAX_KERNEL_SIZE);
+    const float sigmaXDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaX)));
+    const float sigmaYDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaY)));
+    const int xRadius = width / 2;
+    const int yRadius = height / 2;
+
     float sum = 0.0f;
-    float sigmaXDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaX)));
-    float sigmaYDenom = 1.0f / (2.0f * SkScalarToFloat(SkScalarSquare(sigmaY)));
-    int xRadius = width / 2;
-    int yRadius = height / 2;
     for (int x = 0; x < width; x++) {
-      float xTerm = static_cast<float>(x - xRadius);
-      xTerm = xTerm * xTerm * sigmaXDenom;
-      for (int y = 0; y < height; y++) {
-        float yTerm = static_cast<float>(y - yRadius);
-        float xyTerm = sk_float_exp(-(xTerm + yTerm * yTerm * sigmaYDenom));
-        // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
-       // is dropped here, since we renormalize the kernel below.
-        kernel[y * width + x] = xyTerm;
-        sum += xyTerm;
-      }
+        float xTerm = static_cast<float>(x - xRadius);
+        xTerm = xTerm * xTerm * sigmaXDenom;
+        for (int y = 0; y < height; y++) {
+            float yTerm = static_cast<float>(y - yRadius);
+            float xyTerm = sk_float_exp(-(xTerm + yTerm * yTerm * sigmaYDenom));
+            // Note that the constant term (1/(sqrt(2*pi*sigma^2)) of the Gaussian
+            // is dropped here, since we renormalize the kernel below.
+            kernel[y * width + x] = xyTerm;
+            sum += xyTerm;
+        }
     }
     // Normalize the kernel
     float scale = 1.0f / sum;
     for (int i = 0; i < width * height; ++i) {
         kernel[i] *= scale;
     }
+}
+
+
+// Static function to create a 2D convolution
+sk_sp<GrFragmentProcessor> GrMatrixConvolutionEffect::MakeGaussian(GrTexture* texture,
+                                                                   const SkIRect& bounds,
+                                                                   const SkISize& kernelSize,
+                                                                   SkScalar gain,
+                                                                   SkScalar bias,
+                                                                   const SkIPoint& kernelOffset,
+                                                                   GrTextureDomain::Mode tileMode,
+                                                                   bool convolveAlpha,
+                                                                   SkScalar sigmaX,
+                                                                   SkScalar sigmaY) {
+    float kernel[MAX_KERNEL_SIZE];
+
+    fill_in_2D_gaussian_kernel(kernel, kernelSize.width(), kernelSize.height(), sigmaX, sigmaY);
+
     return sk_sp<GrFragmentProcessor>(
         new GrMatrixConvolutionEffect(texture, bounds, kernelSize, kernel, gain, bias,
                                       kernelOffset, tileMode, convolveAlpha));
 }
 
+sk_sp<GrFragmentProcessor> GrMatrixConvolutionEffect::MakeGaussian(GrContext* context,
+                                                                   sk_sp<GrTextureProxy> proxy,
+                                                                   const SkIRect& bounds,
+                                                                   const SkISize& kernelSize,
+                                                                   SkScalar gain,
+                                                                   SkScalar bias,
+                                                                   const SkIPoint& kernelOffset,
+                                                                   GrTextureDomain::Mode tileMode,
+                                                                   bool convolveAlpha,
+                                                                   SkScalar sigmaX,
+                                                                   SkScalar sigmaY) {
+    float kernel[MAX_KERNEL_SIZE];
+
+    fill_in_2D_gaussian_kernel(kernel, kernelSize.width(), kernelSize.height(), sigmaX, sigmaY);
+
+    return sk_sp<GrFragmentProcessor>(
+        new GrMatrixConvolutionEffect(context, std::move(proxy), bounds, kernelSize, kernel,
+                                      gain, bias, kernelOffset, tileMode, convolveAlpha));
+}
+
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMatrixConvolutionEffect);
 
 sk_sp<GrFragmentProcessor> GrMatrixConvolutionEffect::TestCreate(GrProcessorTestData* d) {
@@ -259,7 +311,8 @@
     GrTextureDomain::Mode tileMode =
             static_cast<GrTextureDomain::Mode>(d->fRandom->nextRangeU(0, 2));
     bool convolveAlpha = d->fRandom->nextBool();
-    return GrMatrixConvolutionEffect::Make(d->fTextures[texIdx],
+    return GrMatrixConvolutionEffect::Make(d->context(),
+                                           d->textureProxy(texIdx),
                                            bounds,
                                            kernelSize,
                                            kernel.get(),
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.h b/src/gpu/effects/GrMatrixConvolutionEffect.h
index 7cc88b6..0bb7c50 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.h
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.h
@@ -43,6 +43,33 @@
                                                    SkScalar sigmaX,
                                                    SkScalar sigmaY);
 
+    static sk_sp<GrFragmentProcessor> Make(GrContext* context,
+                                           sk_sp<GrTextureProxy> proxy,
+                                           const SkIRect& bounds,
+                                           const SkISize& kernelSize,
+                                           const SkScalar* kernel,
+                                           SkScalar gain,
+                                           SkScalar bias,
+                                           const SkIPoint& kernelOffset,
+                                           GrTextureDomain::Mode tileMode,
+                                           bool convolveAlpha) {
+        return sk_sp<GrFragmentProcessor>(
+            new GrMatrixConvolutionEffect(context, std::move(proxy), bounds, kernelSize, kernel,
+                                          gain, bias, kernelOffset, tileMode, convolveAlpha));
+    }
+
+    static sk_sp<GrFragmentProcessor> MakeGaussian(GrContext* context,
+                                                   sk_sp<GrTextureProxy> proxy,
+                                                   const SkIRect& bounds,
+                                                   const SkISize& kernelSize,
+                                                   SkScalar gain,
+                                                   SkScalar bias,
+                                                   const SkIPoint& kernelOffset,
+                                                   GrTextureDomain::Mode tileMode,
+                                                   bool convolveAlpha,
+                                                   SkScalar sigmaX,
+                                                   SkScalar sigmaY);
+
     const SkIRect& bounds() const { return fBounds; }
     const SkISize& kernelSize() const { return fKernelSize; }
     const float* kernelOffset() const { return fKernelOffset; }
@@ -65,6 +92,17 @@
                               GrTextureDomain::Mode tileMode,
                               bool convolveAlpha);
 
+    GrMatrixConvolutionEffect(GrContext*,
+                              sk_sp<GrTextureProxy> proxy,
+                              const SkIRect& bounds,
+                              const SkISize& kernelSize,
+                              const SkScalar* kernel,
+                              SkScalar gain,
+                              SkScalar bias,
+                              const SkIPoint& kernelOffset,
+                              GrTextureDomain::Mode tileMode,
+                              bool convolveAlpha);
+
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
diff --git a/src/gpu/effects/GrProxyMove.h b/src/gpu/effects/GrProxyMove.h
new file mode 100644
index 0000000..643e01b
--- /dev/null
+++ b/src/gpu/effects/GrProxyMove.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */

+

+#ifndef GrProxyMove_DEFINED
+#define GrProxyMove_DEFINED
+
+// In a few places below we rely on braced initialization order being defined by the C++ spec (left
+// to right). We use operator-> on a sk_sp and then in a later argument std::move() the sk_sp. GCC
+// 4.9.0 and earlier has a bug where the left to right order evaluation isn't implemented correctly.
+#if defined(__GNUC__) && !defined(__clang__)
+#   define GCC_VERSION (__GNUC__ * 10000  + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#   if (GCC_VERSION > 40900)
+#       define GCC_EVAL_ORDER_BUG 0
+#   else
+#       define GCC_EVAL_ORDER_BUG 1
+#   endif
+#   undef GCC_VERSION
+#else
+#   define GCC_EVAL_ORDER_BUG 0
+#endif
+
+#if GCC_EVAL_ORDER_BUG
+#   define GR_PROXY_MOVE(X) (X)
+#else
+#   define GR_PROXY_MOVE(X) (std::move(X))
+#endif
+
+#undef GCC_EVAL_ORDER_BUG
+
+#endif
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index 682539f..3dc6ea3 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -7,11 +7,38 @@
 
 #include "GrSimpleTextureEffect.h"
 #include "GrInvariantOutput.h"
+#include "GrProxyMove.h"
 #include "GrTexture.h"
 #include "glsl/GrGLSLColorSpaceXformHelper.h"
 #include "glsl/GrGLSLFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 
+GrSimpleTextureEffect::GrSimpleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
+                                             sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                             const SkMatrix& matrix,
+                                             GrSamplerParams::FilterMode filterMode)
+        : INHERITED{ctx,
+                    ModulationFlags(proxy->config()),
+                    GR_PROXY_MOVE(proxy),
+                    std::move(colorSpaceXform),
+                    matrix,
+                    filterMode} {
+    this->initClassID<GrSimpleTextureEffect>();
+}
+
+GrSimpleTextureEffect::GrSimpleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
+                                             sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                             const SkMatrix& matrix,
+                                             const GrSamplerParams& params)
+        : INHERITED{ctx,
+                    ModulationFlags(proxy->config()),
+                    GR_PROXY_MOVE(proxy),
+                    std::move(colorSpaceXform),
+                    matrix,
+                    params} {
+    this->initClassID<GrSimpleTextureEffect>();
+}
+
 class GrGLSimpleTextureEffect : public GrGLSLFragmentProcessor {
 public:
     void emitCode(EmitArgs& args) override {
@@ -70,8 +97,8 @@
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSimpleTextureEffect);
 
 sk_sp<GrFragmentProcessor> GrSimpleTextureEffect::TestCreate(GrProcessorTestData* d) {
-    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
-                                          GrProcessorUnitTest::kAlphaTextureIdx;
+    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
+                                        : GrProcessorUnitTest::kAlphaTextureIdx;
     static const SkShader::TileMode kTileModes[] = {
         SkShader::kClamp_TileMode,
         SkShader::kRepeat_TileMode,
@@ -81,10 +108,11 @@
         kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
         kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
     };
-    GrSamplerParams params(tileModes, d->fRandom->nextBool() ? GrSamplerParams::kBilerp_FilterMode :
-                                                               GrSamplerParams::kNone_FilterMode);
+    GrSamplerParams params(tileModes, d->fRandom->nextBool() ? GrSamplerParams::kBilerp_FilterMode
+                                                             : GrSamplerParams::kNone_FilterMode);
 
     const SkMatrix& matrix = GrTest::TestMatrix(d->fRandom);
-    auto colorSpaceXform = GrTest::TestColorXform(d->fRandom);
-    return GrSimpleTextureEffect::Make(d->fTextures[texIdx], colorSpaceXform, matrix);
+    sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(d->fRandom);
+    return GrSimpleTextureEffect::Make(d->context(), d->textureProxy(texIdx),
+                                       std::move(colorSpaceXform), matrix);
 }
diff --git a/src/gpu/effects/GrSimpleTextureEffect.h b/src/gpu/effects/GrSimpleTextureEffect.h
index c44ce44..64ca3cb 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.h
+++ b/src/gpu/effects/GrSimpleTextureEffect.h
@@ -13,29 +13,6 @@
 
 class GrInvariantOutput;
 
-// In a few places below we rely on braced initialization order being defined by the C++ spec (left
-// to right). We use operator-> on a sk_sp and then in a later argument std::move() the sk_sp. GCC
-// 4.9.0 and earlier has a bug where the left to right order evaluation isn't implemented correctly.
-#if defined(__GNUC__) && !defined(__clang__)
-#   define GCC_VERSION (__GNUC__ * 10000  + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
-#   if (GCC_VERSION > 40900)
-#       define GCC_EVAL_ORDER_BUG 0
-#   else
-#       define GCC_EVAL_ORDER_BUG 1
-#   endif
-#   undef GCC_VERSION
-#else
-#   define GCC_EVAL_ORDER_BUG 0
-#endif
-
-#if GCC_EVAL_ORDER_BUG
-#   define PROXY_MOVE(X) (X)
-#else
-#   define PROXY_MOVE(X) (std::move(X))
-#endif
-
-#undef GCC_EVAL_ORDER_BUG
-
 /**
  * The output color of this effect is a modulation of the input color and a sample from a texture.
  * It allows explicit specification of the filtering and wrap modes (GrSamplerParams) and accepts
@@ -52,14 +29,6 @@
                                       GrSamplerParams::kNone_FilterMode));
     }
 
-    static sk_sp<GrFragmentProcessor> Make(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
-                                           sk_sp<GrColorSpaceXform> colorSpaceXform,
-                                           const SkMatrix& matrix) {
-        return sk_sp<GrFragmentProcessor>(
-            new GrSimpleTextureEffect(ctx, std::move(proxy), std::move(colorSpaceXform), matrix,
-                                      GrSamplerParams::kNone_FilterMode));
-    }
-
     /* clamp mode */
     static sk_sp<GrFragmentProcessor> Make(GrTexture* tex,
                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
@@ -69,6 +38,24 @@
             new GrSimpleTextureEffect(tex, std::move(colorSpaceXform), matrix, filterMode));
     }
 
+    static sk_sp<GrFragmentProcessor> Make(GrTexture* tex,
+                                           sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                           const SkMatrix& matrix,
+                                           const GrSamplerParams& p) {
+        return sk_sp<GrFragmentProcessor>(new GrSimpleTextureEffect(tex, std::move(colorSpaceXform),
+                                                                    matrix, p));
+    }
+
+    /* unfiltered, clamp mode */
+    static sk_sp<GrFragmentProcessor> Make(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
+                                           sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                           const SkMatrix& matrix) {
+        return sk_sp<GrFragmentProcessor>(
+            new GrSimpleTextureEffect(ctx, std::move(proxy), std::move(colorSpaceXform), matrix,
+                                      GrSamplerParams::kNone_FilterMode));
+    }
+
+    /* clamp mode */
     static sk_sp<GrFragmentProcessor> Make(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
                                            const SkMatrix& matrix,
@@ -78,14 +65,6 @@
                                       matrix, filterMode));
     }
 
-    static sk_sp<GrFragmentProcessor> Make(GrTexture* tex,
-                                           sk_sp<GrColorSpaceXform> colorSpaceXform,
-                                           const SkMatrix& matrix,
-                                           const GrSamplerParams& p) {
-        return sk_sp<GrFragmentProcessor>(new GrSimpleTextureEffect(tex, std::move(colorSpaceXform),
-                                                                    matrix, p));
-    }
-
     static sk_sp<GrFragmentProcessor> Make(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
                                            sk_sp<GrColorSpaceXform> colorSpaceXform,
                                            const SkMatrix& matrix,
@@ -109,18 +88,6 @@
         this->initClassID<GrSimpleTextureEffect>();
     }
 
-    GrSimpleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
-                          sk_sp<GrColorSpaceXform> colorSpaceXform, const SkMatrix& matrix,
-                          GrSamplerParams::FilterMode filterMode)
-            : INHERITED{ctx,
-                        ModulationFlags(proxy->config()),
-                        PROXY_MOVE(proxy),
-                        std::move(colorSpaceXform),
-                        matrix,
-                        filterMode} {
-        this->initClassID<GrSimpleTextureEffect>();
-    }
-
     GrSimpleTextureEffect(GrTexture* texture,
                           sk_sp<GrColorSpaceXform>colorSpaceXform,
                           const SkMatrix& matrix,
@@ -132,15 +99,11 @@
 
     GrSimpleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
                           sk_sp<GrColorSpaceXform> colorSpaceXform, const SkMatrix& matrix,
-                          const GrSamplerParams& params)
-            : INHERITED{ctx,
-                        ModulationFlags(proxy->config()),
-                        PROXY_MOVE(proxy),
-                        std::move(colorSpaceXform),
-                        matrix,
-                        params} {
-        this->initClassID<GrSimpleTextureEffect>();
-    }
+                          GrSamplerParams::FilterMode filterMode);
+
+    GrSimpleTextureEffect(GrContext* ctx, sk_sp<GrTextureProxy> proxy,
+                          sk_sp<GrColorSpaceXform> colorSpaceXform, const SkMatrix& matrix,
+                          const GrSamplerParams& params);
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
@@ -155,6 +118,4 @@
     typedef GrSingleTextureEffect INHERITED;
 };
 
-#undef PROXY_MOVE
-
 #endif
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
index 7ab598f..f27b776 100644
--- a/src/gpu/effects/GrTextureDomain.cpp
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -6,9 +6,12 @@
  */
 
 #include "GrTextureDomain.h"
+
+#include "GrContext.h"
 #include "GrInvariantOutput.h"
 #include "GrShaderCaps.h"
 #include "GrSimpleTextureEffect.h"
+#include "GrSurfaceProxyPriv.h"
 #include "SkFloatingPoint.h"
 #include "glsl/GrGLSLColorSpaceXformHelper.h"
 #include "glsl/GrGLSLFragmentProcessor.h"
@@ -17,6 +20,16 @@
 #include "glsl/GrGLSLShaderBuilder.h"
 #include "glsl/GrGLSLUniformHandler.h"
 
+static bool can_ignore_rect(GrSurfaceProxy* proxy, const SkRect& domain) {
+    if (proxy->priv().isExact()) {
+        const SkIRect kFullRect = SkIRect::MakeWH(proxy->width(), proxy->height());
+
+        return domain.contains(kFullRect);
+    }
+
+    return false;
+}
+
 static bool can_ignore_rect(GrTexture* tex, const SkRect& domain) {
     // This logic is relying on the instantiated size of 'tex'. In the deferred world it
     // will have to change so this logic only fires for kExact texture proxies. This shouldn't
@@ -28,7 +41,8 @@
 }
 
 GrTextureDomain::GrTextureDomain(GrTexture* tex, const SkRect& domain, Mode mode, int index)
-    : fMode(mode), fIndex(index) {
+    : fMode(mode)
+    , fIndex(index) {
 
     if (kIgnore_Mode == fMode) {
         return;
@@ -54,6 +68,34 @@
     SkASSERT(fDomain.fTop <= fDomain.fBottom);
 }
 
+GrTextureDomain::GrTextureDomain(GrTextureProxy* proxy, const SkRect& domain, Mode mode, int index)
+    : fMode(mode)
+    , fIndex(index) {
+
+    if (kIgnore_Mode == fMode) {
+        return;
+    }
+
+    if (kClamp_Mode == mode && can_ignore_rect(proxy, domain)) {
+        fMode = kIgnore_Mode;
+        return;
+    }
+
+    const SkRect kFullRect = SkRect::MakeIWH(proxy->width(), proxy->height());
+
+    // We don't currently handle domains that are empty or don't intersect the texture.
+    // It is OK if the domain rect is a line or point, but it should not be inverted. We do not
+    // handle rects that do not intersect the [0..1]x[0..1] rect.
+    SkASSERT(domain.fLeft <= domain.fRight);
+    SkASSERT(domain.fTop <= domain.fBottom);
+    fDomain.fLeft = SkScalarPin(domain.fLeft, 0.0f, kFullRect.fRight);
+    fDomain.fRight = SkScalarPin(domain.fRight, fDomain.fLeft, kFullRect.fRight);
+    fDomain.fTop = SkScalarPin(domain.fTop, 0.0f, kFullRect.fBottom);
+    fDomain.fBottom = SkScalarPin(domain.fBottom, fDomain.fTop, kFullRect.fBottom);
+    SkASSERT(fDomain.fLeft <= fDomain.fRight);
+    SkASSERT(fDomain.fTop <= fDomain.fBottom);
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 void GrTextureDomain::GLDomain::sampleTexture(GrGLSLShaderBuilder* builder,
@@ -191,7 +233,6 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-
 sk_sp<GrFragmentProcessor> GrTextureDomainEffect::Make(GrTexture* texture,
                                                        sk_sp<GrColorSpaceXform> colorSpaceXform,
                                                        const SkMatrix& matrix,
@@ -209,8 +250,8 @@
 }
 
 inline GrFragmentProcessor::OptimizationFlags GrTextureDomainEffect::OptFlags(
-        GrTexture* texture, GrTextureDomain::Mode mode) {
-    if (mode == GrTextureDomain::kDecal_Mode || !GrPixelConfigIsOpaque(texture->config())) {
+        GrPixelConfig config, GrTextureDomain::Mode mode) {
+    if (mode == GrTextureDomain::kDecal_Mode || !GrPixelConfigIsOpaque(config)) {
         return GrFragmentProcessor::kModulatesInput_OptimizationFlag;
     } else {
         return GrFragmentProcessor::kModulatesInput_OptimizationFlag |
@@ -225,13 +266,46 @@
                                              GrTextureDomain::Mode mode,
                                              GrSamplerParams::FilterMode filterMode)
         : GrSingleTextureEffect(texture, std::move(colorSpaceXform), matrix, filterMode,
-                                OptFlags(texture, mode))
+                                OptFlags(texture->config(), mode))
         , fTextureDomain(texture, domain, mode) {
     SkASSERT(mode != GrTextureDomain::kRepeat_Mode ||
             filterMode == GrSamplerParams::kNone_FilterMode);
     this->initClassID<GrTextureDomainEffect>();
 }
 
+sk_sp<GrFragmentProcessor> GrTextureDomainEffect::Make(GrContext* context,
+                                                       sk_sp<GrTextureProxy> proxy,
+                                                       sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                                       const SkMatrix& matrix,
+                                                       const SkRect& domain,
+                                                       GrTextureDomain::Mode mode,
+                                                       GrSamplerParams::FilterMode filterMode) {
+    if (GrTextureDomain::kIgnore_Mode == mode ||
+        (GrTextureDomain::kClamp_Mode == mode && can_ignore_rect(proxy.get(), domain))) {
+        return GrSimpleTextureEffect::Make(context, std::move(proxy), std::move(colorSpaceXform),
+                                           matrix, filterMode);
+    } else {
+        return sk_sp<GrFragmentProcessor>(
+            new GrTextureDomainEffect(context, std::move(proxy), std::move(colorSpaceXform),
+                                      matrix, domain, mode, filterMode));
+    }
+}
+
+GrTextureDomainEffect::GrTextureDomainEffect(GrContext* context,
+                                             sk_sp<GrTextureProxy> proxy,
+                                             sk_sp<GrColorSpaceXform> colorSpaceXform,
+                                             const SkMatrix& matrix,
+                                             const SkRect& domain,
+                                             GrTextureDomain::Mode mode,
+                                             GrSamplerParams::FilterMode filterMode)
+    : GrSingleTextureEffect(context, OptFlags(proxy->config(), mode), proxy,
+                            std::move(colorSpaceXform), matrix, filterMode)
+    , fTextureDomain(proxy.get(), domain, mode) {
+    SkASSERT(mode != GrTextureDomain::kRepeat_Mode ||
+             filterMode == GrSamplerParams::kNone_FilterMode);
+    this->initClassID<GrTextureDomainEffect>();
+}
+
 void GrTextureDomainEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
                                                   GrProcessorKeyBuilder* b) const {
     b->add32(GrTextureDomain::GLDomain::DomainKey(fTextureDomain));
@@ -302,26 +376,27 @@
 GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrTextureDomainEffect);
 
 sk_sp<GrFragmentProcessor> GrTextureDomainEffect::TestCreate(GrProcessorTestData* d) {
-    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
-                                          GrProcessorUnitTest::kAlphaTextureIdx;
-    GrTexture* tex = d->fTextures[texIdx];
+    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
+                                        : GrProcessorUnitTest::kAlphaTextureIdx;
+    sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
     SkRect domain;
-    domain.fLeft = d->fRandom->nextRangeScalar(0, tex->width());
-    domain.fRight = d->fRandom->nextRangeScalar(domain.fLeft, tex->width());
-    domain.fTop = d->fRandom->nextRangeScalar(0, tex->height());
-    domain.fBottom = d->fRandom->nextRangeScalar(domain.fTop, tex->height());
+    domain.fLeft = d->fRandom->nextRangeScalar(0, proxy->width());
+    domain.fRight = d->fRandom->nextRangeScalar(domain.fLeft, proxy->width());
+    domain.fTop = d->fRandom->nextRangeScalar(0, proxy->height());
+    domain.fBottom = d->fRandom->nextRangeScalar(domain.fTop, proxy->height());
     GrTextureDomain::Mode mode =
         (GrTextureDomain::Mode) d->fRandom->nextULessThan(GrTextureDomain::kModeCount);
     const SkMatrix& matrix = GrTest::TestMatrix(d->fRandom);
     bool bilerp = mode != GrTextureDomain::kRepeat_Mode ? d->fRandom->nextBool() : false;
-    auto colorSpaceXform = GrTest::TestColorXform(d->fRandom);
-    return GrTextureDomainEffect::Make(
-        tex,
-        colorSpaceXform,
-        matrix,
-        domain,
-        mode,
-        bilerp ? GrSamplerParams::kBilerp_FilterMode : GrSamplerParams::kNone_FilterMode);
+    sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(d->fRandom);
+    return GrTextureDomainEffect::Make(d->context(),
+                                       std::move(proxy),
+                                       std::move(colorSpaceXform),
+                                       matrix,
+                                       domain,
+                                       mode,
+                                       bilerp ? GrSamplerParams::kBilerp_FilterMode
+                                              : GrSamplerParams::kNone_FilterMode);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -344,6 +419,30 @@
     this->initClassID<GrDeviceSpaceTextureDecalFragmentProcessor>();
 }
 
+sk_sp<GrFragmentProcessor> GrDeviceSpaceTextureDecalFragmentProcessor::Make(
+        GrContext* context,
+        sk_sp<GrTextureProxy> proxy,
+        const SkIRect& subset,
+        const SkIPoint& deviceSpaceOffset) {
+    return sk_sp<GrFragmentProcessor>(new GrDeviceSpaceTextureDecalFragmentProcessor(
+            context, std::move(proxy), subset, deviceSpaceOffset));
+}
+
+GrDeviceSpaceTextureDecalFragmentProcessor::GrDeviceSpaceTextureDecalFragmentProcessor(
+        GrContext* context,
+        sk_sp<GrTextureProxy> proxy,
+        const SkIRect& subset,
+        const SkIPoint& deviceSpaceOffset)
+        : INHERITED(kModulatesInput_OptimizationFlag)
+        , fTextureSampler(context->textureProvider(), proxy, GrSamplerParams::ClampNoFilter())
+        , fTextureDomain(proxy.get(), GrTextureDomain::MakeTexelDomain(subset),
+                         GrTextureDomain::kDecal_Mode) {
+    this->addTextureSampler(&fTextureSampler);
+    fDeviceSpaceOffset.fX = deviceSpaceOffset.fX - subset.fLeft;
+    fDeviceSpaceOffset.fY = deviceSpaceOffset.fY - subset.fTop;
+    this->initClassID<GrDeviceSpaceTextureDecalFragmentProcessor>();
+}
+
 GrGLSLFragmentProcessor* GrDeviceSpaceTextureDecalFragmentProcessor::onCreateGLSLInstance() const  {
     class GLSLProcessor : public GrGLSLFragmentProcessor {
     public:
@@ -420,13 +519,15 @@
         GrProcessorTestData* d) {
     int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
                                         : GrProcessorUnitTest::kAlphaTextureIdx;
+    sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
     SkIRect subset;
-    subset.fLeft = d->fRandom->nextULessThan(d->fTextures[texIdx]->width() - 1);
-    subset.fRight = d->fRandom->nextRangeU(subset.fLeft, d->fTextures[texIdx]->width());
-    subset.fTop = d->fRandom->nextULessThan(d->fTextures[texIdx]->height() - 1);
-    subset.fBottom = d->fRandom->nextRangeU(subset.fTop, d->fTextures[texIdx]->height());
+    subset.fLeft = d->fRandom->nextULessThan(proxy->width() - 1);
+    subset.fRight = d->fRandom->nextRangeU(subset.fLeft, proxy->width());
+    subset.fTop = d->fRandom->nextULessThan(proxy->height() - 1);
+    subset.fBottom = d->fRandom->nextRangeU(subset.fTop, proxy->height());
     SkIPoint pt;
     pt.fX = d->fRandom->nextULessThan(2048);
     pt.fY = d->fRandom->nextULessThan(2048);
-    return GrDeviceSpaceTextureDecalFragmentProcessor::Make(d->fTextures[texIdx], subset, pt);
+    return GrDeviceSpaceTextureDecalFragmentProcessor::Make(d->context(),
+                                                            std::move(proxy), subset, pt);
 }
diff --git a/src/gpu/effects/GrTextureDomain.h b/src/gpu/effects/GrTextureDomain.h
index 6758d90..fbc20f1 100644
--- a/src/gpu/effects/GrTextureDomain.h
+++ b/src/gpu/effects/GrTextureDomain.h
@@ -44,7 +44,8 @@
     static const int kModeCount = kLastMode + 1;
 
     static const GrTextureDomain& IgnoredDomain() {
-        static const GrTextureDomain gDomain(nullptr, SkRect::MakeEmpty(), kIgnore_Mode);
+        static const GrTextureDomain gDomain((GrTextureProxy*)nullptr,
+                                             SkRect::MakeEmpty(), kIgnore_Mode);
         return gDomain;
     }
 
@@ -54,6 +55,8 @@
      */
     GrTextureDomain(GrTexture*, const SkRect& domain, Mode, int index = -1);
 
+    GrTextureDomain(GrTextureProxy*, const SkRect& domain, Mode, int index = -1);
+
     const SkRect& domain() const { return fDomain; }
     Mode mode() const { return fMode; }
 
@@ -157,6 +160,14 @@
                                            GrTextureDomain::Mode,
                                            GrSamplerParams::FilterMode filterMode);
 
+    static sk_sp<GrFragmentProcessor> Make(GrContext*,
+                                           sk_sp<GrTextureProxy>,
+                                           sk_sp<GrColorSpaceXform>,
+                                           const SkMatrix&,
+                                           const SkRect& domain,
+                                           GrTextureDomain::Mode,
+                                           GrSamplerParams::FilterMode filterMode);
+
     const char* name() const override { return "TextureDomain"; }
 
     SkString dumpInfo() const override {
@@ -178,7 +189,15 @@
                           GrTextureDomain::Mode,
                           GrSamplerParams::FilterMode);
 
-    static OptimizationFlags OptFlags(GrTexture* texture, GrTextureDomain::Mode mode);
+    GrTextureDomainEffect(GrContext*,
+                          sk_sp<GrTextureProxy>,
+                          sk_sp<GrColorSpaceXform>,
+                          const SkMatrix&,
+                          const SkRect& domain,
+                          GrTextureDomain::Mode,
+                          GrSamplerParams::FilterMode);
+
+    static OptimizationFlags OptFlags(GrPixelConfig config, GrTextureDomain::Mode mode);
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
@@ -198,6 +217,9 @@
     static sk_sp<GrFragmentProcessor> Make(GrTexture*, const SkIRect& subset,
                                            const SkIPoint& deviceSpaceOffset);
 
+    static sk_sp<GrFragmentProcessor> Make(GrContext*, sk_sp<GrTextureProxy>, const SkIRect& subset,
+                                           const SkIPoint& deviceSpaceOffset);
+
     const char* name() const override { return "GrDeviceSpaceTextureDecalFragmentProcessor"; }
 
     SkString dumpInfo() const override {
@@ -217,6 +239,9 @@
 
     GrDeviceSpaceTextureDecalFragmentProcessor(GrTexture*, const SkIRect&, const SkIPoint&);
 
+    GrDeviceSpaceTextureDecalFragmentProcessor(GrContext*, sk_sp<GrTextureProxy>,
+                                               const SkIRect&, const SkIPoint&);
+
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
     // Since we always use decal mode, there is no need for key data.