Rework GrSamplerParams to be more compact and use its own wrap mode enum.

The main change is to make GrSamplerParams smaller by making its enums have byte-sized underlying types. The rest is cosmetic.

Change-Id: Ib71ea50612d24619a85e463826c6b8dfb9b445e3
Reviewed-on: https://skia-review.googlesource.com/43200
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/core/SkGpuBlurUtils.cpp b/src/core/SkGpuBlurUtils.cpp
index b328eea..3985713 100644
--- a/src/core/SkGpuBlurUtils.cpp
+++ b/src/core/SkGpuBlurUtils.cpp
@@ -256,7 +256,7 @@
 
     SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY));
 
-    // GrTextureDomainEffect does not support kRepeat_Mode with GrSamplerParams::FilterMode.
+    // GrTextureDomainEffect does not support kRepeat_Mode with GrSamplerState::Filter.
     GrTextureDomain::Mode modeForScaling =
             GrTextureDomain::kRepeat_Mode == mode ? GrTextureDomain::kDecal_Mode : mode;
     for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
@@ -284,14 +284,13 @@
                                                   SkMatrix::I(),
                                                   domain,
                                                   modeForScaling,
-                                                  GrSamplerParams::kBilerp_FilterMode);
+                                                  GrSamplerState::Filter::kBilerp);
             paint.addColorFragmentProcessor(std::move(fp));
             srcRect.offset(-srcOffset);
             srcOffset.set(0, 0);
         } else {
-            GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
-            paint.addColorTextureProcessor(std::move(srcProxy),
-                                           nullptr, SkMatrix::I(), params);
+            paint.addColorTextureProcessor(std::move(srcProxy), nullptr, SkMatrix::I(),
+                                           GrSamplerState::ClampBilerp());
         }
         paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
@@ -405,12 +404,12 @@
                                                   SkMatrix::I(),
                                                   domain,
                                                   modeForScaling,
-                                                  GrSamplerParams::kBilerp_FilterMode);
+                                                  GrSamplerState::Filter::kBilerp);
             paint.addColorFragmentProcessor(std::move(fp));
         } else {
             // FIXME:  this should be mitchell, not bilinear.
-            GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
-            paint.addColorTextureProcessor(std::move(srcProxy), nullptr, SkMatrix::I(), params);
+            paint.addColorTextureProcessor(std::move(srcProxy), nullptr, SkMatrix::I(),
+                                           GrSamplerState::ClampBilerp());
         }
         paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
diff --git a/src/effects/SkArithmeticImageFilter.cpp b/src/effects/SkArithmeticImageFilter.cpp
index 34df275..dde38b7 100644
--- a/src/effects/SkArithmeticImageFilter.cpp
+++ b/src/effects/SkArithmeticImageFilter.cpp
@@ -359,9 +359,9 @@
         sk_sp<GrColorSpaceXform> bgXform =
                 GrColorSpaceXform::Make(background->getColorSpace(), outputProperties.colorSpace());
         bgFP = GrTextureDomainEffect::Make(
-                std::move(backgroundProxy), std::move(bgXform),
-                backgroundMatrix, GrTextureDomain::MakeTexelDomain(background->subset()),
-                GrTextureDomain::kDecal_Mode, GrSamplerParams::kNone_FilterMode);
+                std::move(backgroundProxy), std::move(bgXform), backgroundMatrix,
+                GrTextureDomain::MakeTexelDomain(background->subset()),
+                GrTextureDomain::kDecal_Mode, GrSamplerState::Filter::kNearest);
     } else {
         bgFP = GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
                                            GrConstColorProcessor::kIgnore_InputMode);
@@ -375,7 +375,7 @@
         auto foregroundFP = GrTextureDomainEffect::Make(
                 std::move(foregroundProxy), std::move(fgXform), foregroundMatrix,
                 GrTextureDomain::MakeTexelDomain(foreground->subset()),
-                GrTextureDomain::kDecal_Mode, GrSamplerParams::kNone_FilterMode);
+                GrTextureDomain::kDecal_Mode, GrSamplerState::Filter::kNearest);
         paint.addColorFragmentProcessor(std::move(foregroundFP));
 
         std::unique_ptr<GrFragmentProcessor> xferFP =
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index ba01969..215444b 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -99,7 +99,7 @@
                       float xInvInset,
                       float yInvInset)
             : INHERITED{ModulateByConfigOptimizationFlags(proxy->config())}
-            // TODO: no GrSamplerParams::kBilerp_FilterMode?
+            // TODO: no GrSamplerState::Filter::kBilerp?
             , fCoordTransform(proxy.get())
             , fTextureSampler(std::move(proxy))
             , fColorSpaceXform(std::move(colorSpaceXform))
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp
index e1033cf..f7ce0a3 100644
--- a/src/effects/SkXfermodeImageFilter.cpp
+++ b/src/effects/SkXfermodeImageFilter.cpp
@@ -251,12 +251,10 @@
                                                 -SkIntToScalar(backgroundOffset.fY));
         sk_sp<GrColorSpaceXform> bgXform = GrColorSpaceXform::Make(background->getColorSpace(),
                                                                    outputProperties.colorSpace());
-        bgFP = GrTextureDomainEffect::Make(
-                            std::move(backgroundProxy),
-                            std::move(bgXform), bgMatrix,
-                            GrTextureDomain::MakeTexelDomain(background->subset()),
-                            GrTextureDomain::kDecal_Mode,
-                            GrSamplerParams::kNone_FilterMode);
+        bgFP = GrTextureDomainEffect::Make(std::move(backgroundProxy), std::move(bgXform), bgMatrix,
+                                           GrTextureDomain::MakeTexelDomain(background->subset()),
+                                           GrTextureDomain::kDecal_Mode,
+                                           GrSamplerState::Filter::kNearest);
     } else {
         bgFP = GrConstColorProcessor::Make(GrColor4f::TransparentBlack(),
                                            GrConstColorProcessor::kIgnore_InputMode);
@@ -270,7 +268,7 @@
         auto foregroundFP = GrTextureDomainEffect::Make(
                 std::move(foregroundProxy), std::move(fgXform), fgMatrix,
                 GrTextureDomain::MakeTexelDomain(foreground->subset()),
-                GrTextureDomain::kDecal_Mode, GrSamplerParams::kNone_FilterMode);
+                GrTextureDomain::kDecal_Mode, GrSamplerState::Filter::kNearest);
         paint.addColorFragmentProcessor(std::move(foregroundFP));
 
         std::unique_ptr<GrFragmentProcessor> xferFP = this->makeFGFrag(std::move(bgFP));
diff --git a/src/gpu/GrBitmapTextureMaker.h b/src/gpu/GrBitmapTextureMaker.h
index 419649c..f945cbc 100644
--- a/src/gpu/GrBitmapTextureMaker.h
+++ b/src/gpu/GrBitmapTextureMaker.h
@@ -9,6 +9,7 @@
 #define GrBitmapTextureMaker_DEFINED
 
 #include "GrTextureMaker.h"
+#include "SkBitmap.h"
 
 /** This class manages the conversion of SW-backed bitmaps to GrTextures. If the input bitmap is
     non-volatile the texture is cached using a key created from the pixels' image id and the
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index f42e538..72179bf 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -45,25 +45,25 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 bool GrGpu::isACopyNeededForTextureParams(int width, int height,
-                                          const GrSamplerParams& textureParams,
+                                          const GrSamplerState& textureParams,
                                           GrTextureProducer::CopyParams* copyParams,
                                           SkScalar scaleAdjust[2]) const {
     const GrCaps& caps = *this->caps();
-    if (textureParams.isTiled() && !caps.npotTextureTileSupport() &&
+    if (textureParams.isRepeated() && !caps.npotTextureTileSupport() &&
         (!SkIsPow2(width) || !SkIsPow2(height))) {
         SkASSERT(scaleAdjust);
         copyParams->fWidth = GrNextPow2(width);
         copyParams->fHeight = GrNextPow2(height);
         scaleAdjust[0] = ((SkScalar) copyParams->fWidth) / width;
         scaleAdjust[1] = ((SkScalar) copyParams->fHeight) / height;
-        switch (textureParams.filterMode()) {
-            case GrSamplerParams::kNone_FilterMode:
-                copyParams->fFilter = GrSamplerParams::kNone_FilterMode;
+        switch (textureParams.filter()) {
+            case GrSamplerState::Filter::kNearest:
+                copyParams->fFilter = GrSamplerState::Filter::kNearest;
                 break;
-            case GrSamplerParams::kBilerp_FilterMode:
-            case GrSamplerParams::kMipMap_FilterMode:
+            case GrSamplerState::Filter::kBilerp:
+            case GrSamplerState::Filter::kMipMap:
                 // We are only ever scaling up so no reason to ever indicate kMipMap.
-                copyParams->fFilter = GrSamplerParams::kBilerp_FilterMode;
+                copyParams->fFilter = GrSamplerState::Filter::kBilerp;
                 break;
         }
         return true;
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index a0a552c..ef99a48 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -486,9 +486,9 @@
     virtual void clearStencil(GrRenderTarget* target, int clearValue) = 0;
 
     // Determines whether a texture will need to be rescaled in order to be used with the
-    // GrSamplerParams. This variation is called when the caller will create a new texture using the
+    // GrSamplerState. This variation is called when the caller will create a new texture using the
     // resource provider from a non-texture src (cpu-backed image, ...).
-    bool isACopyNeededForTextureParams(int width, int height, const GrSamplerParams&,
+    bool isACopyNeededForTextureParams(int width, int height, const GrSamplerState&,
                                        GrTextureProducer::CopyParams*,
                                        SkScalar scaleAdjust[2]) const;
 
@@ -496,7 +496,7 @@
     // original texture but rather was handed the original texture. It adds additional checks
     // relevant to original textures that were created external to Skia via
     // GrResourceProvider::wrap methods.
-    bool isACopyNeededForTextureParams(GrTextureProxy* proxy, const GrSamplerParams& params,
+    bool isACopyNeededForTextureParams(GrTextureProxy* proxy, const GrSamplerState& params,
                                        GrTextureProducer::CopyParams* copyParams,
                                        SkScalar scaleAdjust[2]) const {
         if (this->isACopyNeededForTextureParams(proxy->width(), proxy->height(), params,
@@ -569,7 +569,7 @@
         return nullptr;
     }
 
-    virtual bool onIsACopyNeededForTextureParams(GrTextureProxy* proxy, const GrSamplerParams&,
+    virtual bool onIsACopyNeededForTextureParams(GrTextureProxy* proxy, const GrSamplerState&,
                                                  GrTextureProducer::CopyParams*,
                                                  SkScalar scaleAdjust[2]) const {
         return false;
diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp
index 139a2cc..0d52a5d 100644
--- a/src/gpu/GrPaint.cpp
+++ b/src/gpu/GrPaint.cpp
@@ -48,10 +48,10 @@
 void GrPaint::addColorTextureProcessor(sk_sp<GrTextureProxy> proxy,
                                        sk_sp<GrColorSpaceXform> colorSpaceXform,
                                        const SkMatrix& matrix,
-                                       const GrSamplerParams& params) {
+                                       const GrSamplerState& samplerState) {
     this->addColorFragmentProcessor(GrSimpleTextureEffect::Make(std::move(proxy),
                                                                 std::move(colorSpaceXform),
-                                                                matrix, params));
+                                                                matrix, samplerState));
 }
 
 void GrPaint::addCoverageTextureProcessor(sk_sp<GrTextureProxy> proxy,
@@ -62,7 +62,7 @@
 
 void GrPaint::addCoverageTextureProcessor(sk_sp<GrTextureProxy> proxy,
                                           const SkMatrix& matrix,
-                                          const GrSamplerParams& params) {
+                                          const GrSamplerState& params) {
     this->addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(std::move(proxy),
                                                                    nullptr, matrix, params));
 }
diff --git a/src/gpu/GrPaint.h b/src/gpu/GrPaint.h
index ae19cad..72f3204 100644
--- a/src/gpu/GrPaint.h
+++ b/src/gpu/GrPaint.h
@@ -112,13 +112,11 @@
      */
     void addColorTextureProcessor(sk_sp<GrTextureProxy>,
                                   sk_sp<GrColorSpaceXform>, const SkMatrix&);
-    void addColorTextureProcessor(sk_sp<GrTextureProxy>,
-                                  sk_sp<GrColorSpaceXform>, const SkMatrix&,
-                                  const GrSamplerParams&);
+    void addColorTextureProcessor(sk_sp<GrTextureProxy>, sk_sp<GrColorSpaceXform>, const SkMatrix&,
+                                  const GrSamplerState&);
 
     void addCoverageTextureProcessor(sk_sp<GrTextureProxy>, const SkMatrix&);
-    void addCoverageTextureProcessor(sk_sp<GrTextureProxy>,
-                                     const SkMatrix&, const GrSamplerParams&);
+    void addCoverageTextureProcessor(sk_sp<GrTextureProxy>, const SkMatrix&, const GrSamplerState&);
 
     int numColorFragmentProcessors() const { return fColorFragmentProcessors.count(); }
     int numCoverageFragmentProcessors() const { return fCoverageFragmentProcessors.count(); }
diff --git a/src/gpu/GrPathRendering.cpp b/src/gpu/GrPathRendering.cpp
index 0e947d5..f0d5f90 100644
--- a/src/gpu/GrPathRendering.cpp
+++ b/src/gpu/GrPathRendering.cpp
@@ -8,6 +8,7 @@
 #include "GrGpu.h"
 #include "GrPathRendering.h"
 #include "SkDescriptor.h"
+#include "SkScalerContext.h"
 #include "SkGlyph.h"
 #include "SkMatrix.h"
 #include "SkTypeface.h"
diff --git a/src/gpu/GrPathRendering.h b/src/gpu/GrPathRendering.h
index bc122de..c32e789 100644
--- a/src/gpu/GrPathRendering.h
+++ b/src/gpu/GrPathRendering.h
@@ -12,12 +12,13 @@
 #include "GrPathRange.h"
 #include "GrPipeline.h"
 
-class SkDescriptor;
-class SkTypeface;
 class GrGpu;
 class GrPath;
 class GrStencilSettings;
 class GrStyle;
+struct SkScalerContextEffects;
+class SkDescriptor;
+class SkTypeface;
 
 /**
  * Abstract class wrapping HW path rendering API.
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index 148c011..7ea5972 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -9,7 +9,7 @@
 #include "GrContext.h"
 #include "GrGeometryProcessor.h"
 #include "GrMemoryPool.h"
-#include "GrSamplerParams.h"
+#include "GrSamplerState.h"
 #include "GrTextureProxy.h"
 #include "GrXferProcessor.h"
 #include "SkSpinlock.h"
@@ -220,33 +220,33 @@
 GrResourceIOProcessor::TextureSampler::TextureSampler() {}
 
 GrResourceIOProcessor::TextureSampler::TextureSampler(sk_sp<GrTextureProxy> proxy,
-                                                      const GrSamplerParams& params) {
-    this->reset(std::move(proxy), params);
+                                                      const GrSamplerState& samplerState) {
+    this->reset(std::move(proxy), samplerState);
 }
 
 GrResourceIOProcessor::TextureSampler::TextureSampler(sk_sp<GrTextureProxy> proxy,
-                                                      GrSamplerParams::FilterMode filterMode,
-                                                      SkShader::TileMode tileXAndY,
+                                                      GrSamplerState::Filter filterMode,
+                                                      GrSamplerState::WrapMode wrapXAndY,
                                                       GrShaderFlags visibility) {
-    this->reset(std::move(proxy), filterMode, tileXAndY, visibility);
+    this->reset(std::move(proxy), filterMode, wrapXAndY, visibility);
 }
 
 void GrResourceIOProcessor::TextureSampler::reset(sk_sp<GrTextureProxy> proxy,
-                                                  const GrSamplerParams& params,
+                                                  const GrSamplerState& samplerState,
                                                   GrShaderFlags visibility) {
-    fParams = params;
+    fSamplerState = samplerState;
     fProxyRef.setProxy(std::move(proxy), kRead_GrIOType);
-    fParams.setFilterMode(SkTMin(params.filterMode(), this->proxy()->highestFilterMode()));
+    fSamplerState.setFilterMode(SkTMin(samplerState.filter(), this->proxy()->highestFilterMode()));
     fVisibility = visibility;
 }
 
 void GrResourceIOProcessor::TextureSampler::reset(sk_sp<GrTextureProxy> proxy,
-                                                  GrSamplerParams::FilterMode filterMode,
-                                                  SkShader::TileMode tileXAndY,
+                                                  GrSamplerState::Filter filterMode,
+                                                  GrSamplerState::WrapMode wrapXAndY,
                                                   GrShaderFlags visibility) {
     fProxyRef.setProxy(std::move(proxy), kRead_GrIOType);
     filterMode = SkTMin(filterMode, this->proxy()->highestFilterMode());
-    fParams.reset(tileXAndY, filterMode);
+    fSamplerState = GrSamplerState(wrapXAndY, filterMode);
     fVisibility = visibility;
 }
 
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index 721f7c2..de0598f 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -14,7 +14,7 @@
 #include "GrGpuResourceRef.h"
 #include "GrProcessorUnitTest.h"
 #include "GrProgramElement.h"
-#include "GrSamplerParams.h"
+#include "GrSamplerState.h"
 #include "GrShaderVar.h"
 #include "GrSurfaceProxyPriv.h"
 #include "GrTextureProxy.h"
@@ -209,7 +209,7 @@
 
 /**
  * Used to represent a texture that is required by a GrResourceIOProcessor. It holds a GrTexture
- * along with an associated GrSamplerParams. TextureSamplers don't perform any coord manipulation to
+ * along with an associated GrSamplerState. TextureSamplers don't perform any coord manipulation to
  * account for texture origin.
  */
 class GrResourceIOProcessor::TextureSampler {
@@ -225,29 +225,28 @@
      */
     explicit TextureSampler(const TextureSampler& that)
             : fProxyRef(sk_ref_sp(that.fProxyRef.get()), that.fProxyRef.ioType())
-            , fParams(that.fParams)
+            , fSamplerState(that.fSamplerState)
             , fVisibility(that.fVisibility) {}
 
-    TextureSampler(sk_sp<GrTextureProxy>, const GrSamplerParams&);
+    TextureSampler(sk_sp<GrTextureProxy>, const GrSamplerState&);
 
     explicit TextureSampler(sk_sp<GrTextureProxy>,
-                            GrSamplerParams::FilterMode = GrSamplerParams::kNone_FilterMode,
-                            SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode,
+                            GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
+                            GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp,
                             GrShaderFlags visibility = kFragment_GrShaderFlag);
 
     TextureSampler& operator=(const TextureSampler&) = delete;
 
-    void reset(sk_sp<GrTextureProxy>, const GrSamplerParams&,
+    void reset(sk_sp<GrTextureProxy>, const GrSamplerState&,
                GrShaderFlags visibility = kFragment_GrShaderFlag);
     void reset(sk_sp<GrTextureProxy>,
-               GrSamplerParams::FilterMode = GrSamplerParams::kNone_FilterMode,
-               SkShader::TileMode tileXAndY = SkShader::kClamp_TileMode,
+               GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
+               GrSamplerState::WrapMode wrapXAndY = GrSamplerState::WrapMode::kClamp,
                GrShaderFlags visibility = kFragment_GrShaderFlag);
 
     bool operator==(const TextureSampler& that) const {
         return this->proxy()->underlyingUniqueID() == that.proxy()->underlyingUniqueID() &&
-               fParams == that.fParams &&
-               fVisibility == that.fVisibility;
+               fSamplerState == that.fSamplerState && fVisibility == that.fVisibility;
     }
 
     bool operator!=(const TextureSampler& other) const { return !(*this == other); }
@@ -265,7 +264,7 @@
 
     GrTextureProxy* proxy() const { return fProxyRef.get()->asTextureProxy(); }
     GrShaderFlags visibility() const { return fVisibility; }
-    const GrSamplerParams& params() const { return fParams; }
+    const GrSamplerState& samplerState() const { return fSamplerState; }
 
     bool isInitialized() const { return SkToBool(fProxyRef.get()); }
     /**
@@ -274,9 +273,9 @@
     const GrSurfaceProxyRef* programProxy() const { return &fProxyRef; }
 
 private:
-    GrSurfaceProxyRef               fProxyRef;
-    GrSamplerParams                 fParams;
-    GrShaderFlags                   fVisibility;
+    GrSurfaceProxyRef fProxyRef;
+    GrSamplerState fSamplerState;
+    GrShaderFlags fVisibility;
 };
 
 /**
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 9d8f69f..8828f27 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -779,7 +779,7 @@
 }
 
 void GrRenderTargetContext::drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
-                                              GrSamplerParams::FilterMode filter, GrColor color,
+                                              GrSamplerState::Filter filter, GrColor color,
                                               const SkRect& srcRect, const SkRect& dstRect,
                                               const SkMatrix& viewMatrix,
                                               sk_sp<GrColorSpaceXform> colorSpaceXform) {
@@ -788,8 +788,8 @@
     SkDEBUGCODE(this->validate();)
     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureAffine", fContext);
     SkASSERT(!viewMatrix.hasPerspective());
-    if (filter != GrSamplerParams::kNone_FilterMode && !must_filter(srcRect, dstRect, viewMatrix)) {
-        filter = GrSamplerParams::kNone_FilterMode;
+    if (filter != GrSamplerState::Filter::kNearest && !must_filter(srcRect, dstRect, viewMatrix)) {
+        filter = GrSamplerState::Filter::kNearest;
     }
     SkRect clippedDstRect = dstRect;
     SkRect clippedSrcRect = srcRect;
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 084e153..a37ad38 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -141,7 +141,7 @@
      * device space. The edges of the rendered rectangle are not antialiased. This asserts that the
      * view matrix does not have perspective.
      */
-    void drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy>, GrSamplerParams::FilterMode,
+    void drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy>, GrSamplerState::Filter,
                            GrColor, const SkRect& srcRect, const SkRect& dstRect,
                            const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform>);
 
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index 3070d4d..5780cee 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -151,7 +151,7 @@
                                               SkIntToScalar(-textureOriginInDeviceSpace.fY));
     maskMatrix.preConcat(viewMatrix);
     paint.addCoverageFragmentProcessor(GrSimpleTextureEffect::Make(
-                std::move(proxy), nullptr, maskMatrix, GrSamplerParams::kNone_FilterMode));
+            std::move(proxy), nullptr, maskMatrix, GrSamplerState::Filter::kNearest));
     DrawNonAARect(renderTargetContext, std::move(paint), userStencilSettings, clip, SkMatrix::I(),
                   dstRect, invert);
 }
diff --git a/src/gpu/GrTestUtils.cpp b/src/gpu/GrTestUtils.cpp
index aad927a..e4516dd 100644
--- a/src/gpu/GrTestUtils.cpp
+++ b/src/gpu/GrTestUtils.cpp
@@ -106,6 +106,15 @@
 const SkMatrix& TestMatrixInvertible(SkRandom* random) { return test_matrix(random, true, false); }
 const SkMatrix& TestMatrixPerspective(SkRandom* random) { return test_matrix(random, false, true); }
 
+void TestWrapModes(SkRandom* random, GrSamplerState::WrapMode wrapModes[2]) {
+    static const GrSamplerState::WrapMode kWrapModes[] = {
+            GrSamplerState::WrapMode::kClamp,
+            GrSamplerState::WrapMode::kRepeat,
+            GrSamplerState::WrapMode::kMirrorRepeat,
+    };
+    wrapModes[0] = kWrapModes[random->nextULessThan(SK_ARRAY_COUNT(kWrapModes))];
+    wrapModes[1] = kWrapModes[random->nextULessThan(SK_ARRAY_COUNT(kWrapModes))];
+}
 const SkRect& TestRect(SkRandom* random) {
     static SkRect gRects[7];
     static bool gOnce;
diff --git a/src/gpu/GrTestUtils.h b/src/gpu/GrTestUtils.h
index fd9398d..0bbcf30 100644
--- a/src/gpu/GrTestUtils.h
+++ b/src/gpu/GrTestUtils.h
@@ -12,13 +12,14 @@
 
 #if GR_TEST_UTILS
 
+#include "../private/SkTemplates.h"
 #include "GrColor.h"
 #include "GrColorSpaceXform.h"
+#include "GrSamplerState.h"
 #include "SkPathEffect.h"
 #include "SkRandom.h"
 #include "SkShaderBase.h"
 #include "SkStrokeRec.h"
-#include "../private/SkTemplates.h"
 
 struct GrProcessorTestData;
 class GrStyle;
@@ -36,6 +37,7 @@
 const SkMatrix& TestMatrixRectStaysRect(SkRandom*);
 const SkMatrix& TestMatrixInvertible(SkRandom*);
 const SkMatrix& TestMatrixPerspective(SkRandom*);
+void TestWrapModes(SkRandom*, GrSamplerState::WrapMode[2]);
 const SkRect& TestRect(SkRandom*);
 const SkRect& TestSquare(SkRandom*);
 const SkRRect& TestRRectSimple(SkRandom*);
diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp
index c702280..c94c7e0 100644
--- a/src/gpu/GrTexture.cpp
+++ b/src/gpu/GrTexture.cpp
@@ -41,12 +41,12 @@
 
 /////////////////////////////////////////////////////////////////////////////
 GrTexture::GrTexture(GrGpu* gpu, const GrSurfaceDesc& desc, GrSLType samplerType,
-                     GrSamplerParams::FilterMode highestFilterMode, bool wasMipMapDataProvided)
-    : INHERITED(gpu, desc)
-    , fSamplerType(samplerType)
-    , fHighestFilterMode(highestFilterMode)
-    // Mip color mode is explicitly set after creation via GrTexturePriv
-    , fMipColorMode(SkDestinationSurfaceColorMode::kLegacy) {
+                     GrSamplerState::Filter highestFilterMode, bool wasMipMapDataProvided)
+        : INHERITED(gpu, desc)
+        , fSamplerType(samplerType)
+        , fHighestFilterMode(highestFilterMode)
+        // Mip color mode is explicitly set after creation via GrTexturePriv
+        , fMipColorMode(SkDestinationSurfaceColorMode::kLegacy) {
     if (wasMipMapDataProvided) {
         fMipMapsStatus = kValid_MipMapsStatus;
         fMaxMipMapLevel = SkMipMap::ComputeLevelCount(this->width(), this->height());
diff --git a/src/gpu/GrTextureAdjuster.cpp b/src/gpu/GrTextureAdjuster.cpp
index 546ea67..9c34cca 100644
--- a/src/gpu/GrTextureAdjuster.cpp
+++ b/src/gpu/GrTextureAdjuster.cpp
@@ -67,10 +67,9 @@
     return copy;
 }
 
-sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxySafeForParams(
-                                                                 const GrSamplerParams& params,
-                                                                 SkIPoint* outOffset,
-                                                                 SkScalar scaleAdjust[2]) {
+sk_sp<GrTextureProxy> GrTextureAdjuster::refTextureProxySafeForParams(const GrSamplerState& params,
+                                                                      SkIPoint* outOffset,
+                                                                      SkScalar scaleAdjust[2]) {
     sk_sp<GrTextureProxy> proxy = this->originalProxyRef();
     CopyParams copyParams;
     const SkIRect* contentArea = this->contentAreaOrNull();
@@ -80,12 +79,12 @@
         return nullptr;
     }
 
-    if (contentArea && GrSamplerParams::kMipMap_FilterMode == params.filterMode()) {
+    if (contentArea && GrSamplerState::Filter::kMipMap == params.filter()) {
         // If we generate a MIP chain for texture it will read pixel values from outside the content
         // area.
         copyParams.fWidth = contentArea->width();
         copyParams.fHeight = contentArea->height();
-        copyParams.fFilter = GrSamplerParams::kBilerp_FilterMode;
+        copyParams.fFilter = GrSamplerState::Filter::kBilerp;
     } else if (!fContext->getGpu()->isACopyNeededForTextureParams(proxy.get(), params, &copyParams,
                                                                   scaleAdjust)) {
         if (outOffset) {
@@ -110,7 +109,7 @@
         const SkRect& origConstraintRect,
         FilterConstraint filterConstraint,
         bool coordsLimitedToConstraintRect,
-        const GrSamplerParams::FilterMode* filterOrNullForBicubic,
+        const GrSamplerState::Filter* filterOrNullForBicubic,
         SkColorSpace* dstColorSpace) {
     SkMatrix textureMatrix = origTextureMatrix;
     const SkIRect* contentArea = this->contentAreaOrNull();
@@ -125,12 +124,13 @@
     }
 
     SkRect domain;
-    GrSamplerParams params;
+    GrSamplerState samplerState;
     if (filterOrNullForBicubic) {
-        params.setFilterMode(*filterOrNullForBicubic);
+        samplerState.setFilterMode(*filterOrNullForBicubic);
     }
     SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
-    sk_sp<GrTextureProxy> proxy(this->refTextureProxySafeForParams(params, nullptr, scaleAdjust));
+    sk_sp<GrTextureProxy> proxy(
+            this->refTextureProxySafeForParams(samplerState, nullptr, scaleAdjust));
     if (!proxy) {
         return nullptr;
     }
@@ -153,8 +153,8 @@
 
         // We only expect MIP maps to require a tight copy.
         SkASSERT(filterOrNullForBicubic &&
-                 GrSamplerParams::kMipMap_FilterMode == *filterOrNullForBicubic);
-        static const GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode;
+                 GrSamplerState::Filter::kMipMap == *filterOrNullForBicubic);
+        static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
         domainMode =
             DetermineDomainMode(*constraintRect, filterConstraint, coordsLimitedToConstraintRect,
                                 proxy.get(),
diff --git a/src/gpu/GrTextureAdjuster.h b/src/gpu/GrTextureAdjuster.h
index fad533f..cf84fe0 100644
--- a/src/gpu/GrTextureAdjuster.h
+++ b/src/gpu/GrTextureAdjuster.h
@@ -24,7 +24,7 @@
         outOffset will be the top-left corner of the subset if a copy is not made. Otherwise,
         the copy will be tight to the contents and outOffset will be (0, 0). If the copy's size
         does not match subset's dimensions then the contents are scaled to fit the copy.*/
-    sk_sp<GrTextureProxy> refTextureProxySafeForParams(const GrSamplerParams&, SkIPoint* outOffset,
+    sk_sp<GrTextureProxy> refTextureProxySafeForParams(const GrSamplerState&, SkIPoint* outOffset,
                                                        SkScalar scaleAdjust[2]);
 
     std::unique_ptr<GrFragmentProcessor> createFragmentProcessor(
@@ -32,7 +32,7 @@
             const SkRect& constraintRect,
             FilterConstraint,
             bool coordsLimitedToConstraintRect,
-            const GrSamplerParams::FilterMode* filterOrNullForBicubic,
+            const GrSamplerState::Filter* filterOrNullForBicubic,
             SkColorSpace* dstColorSpace) override;
 
     // We do not ref the texture nor the colorspace, so the caller must keep them in scope while
diff --git a/src/gpu/GrTextureMaker.cpp b/src/gpu/GrTextureMaker.cpp
index 7e257d8..efcf755 100644
--- a/src/gpu/GrTextureMaker.cpp
+++ b/src/gpu/GrTextureMaker.cpp
@@ -11,12 +11,12 @@
 #include "GrGpu.h"
 #include "GrResourceProvider.h"
 
-sk_sp<GrTextureProxy> GrTextureMaker::refTextureProxyForParams(const GrSamplerParams& params,
+sk_sp<GrTextureProxy> GrTextureMaker::refTextureProxyForParams(const GrSamplerState& params,
                                                                SkColorSpace* dstColorSpace,
                                                                sk_sp<SkColorSpace>* texColorSpace,
                                                                SkScalar scaleAdjust[2]) {
     CopyParams copyParams;
-    bool willBeMipped = params.filterMode() == GrSamplerParams::kMipMap_FilterMode;
+    bool willBeMipped = params.filter() == GrSamplerState::Filter::kMipMap;
 
     if (!fContext->caps()->mipMapSupport()) {
         willBeMipped = false;
@@ -81,32 +81,31 @@
         const SkRect& constraintRect,
         FilterConstraint filterConstraint,
         bool coordsLimitedToConstraintRect,
-        const GrSamplerParams::FilterMode* filterOrNullForBicubic,
+        const GrSamplerState::Filter* filterOrNullForBicubic,
         SkColorSpace* dstColorSpace) {
-    const GrSamplerParams::FilterMode* fmForDetermineDomain = filterOrNullForBicubic;
-    if (filterOrNullForBicubic && GrSamplerParams::kMipMap_FilterMode == *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 GrSamplerParams::FilterMode kBilerp = GrSamplerParams::kBilerp_FilterMode;
+        static const GrSamplerState::Filter kBilerp = GrSamplerState::Filter::kBilerp;
         fmForDetermineDomain = &kBilerp;
     }
 
-    GrSamplerParams params;
+    GrSamplerState samplerState;
     if (filterOrNullForBicubic) {
-        params.reset(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
+        samplerState = GrSamplerState(GrSamplerState::WrapMode::kClamp, *filterOrNullForBicubic);
     } else {
         // Bicubic doesn't use filtering for it's texture accesses.
-        params.reset(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
+        samplerState = GrSamplerState::ClampNearest();
     }
     sk_sp<SkColorSpace> texColorSpace;
     SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
-    sk_sp<GrTextureProxy> proxy(this->refTextureProxyForParams(params, dstColorSpace,
-                                                               &texColorSpace,
-                                                               scaleAdjust));
+    sk_sp<GrTextureProxy> proxy(this->refTextureProxyForParams(samplerState, dstColorSpace,
+                                                               &texColorSpace, scaleAdjust));
     if (!proxy) {
         return nullptr;
     }
diff --git a/src/gpu/GrTextureMaker.h b/src/gpu/GrTextureMaker.h
index 5055a8a..b482170 100644
--- a/src/gpu/GrTextureMaker.h
+++ b/src/gpu/GrTextureMaker.h
@@ -25,7 +25,7 @@
      *  in order to correct the absolute texture coordinates.
      *  Places the color space of the texture in (*texColorSpace).
      */
-    sk_sp<GrTextureProxy> refTextureProxyForParams(const GrSamplerParams&,
+    sk_sp<GrTextureProxy> refTextureProxyForParams(const GrSamplerState&,
                                                    SkColorSpace* dstColorSpace,
                                                    sk_sp<SkColorSpace>* texColorSpace,
                                                    SkScalar scaleAdjust[2]);
@@ -35,7 +35,7 @@
             const SkRect& constraintRect,
             FilterConstraint filterConstraint,
             bool coordsLimitedToConstraintRect,
-            const GrSamplerParams::FilterMode* filterOrNullForBicubic,
+            const GrSamplerState::Filter* filterOrNullForBicubic,
             SkColorSpace* dstColorSpace) override;
 
 protected:
diff --git a/src/gpu/GrTexturePriv.h b/src/gpu/GrTexturePriv.h
index 1331e72..e3af9e3 100644
--- a/src/gpu/GrTexturePriv.h
+++ b/src/gpu/GrTexturePriv.h
@@ -48,7 +48,7 @@
     GrSLType samplerType() const { return fTexture->fSamplerType; }
 
     /** The filter used is clamped to this value in GrProcessor::TextureSampler. */
-    GrSamplerParams::FilterMode highestFilterMode() const { return fTexture->fHighestFilterMode; }
+    GrSamplerState::Filter highestFilterMode() const { return fTexture->fHighestFilterMode; }
 
     void setMipColorMode(SkDestinationSurfaceColorMode colorMode) const {
         fTexture->fMipColorMode = colorMode;
diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp
index 9273223..91e196d 100644
--- a/src/gpu/GrTextureProducer.cpp
+++ b/src/gpu/GrTextureProducer.cpp
@@ -41,7 +41,7 @@
     }
 
     bool needsDomain = false;
-    if (copyParams.fFilter != GrSamplerParams::kNone_FilterMode) {
+    if (copyParams.fFilter != GrSamplerState::Filter::kNearest) {
         bool resizing = localRect.width()  != dstRect.width() ||
                         localRect.height() != dstRect.height();
 
@@ -56,13 +56,13 @@
         const SkRect domain = localRect.makeInset(0.5f, 0.5f);
         // This would cause us to read values from outside the subset. Surely, the caller knows
         // better!
-        SkASSERT(copyParams.fFilter != GrSamplerParams::kMipMap_FilterMode);
+        SkASSERT(copyParams.fFilter != GrSamplerState::Filter::kMipMap);
         paint.addColorFragmentProcessor(
             GrTextureDomainEffect::Make(std::move(inputProxy), nullptr, SkMatrix::I(),
                                         domain, GrTextureDomain::kClamp_Mode, copyParams.fFilter));
     } else {
-        GrSamplerParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
-        paint.addColorTextureProcessor(std::move(inputProxy), nullptr, SkMatrix::I(), params);
+        GrSamplerState samplerState(GrSamplerState::WrapMode::kClamp, copyParams.fFilter);
+        paint.addColorTextureProcessor(std::move(inputProxy), nullptr, SkMatrix::I(), samplerState);
     }
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
@@ -84,13 +84,13 @@
  *  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,
-                                GrTextureProxy* proxy,
-                                const SkIRect* contentRect,
-                                const GrSamplerParams::FilterMode* filterModeOrNullForBicubic,
-                                SkRect* domainRect) {
+        const SkRect& constraintRect,
+        FilterConstraint filterConstraint,
+        bool coordsLimitedToConstraintRect,
+        GrTextureProxy* proxy,
+        const SkIRect* contentRect,
+        const GrSamplerState::Filter* filterModeOrNullForBicubic,
+        SkRect* domainRect) {
     const SkIRect proxyBounds = SkIRect::MakeWH(proxy->width(), proxy->height());
 
     SkASSERT(proxyBounds.contains(constraintRect));
@@ -124,17 +124,17 @@
     SkScalar filterHalfWidth = 0.f;
     if (filterModeOrNullForBicubic) {
         switch (*filterModeOrNullForBicubic) {
-            case GrSamplerParams::kNone_FilterMode:
+            case GrSamplerState::Filter::kNearest:
                 if (coordsLimitedToConstraintRect) {
                     return kNoDomain_DomainMode;
                 } else {
                     filterHalfWidth = 0.f;
                 }
                 break;
-            case GrSamplerParams::kBilerp_FilterMode:
+            case GrSamplerState::Filter::kBilerp:
                 filterHalfWidth = .5f;
                 break;
-            case GrSamplerParams::kMipMap_FilterMode:
+            case GrSamplerState::Filter::kMipMap:
                 if (restrictFilterToRect || contentRect) {
                     // No domain can save us here.
                     return kTightCopy_DomainMode;
@@ -224,7 +224,7 @@
         const SkMatrix& textureMatrix,
         DomainMode domainMode,
         const SkRect& domain,
-        const GrSamplerParams::FilterMode* filterOrNullForBicubic) {
+        const GrSamplerState::Filter* filterOrNullForBicubic) {
     SkASSERT(kTightCopy_DomainMode != domainMode);
     if (filterOrNullForBicubic) {
         if (kDomain_DomainMode == domainMode) {
@@ -233,18 +233,17 @@
                                                domain, GrTextureDomain::kClamp_Mode,
                                                *filterOrNullForBicubic);
         } else {
-            GrSamplerParams params(SkShader::kClamp_TileMode, *filterOrNullForBicubic);
-            return GrSimpleTextureEffect::Make(std::move(proxy),
-                                               std::move(colorSpaceXform), textureMatrix,
-                                               params);
+            GrSamplerState samplerState(GrSamplerState::WrapMode::kClamp, *filterOrNullForBicubic);
+            return GrSimpleTextureEffect::Make(std::move(proxy), std::move(colorSpaceXform),
+                                               textureMatrix, samplerState);
         }
     } else {
         if (kDomain_DomainMode == domainMode) {
             return GrBicubicEffect::Make(std::move(proxy), std::move(colorSpaceXform),
                                          textureMatrix, domain);
         } else {
-            static const SkShader::TileMode kClampClamp[] =
-                { SkShader::kClamp_TileMode, SkShader::kClamp_TileMode };
+            static const GrSamplerState::WrapMode kClampClamp[] = {
+                    GrSamplerState::WrapMode::kClamp, GrSamplerState::WrapMode::kClamp};
             return GrBicubicEffect::Make(std::move(proxy), std::move(colorSpaceXform),
                                          textureMatrix, kClampClamp);
         }
diff --git a/src/gpu/GrTextureProducer.h b/src/gpu/GrTextureProducer.h
index ccc0dae..7d05664 100644
--- a/src/gpu/GrTextureProducer.h
+++ b/src/gpu/GrTextureProducer.h
@@ -8,17 +8,23 @@
 #ifndef GrTextureProducer_DEFINED
 #define GrTextureProducer_DEFINED
 
-#include "GrSamplerParams.h"
 #include "GrResourceKey.h"
+#include "GrSamplerState.h"
+#include "SkImageInfo.h"
 
+class GrContext;
 class GrColorSpaceXform;
+class GrFragmentProcessor;
 class GrTexture;
 class GrTextureProxy;
+class SkColorSpace;
+class SkMatrix;
+struct SkRect;
 
 /**
  * Different GPUs and API extensions have different requirements with respect to what texture
  * sampling parameters may be used with textures of various types. This class facilitates making
- * texture compatible with a given GrSamplerParams. There are two immediate subclasses defined
+ * texture compatible with a given GrSamplerState. There are two immediate subclasses defined
  * below. One is a base class for sources that are inherently texture-backed (e.g. a texture-backed
  * SkImage). It supports subsetting the original texture. The other is for use cases where the
  * source can generate a texture that represents some content (e.g. cpu pixels, SkPicture, ...).
@@ -26,9 +32,9 @@
 class GrTextureProducer : public SkNoncopyable {
 public:
     struct CopyParams {
-        GrSamplerParams::FilterMode fFilter;
-        int                         fWidth;
-        int                         fHeight;
+        GrSamplerState::Filter fFilter;
+        int fWidth;
+        int fHeight;
     };
 
     enum FilterConstraint {
@@ -61,7 +67,7 @@
             const SkRect& constraintRect,
             FilterConstraint filterConstraint,
             bool coordsLimitedToConstraintRect,
-            const GrSamplerParams::FilterMode* filterOrNullForBicubic,
+            const GrSamplerState::Filter* filterOrNullForBicubic,
             SkColorSpace* dstColorSpace) = 0;
 
     virtual ~GrTextureProducer() {}
@@ -87,7 +93,7 @@
         if (origKey.isValid()) {
             static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
             GrUniqueKey::Builder builder(copyKey, origKey, kDomain, 3);
-            builder[0] = copyParams.fFilter;
+            builder[0] = static_cast<uint32_t>(copyParams.fFilter);
             builder[1] = copyParams.fWidth;
             builder[2] = copyParams.fHeight;
         }
@@ -121,14 +127,13 @@
     static sk_sp<GrTextureProxy> CopyOnGpu(GrContext*, sk_sp<GrTextureProxy> inputProxy,
                                            const SkIRect* subset, const CopyParams& copyParams);
 
-    static DomainMode DetermineDomainMode(
-        const SkRect& constraintRect,
-        FilterConstraint filterConstraint,
-        bool coordsLimitedToConstraintRect,
-        GrTextureProxy*,
-        const SkIRect* textureContentArea,
-        const GrSamplerParams::FilterMode* filterModeOrNullForBicubic,
-        SkRect* domainRect);
+    static DomainMode DetermineDomainMode(const SkRect& constraintRect,
+                                          FilterConstraint filterConstraint,
+                                          bool coordsLimitedToConstraintRect,
+                                          GrTextureProxy*,
+                                          const SkIRect* textureContentArea,
+                                          const GrSamplerState::Filter* filterModeOrNullForBicubic,
+                                          SkRect* domainRect);
 
     static std::unique_ptr<GrFragmentProcessor> CreateFragmentProcessorForDomainAndFilter(
             sk_sp<GrTextureProxy> proxy,
@@ -136,7 +141,7 @@
             const SkMatrix& textureMatrix,
             DomainMode,
             const SkRect& domain,
-            const GrSamplerParams::FilterMode* filterOrNullForBicubic);
+            const GrSamplerState::Filter* filterOrNullForBicubic);
 
 private:
     const int   fWidth;
diff --git a/src/gpu/GrTextureProxy.cpp b/src/gpu/GrTextureProxy.cpp
index a09cc71..2455628 100644
--- a/src/gpu/GrTextureProxy.cpp
+++ b/src/gpu/GrTextureProxy.cpp
@@ -61,20 +61,20 @@
 }
 
 // This method parallels the highest_filter_mode functions in GrGLTexture & GrVkTexture.
-GrSamplerParams::FilterMode GrTextureProxy::highestFilterMode() const {
+GrSamplerState::Filter GrTextureProxy::highestFilterMode() const {
     if (fTarget) {
         return fTarget->asTexture()->texturePriv().highestFilterMode();
     }
 
     if (GrPixelConfigIsSint(this->config())) {
         // We only ever want to nearest-neighbor sample signed int textures.
-        return GrSamplerParams::kNone_FilterMode;
+        return GrSamplerState::Filter::kNearest;
     }
 
     // In OpenGL, GR_GL_TEXTURE_RECTANGLE and GR_GL_TEXTURE_EXTERNAL (which have a highest filter
     // mode of bilerp) can only be created via wrapping.
 
-    return GrSamplerParams::kMipMap_FilterMode;
+    return GrSamplerState::Filter::kMipMap;
 }
 
 size_t GrTextureProxy::onUninstantiatedGpuMemorySize() const {
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 0cf2ae5..8e05d8a 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -702,10 +702,11 @@
     }
 }
 
-bool SkGpuDevice::shouldTileImageID(uint32_t imageID, const SkIRect& imageRect,
+bool SkGpuDevice::shouldTileImageID(uint32_t imageID,
+                                    const SkIRect& imageRect,
                                     const SkMatrix& viewMatrix,
                                     const SkMatrix& srcToDstRect,
-                                    const GrSamplerParams& params,
+                                    const GrSamplerState& params,
                                     const SkRect* srcRectPtr,
                                     int maxTileSize,
                                     int* tileSize,
@@ -761,20 +762,20 @@
     // If image is explicitly texture backed then we shouldn't get here.
     SkASSERT(!image->isTextureBacked());
 
-    GrSamplerParams params;
+    GrSamplerState samplerState;
     bool doBicubic;
-    GrSamplerParams::FilterMode textureFilterMode =
-                    GrSkFilterQualityToGrFilterMode(quality, viewMatrix, srcToDstRect, &doBicubic);
+    GrSamplerState::Filter textureFilterMode =
+            GrSkFilterQualityToGrFilterMode(quality, viewMatrix, srcToDstRect, &doBicubic);
 
     int tileFilterPad;
     if (doBicubic) {
         tileFilterPad = GrBicubicEffect::kFilterTexelPad;
-    } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
+    } else if (GrSamplerState::Filter::kNearest == textureFilterMode) {
         tileFilterPad = 0;
     } else {
         tileFilterPad = 1;
     }
-    params.setFilterMode(textureFilterMode);
+    samplerState.setFilterMode(textureFilterMode);
 
     int maxTileSize = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
 
@@ -783,7 +784,7 @@
     SkIRect outClippedSrcRect;
 
     return this->shouldTileImageID(image->unique(), image->bounds(), viewMatrix, srcToDstRect,
-                                   params, srcRectPtr, maxTileSize, &outTileSize,
+                                   samplerState, srcRectPtr, maxTileSize, &outTileSize,
                                    &outClippedSrcRect);
 }
 
@@ -811,30 +812,29 @@
         int tileSize;
         SkIRect clippedSrcRect;
 
-        GrSamplerParams params;
+        GrSamplerState samplerState;
         bool doBicubic;
-        GrSamplerParams::FilterMode textureFilterMode =
-            GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, SkMatrix::I(),
-                                            &doBicubic);
+        GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode(
+                paint.getFilterQuality(), viewMatrix, SkMatrix::I(), &doBicubic);
 
         int tileFilterPad;
 
         if (doBicubic) {
             tileFilterPad = GrBicubicEffect::kFilterTexelPad;
-        } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
+        } else if (GrSamplerState::Filter::kNearest == textureFilterMode) {
             tileFilterPad = 0;
         } else {
             tileFilterPad = 1;
         }
-        params.setFilterMode(textureFilterMode);
+        samplerState.setFilterMode(textureFilterMode);
 
         int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
         if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), viewMatrix,
-                                    SkMatrix::I(), params, &srcRect, maxTileSizeForFilter,
+                                    SkMatrix::I(), samplerState, &srcRect, maxTileSizeForFilter,
                                     &tileSize, &clippedSrcRect)) {
             this->drawTiledBitmap(bitmap, viewMatrix, SkMatrix::I(), srcRect, clippedSrcRect,
-                                  params, paint, SkCanvas::kStrict_SrcRectConstraint, tileSize,
-                                  doBicubic);
+                                  samplerState, paint, SkCanvas::kStrict_SrcRectConstraint,
+                                  tileSize, doBicubic);
             return;
         }
     }
@@ -883,7 +883,7 @@
                                   const SkMatrix& dstMatrix,
                                   const SkRect& srcRect,
                                   const SkIRect& clippedSrcIRect,
-                                  const GrSamplerParams& params,
+                                  const GrSamplerState& params,
                                   const SkPaint& origPaint,
                                   SkCanvas::SrcRectConstraint constraint,
                                   int tileSize,
@@ -928,7 +928,7 @@
                                             SkIntToScalar(iTileR.fTop));
             SkRect rectToDraw = tileR;
             dstMatrix.mapRect(&rectToDraw);
-            if (GrSamplerParams::kNone_FilterMode != params.filterMode() || bicubic) {
+            if (GrSamplerState::Filter::kNearest != params.filter() || bicubic) {
                 SkIRect iClampRect;
 
                 if (SkCanvas::kFast_SrcRectConstraint == constraint) {
@@ -969,7 +969,7 @@
                                  const SkMatrix& viewMatrix,
                                  const SkRect& dstRect,
                                  const SkRect& srcRect,
-                                 const GrSamplerParams& params,
+                                 const GrSamplerState& samplerState,
                                  const SkPaint& paint,
                                  SkCanvas::SrcRectConstraint constraint,
                                  bool bicubic,
@@ -980,12 +980,10 @@
     // We should be respecting the max tile size by the time we get here.
     SkASSERT(bitmap.width() <= fContext->caps()->maxTileSize() &&
              bitmap.height() <= fContext->caps()->maxTileSize());
+    SkASSERT(!samplerState.isRepeated());
 
-    SkASSERT(SkShader::kClamp_TileMode == params.getTileModeX() &&
-             SkShader::kClamp_TileMode == params.getTileModeY());
-
-    sk_sp<GrTextureProxy> proxy = GrRefCachedBitmapTextureProxy(fContext.get(), bitmap,
-                                                                params, nullptr);
+    sk_sp<GrTextureProxy> proxy =
+            GrRefCachedBitmapTextureProxy(fContext.get(), bitmap, samplerState, nullptr);
     if (!proxy) {
         return;
     }
@@ -1019,19 +1017,18 @@
             fp = GrBicubicEffect::Make(std::move(proxy),
                                        std::move(colorSpaceXform), texMatrix, domain);
         } else {
-            fp = GrTextureDomainEffect::Make(std::move(proxy),
-                                             std::move(colorSpaceXform), texMatrix,
-                                             domain, GrTextureDomain::kClamp_Mode,
-                                             params.filterMode());
+            fp = GrTextureDomainEffect::Make(std::move(proxy), std::move(colorSpaceXform),
+                                             texMatrix, domain, GrTextureDomain::kClamp_Mode,
+                                             samplerState.filter());
         }
     } else if (bicubic) {
-        SkASSERT(GrSamplerParams::kNone_FilterMode == params.filterMode());
-        SkShader::TileMode tileModes[2] = { params.getTileModeX(), params.getTileModeY() };
-        fp = GrBicubicEffect::Make(std::move(proxy),
-                                   std::move(colorSpaceXform), texMatrix, tileModes);
+        SkASSERT(GrSamplerState::Filter::kNearest == samplerState.filter());
+        GrSamplerState::WrapMode wrapMode[2] = {samplerState.wrapModeX(), samplerState.wrapModeY()};
+        fp = GrBicubicEffect::Make(std::move(proxy), std::move(colorSpaceXform), texMatrix,
+                                   wrapMode);
     } else {
-        fp = GrSimpleTextureEffect::Make(std::move(proxy),
-                                         std::move(colorSpaceXform), texMatrix, params);
+        fp = GrSimpleTextureEffect::Make(std::move(proxy), std::move(colorSpaceXform), texMatrix,
+                                         samplerState);
     }
 
     GrPaint grPaint;
@@ -1172,29 +1169,28 @@
         int tileSize;
         SkIRect clippedSrcRect;
 
-        GrSamplerParams params;
+        GrSamplerState sampleState;
         bool doBicubic;
-        GrSamplerParams::FilterMode textureFilterMode =
-            GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), srcToDstMatrix,
-                                            &doBicubic);
+        GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode(
+                paint.getFilterQuality(), this->ctm(), srcToDstMatrix, &doBicubic);
 
         int tileFilterPad;
 
         if (doBicubic) {
             tileFilterPad = GrBicubicEffect::kFilterTexelPad;
-        } else if (GrSamplerParams::kNone_FilterMode == textureFilterMode) {
+        } else if (GrSamplerState::Filter::kNearest == textureFilterMode) {
             tileFilterPad = 0;
         } else {
             tileFilterPad = 1;
         }
-        params.setFilterMode(textureFilterMode);
+        sampleState.setFilterMode(textureFilterMode);
 
         int maxTileSizeForFilter = fContext->caps()->maxTileSize() - 2 * tileFilterPad;
         if (this->shouldTileImageID(bitmap.getGenerationID(), bitmap.getSubset(), this->ctm(),
-                                    srcToDstMatrix, params, src, maxTileSizeForFilter, &tileSize,
-                                    &clippedSrcRect)) {
+                                    srcToDstMatrix, sampleState, src, maxTileSizeForFilter,
+                                    &tileSize, &clippedSrcRect)) {
             this->drawTiledBitmap(bitmap, this->ctm(), srcToDstMatrix, *src, clippedSrcRect,
-                                  params, paint, constraint, tileSize, doBicubic);
+                                  sampleState, paint, constraint, tileSize, doBicubic);
             return;
         }
     }
@@ -1365,10 +1361,9 @@
     bool useFallback = paint.getMaskFilter() || paint.isAntiAlias() ||
                        GrFSAAType::kUnifiedMSAA == fRenderTargetContext->fsaaType();
     bool doBicubic;
-    GrSamplerParams::FilterMode textureFilterMode =
-        GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), this->ctm(), SkMatrix::I(),
-                                        &doBicubic);
-    if (useFallback || doBicubic || GrSamplerParams::kNone_FilterMode != textureFilterMode) {
+    GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode(
+            paint.getFilterQuality(), this->ctm(), SkMatrix::I(), &doBicubic);
+    if (useFallback || doBicubic || GrSamplerState::Filter::kNearest != textureFilterMode) {
         SkLatticeIter iter(producer->width(), producer->height(), center, dst);
 
         SkRect srcR, dstR;
@@ -1379,7 +1374,7 @@
         return;
     }
 
-    static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode;
+    static const GrSamplerState::Filter kMode = GrSamplerState::Filter::kNearest;
     auto fp = producer->createFragmentProcessor(
             SkMatrix::I(), SkRect::MakeIWH(producer->width(), producer->height()),
             GrTextureProducer::kNo_FilterConstraint, true, &kMode,
@@ -1433,7 +1428,7 @@
                                       const SkPaint& paint) {
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawProducerLattice", fContext.get());
 
-    static const GrSamplerParams::FilterMode kMode = GrSamplerParams::kNone_FilterMode;
+    static const GrSamplerState::Filter kMode = GrSamplerState::Filter::kNearest;
     std::unique_ptr<GrFragmentProcessor> fp(producer->createFragmentProcessor(
             SkMatrix::I(), SkRect::MakeIWH(producer->width(), producer->height()),
             GrTextureProducer::kNo_FilterConstraint, true, &kMode,
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index cf78b94..548819b 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -163,10 +163,11 @@
      */
 
     // The tileSize and clippedSrcRect will be valid only if true is returned.
-    bool shouldTileImageID(uint32_t imageID, const SkIRect& imageRect,
+    bool shouldTileImageID(uint32_t imageID,
+                           const SkIRect& imageRect,
                            const SkMatrix& viewMatrix,
                            const SkMatrix& srcToDstRectMatrix,
-                           const GrSamplerParams& params,
+                           const GrSamplerState& params,
                            const SkRect* srcRectPtr,
                            int maxTileSize,
                            int* tileSize,
@@ -188,7 +189,7 @@
                          const SkMatrix& srcToDstMatrix,
                          const SkRect& srcRect,
                          const SkIRect& clippedSrcRect,
-                         const GrSamplerParams& params,
+                         const GrSamplerState& params,
                          const SkPaint& paint,
                          SkCanvas::SrcRectConstraint,
                          int tileSize,
@@ -199,7 +200,7 @@
                         const SkMatrix& viewMatrix,
                         const SkRect& dstRect,
                         const SkRect& srcRect,
-                        const GrSamplerParams& params,
+                        const GrSamplerState& samplerState,
                         const SkPaint& paint,
                         SkCanvas::SrcRectConstraint,
                         bool bicubic,
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index c861cc9..c7aeeb1 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -114,13 +114,13 @@
         srcToDst.mapRect(&dstRect, srcRect);
     }
     auto csxf = GrColorSpaceXform::Make(colorSpace, rtc->getColorSpace());
-    GrSamplerParams::FilterMode filter;
+    GrSamplerState::Filter filter;
     switch (paint.getFilterQuality()) {
         case kNone_SkFilterQuality:
-            filter = GrSamplerParams::kNone_FilterMode;
+            filter = GrSamplerState::Filter::kNearest;
             break;
         case kLow_SkFilterQuality:
-            filter = GrSamplerParams::kBilerp_FilterMode;
+            filter = GrSamplerState::Filter::kBilerp;
             break;
         case kMedium_SkFilterQuality:
         case kHigh_SkFilterQuality:
@@ -157,9 +157,9 @@
                                    const SkMatrix& viewMatrix, const SkPaint& paint) {
     if (can_use_draw_texture_affine(paint, viewMatrix, constraint)) {
         sk_sp<SkColorSpace> cs;
-        // We've done enough checks above to allow us to pass ClampNoFilter() and not check for
+        // We've done enough checks above to allow us to pass ClampNearest() and not check for
         // scaling adjustments.
-        auto proxy = maker->refTextureProxyForParams(GrSamplerParams::ClampNoFilter(),
+        auto proxy = maker->refTextureProxyForParams(GrSamplerState::ClampNearest(),
                                                      fRenderTargetContext->getColorSpace(), &cs,
                                                      nullptr);
         if (!proxy) {
@@ -246,10 +246,9 @@
     bool canUseTextureCoordsAsLocalCoords = !use_shader(producer->isAlphaOnly(), paint) && !mf;
 
     bool doBicubic;
-    GrSamplerParams::FilterMode fm =
-        GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, srcToDstMatrix,
-                                        &doBicubic);
-    const GrSamplerParams::FilterMode* filterMode = doBicubic ? nullptr : &fm;
+    GrSamplerState::Filter fm = GrSkFilterQualityToGrFilterMode(
+            paint.getFilterQuality(), viewMatrix, srcToDstMatrix, &doBicubic);
+    const GrSamplerState::Filter* filterMode = doBicubic ? nullptr : &fm;
 
     GrTextureProducer::FilterConstraint constraintMode;
     if (SkCanvas::kFast_SrcRectConstraint == constraint) {
@@ -264,7 +263,7 @@
     bool coordsAllInsideSrcRect = !paint.isAntiAlias() && !mf;
 
     // Check for optimization to drop the src rect constraint when on bilerp.
-    if (filterMode && GrSamplerParams::kBilerp_FilterMode == *filterMode &&
+    if (filterMode && GrSamplerState::Filter::kBilerp == *filterMode &&
         GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect) {
         SkMatrix combinedMatrix;
         combinedMatrix.setConcat(viewMatrix, srcToDstMatrix);
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 447c28d..dc202fb 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -226,7 +226,7 @@
 
 sk_sp<GrTextureProxy> GrRefCachedBitmapTextureProxy(GrContext* ctx,
                                                     const SkBitmap& bitmap,
-                                                    const GrSamplerParams& params,
+                                                    const GrSamplerState& params,
                                                     SkScalar scaleAdjust[2]) {
     // Caller doesn't care about the texture's color space (they can always get it from the bitmap)
     return GrBitmapTextureMaker(ctx, bitmap).refTextureProxyForParams(params, nullptr,
@@ -621,27 +621,27 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
-GrSamplerParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality,
-                                                            const SkMatrix& viewM,
-                                                            const SkMatrix& localM,
-                                                            bool* doBicubic) {
+GrSamplerState::Filter GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality,
+                                                       const SkMatrix& viewM,
+                                                       const SkMatrix& localM,
+                                                       bool* doBicubic) {
     *doBicubic = false;
-    GrSamplerParams::FilterMode textureFilterMode;
+    GrSamplerState::Filter textureFilterMode;
     switch (paintFilterQuality) {
         case kNone_SkFilterQuality:
-            textureFilterMode = GrSamplerParams::kNone_FilterMode;
+            textureFilterMode = GrSamplerState::Filter::kNearest;
             break;
         case kLow_SkFilterQuality:
-            textureFilterMode = GrSamplerParams::kBilerp_FilterMode;
+            textureFilterMode = GrSamplerState::Filter::kBilerp;
             break;
         case kMedium_SkFilterQuality: {
             SkMatrix matrix;
             matrix.setConcat(viewM, localM);
             if (matrix.getMinScale() < SK_Scalar1) {
-                textureFilterMode = GrSamplerParams::kMipMap_FilterMode;
+                textureFilterMode = GrSamplerState::Filter::kMipMap;
             } else {
                 // Don't trigger MIP level generation unnecessarily.
-                textureFilterMode = GrSamplerParams::kBilerp_FilterMode;
+                textureFilterMode = GrSamplerState::Filter::kBilerp;
             }
             break;
         }
@@ -653,7 +653,7 @@
         }
         default:
             // Should be unreachable.  If not, fall back to mipmaps.
-            textureFilterMode = GrSamplerParams::kMipMap_FilterMode;
+            textureFilterMode = GrSamplerState::Filter::kMipMap;
             break;
 
     }
diff --git a/src/gpu/SkGr.h b/src/gpu/SkGr.h
index d228894..66b625a 100644
--- a/src/gpu/SkGr.h
+++ b/src/gpu/SkGr.h
@@ -10,8 +10,9 @@
 
 #include "GrBlend.h"
 #include "GrColor.h"
-#include "GrSamplerParams.h"
+#include "GrSamplerState.h"
 #include "GrTypes.h"
+#include "SkBlendModePriv.h"
 #include "SkCanvas.h"
 #include "SkColor.h"
 #include "SkColorPriv.h"
@@ -20,7 +21,6 @@
 #include "SkMatrix.h"
 #include "SkPM4f.h"
 #include "SkVertices.h"
-#include "SkBlendModePriv.h"
 
 class GrCaps;
 class GrColorSpaceXform;
@@ -156,10 +156,10 @@
 
 bool GrPixelConfigToColorType(GrPixelConfig, SkColorType*);
 
-GrSamplerParams::FilterMode GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality,
-                                                            const SkMatrix& viewM,
-                                                            const SkMatrix& localM,
-                                                            bool* doBicubic);
+GrSamplerState::Filter GrSkFilterQualityToGrFilterMode(SkFilterQuality paintFilterQuality,
+                                                       const SkMatrix& viewM,
+                                                       const SkMatrix& localM,
+                                                       bool* doBicubic);
 
 //////////////////////////////////////////////////////////////////////////////
 
@@ -195,7 +195,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Texture management
 
-/** Returns a texture representing the bitmap that is compatible with the GrSamplerParams. The
+/** Returns a texture representing the bitmap that is compatible with the GrSamplerState. The
  *  texture is inserted into the cache (unless the bitmap is marked volatile) and can be
  *  retrieved again via this function.
  *  The 'scaleAdjust' in/out parameter will be updated to hold any rescaling that needs to be
@@ -204,7 +204,7 @@
  */
 sk_sp<GrTextureProxy> GrRefCachedBitmapTextureProxy(GrContext*,
                                                     const SkBitmap&,
-                                                    const GrSamplerParams&,
+                                                    const GrSamplerState&,
                                                     SkScalar scaleAdjust[2]);
 
 /**
@@ -238,7 +238,7 @@
 //        return nullptr;
 //    }
 //    sk_sp<GrTexture> texture = GrMakeCachedBitmapTexture(fContext.get(), bitmap,
-//                                                         GrSamplerParams::ClampNoFilter(),
+//                                                         GrSamplerState::ClampNearest(),
 //                                                         nullptr);
 //    if (!texture) {
 //        return nullptr;
diff --git a/src/gpu/ccpr/GrCCPRPathProcessor.cpp b/src/gpu/ccpr/GrCCPRPathProcessor.cpp
index 54ffb9b..429767d 100644
--- a/src/gpu/ccpr/GrCCPRPathProcessor.cpp
+++ b/src/gpu/ccpr/GrCCPRPathProcessor.cpp
@@ -78,8 +78,8 @@
 
     this->addVertexAttrib("edge_norms", kVec4f_GrVertexAttribType, kHigh_GrSLPrecision);
 
-    fAtlasAccess.reset(std::move(atlas), GrSamplerParams::FilterMode::kNone_FilterMode,
-                       SkShader::TileMode::kClamp_TileMode, kFragment_GrShaderFlag);
+    fAtlasAccess.reset(std::move(atlas), GrSamplerState::Filter::kNearest,
+                       GrSamplerState::WrapMode::kClamp, kFragment_GrShaderFlag);
     fAtlasAccess.instantiate(rp);
     this->addTextureSampler(&fAtlasAccess);
 
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index c8b302c..7417e29 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -134,12 +134,12 @@
 GrBicubicEffect::GrBicubicEffect(sk_sp<GrTextureProxy> proxy,
                                  sk_sp<GrColorSpaceXform> colorSpaceXform,
                                  const SkMatrix& matrix,
-                                 const SkShader::TileMode tileModes[2])
+                                 const GrSamplerState::WrapMode wrapModes[2])
         : INHERITED{ModulateByConfigOptimizationFlags(proxy->config())}
         , fCoordTransform(matrix, proxy.get())
         , fDomain(GrTextureDomain::IgnoredDomain())
         , fTextureSampler(std::move(proxy),
-                          GrSamplerParams(tileModes, GrSamplerParams::kNone_FilterMode))
+                          GrSamplerState(wrapModes, GrSamplerState::Filter::kNearest))
         , fColorSpaceXform(std::move(colorSpaceXform)) {
     this->initClassID<GrBicubicEffect>();
     this->addCoordTransform(&fCoordTransform);
@@ -192,8 +192,8 @@
     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 };
+    static const GrSamplerState::WrapMode kClampClamp[] = {GrSamplerState::WrapMode::kClamp,
+                                                           GrSamplerState::WrapMode::kClamp};
     return GrBicubicEffect::Make(d->textureProxy(texIdx), std::move(colorSpaceXform),
                                  SkMatrix::I(), kClampClamp);
 }
@@ -201,10 +201,9 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-bool GrBicubicEffect::ShouldUseBicubic(const SkMatrix& matrix,
-                                       GrSamplerParams::FilterMode* filterMode) {
+bool GrBicubicEffect::ShouldUseBicubic(const SkMatrix& matrix, GrSamplerState::Filter* filterMode) {
     if (matrix.isIdentity()) {
-        *filterMode = GrSamplerParams::kNone_FilterMode;
+        *filterMode = GrSamplerState::Filter::kNearest;
         return false;
     }
 
@@ -212,22 +211,22 @@
     if (!matrix.getMinMaxScales(scales) || scales[0] < SK_Scalar1) {
         // Bicubic doesn't handle arbitrary minimization well, as src texels can be skipped
         // entirely,
-        *filterMode = GrSamplerParams::kMipMap_FilterMode;
+        *filterMode = GrSamplerState::Filter::kMipMap;
         return false;
     }
     // At this point if scales[1] == SK_Scalar1 then the matrix doesn't do any scaling.
     if (scales[1] == SK_Scalar1) {
         if (matrix.rectStaysRect() && SkScalarIsInt(matrix.getTranslateX()) &&
             SkScalarIsInt(matrix.getTranslateY())) {
-            *filterMode = GrSamplerParams::kNone_FilterMode;
+            *filterMode = GrSamplerState::Filter::kNearest;
         } else {
             // Use bilerp to handle rotation or fractional translation.
-            *filterMode = GrSamplerParams::kBilerp_FilterMode;
+            *filterMode = GrSamplerState::Filter::kBilerp;
         }
         return false;
     }
     // When we use the bicubic filtering effect each sample is read from the texture using
     // nearest neighbor sampling.
-    *filterMode = GrSamplerParams::kNone_FilterMode;
+    *filterMode = GrSamplerState::Filter::kNearest;
     return true;
 }
diff --git a/src/gpu/effects/GrBicubicEffect.h b/src/gpu/effects/GrBicubicEffect.h
index 7812f3f..b0a28d9 100644
--- a/src/gpu/effects/GrBicubicEffect.h
+++ b/src/gpu/effects/GrBicubicEffect.h
@@ -36,9 +36,9 @@
     static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
                                                      sk_sp<GrColorSpaceXform> colorSpaceXform,
                                                      const SkMatrix& matrix,
-                                                     const SkShader::TileMode tileModes[2]) {
+                                                     const GrSamplerState::WrapMode wrapModes[2]) {
         return std::unique_ptr<GrFragmentProcessor>(new GrBicubicEffect(
-                std::move(proxy), std::move(colorSpaceXform), matrix, tileModes));
+                std::move(proxy), std::move(colorSpaceXform), matrix, wrapModes));
     }
 
     /**
@@ -60,11 +60,11 @@
      * kNearest).
      */
     static bool ShouldUseBicubic(const SkMatrix& localCoordsToDevice,
-                                 GrSamplerParams::FilterMode* filterMode);
+                                 GrSamplerState::Filter* filterMode);
 
 private:
-    GrBicubicEffect(sk_sp<GrTextureProxy>, sk_sp<GrColorSpaceXform>,
-                    const SkMatrix &matrix, const SkShader::TileMode tileModes[2]);
+    GrBicubicEffect(sk_sp<GrTextureProxy>, sk_sp<GrColorSpaceXform>, const SkMatrix& matrix,
+                    const GrSamplerState::WrapMode wrapModes[2]);
     GrBicubicEffect(sk_sp<GrTextureProxy>, sk_sp<GrColorSpaceXform>,
                     const SkMatrix &matrix, const SkRect& domain);
     explicit GrBicubicEffect(const GrBicubicEffect&);
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index d87f7c0..c2cf8eb 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -122,16 +122,15 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color,
-                                         sk_sp<GrTextureProxy> proxy,
-                                         const GrSamplerParams& params, GrMaskFormat format,
+GrBitmapTextGeoProc::GrBitmapTextGeoProc(GrColor color, sk_sp<GrTextureProxy> proxy,
+                                         const GrSamplerState& params, GrMaskFormat format,
                                          const SkMatrix& localMatrix, bool usesLocalCoords)
-    : fColor(color)
-    , fLocalMatrix(localMatrix)
-    , fUsesLocalCoords(usesLocalCoords)
-    , fTextureSampler(std::move(proxy), params)
-    , fInColor(nullptr)
-    , fMaskFormat(format) {
+        : fColor(color)
+        , fLocalMatrix(localMatrix)
+        , fUsesLocalCoords(usesLocalCoords)
+        , fTextureSampler(std::move(proxy), params)
+        , fInColor(nullptr)
+        , fMaskFormat(format) {
     this->initClassID<GrBitmapTextGeoProc>();
     fInPosition =
             &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision);
@@ -161,22 +160,17 @@
 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrBitmapTextGeoProc);
 
 #if GR_TEST_UTILS
+
 sk_sp<GrGeometryProcessor> GrBitmapTextGeoProc::TestCreate(GrProcessorTestData* d) {
     int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
                                         : GrProcessorUnitTest::kAlphaTextureIdx;
     sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
 
-    static const SkShader::TileMode kTileModes[] = {
-        SkShader::kClamp_TileMode,
-        SkShader::kRepeat_TileMode,
-        SkShader::kMirror_TileMode,
-    };
-    SkShader::TileMode tileModes[] = {
-        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);
+    GrSamplerState::WrapMode wrapModes[2];
+    GrTest::TestWrapModes(d->fRandom, wrapModes);
+    GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
+                                                   ? GrSamplerState::Filter::kBilerp
+                                                   : GrSamplerState::Filter::kNearest);
 
     GrMaskFormat format = kARGB_GrMaskFormat; // init to avoid warning
     switch (d->fRandom->nextULessThan(3)) {
@@ -191,8 +185,8 @@
             break;
     }
 
-    return GrBitmapTextGeoProc::Make(GrRandomColor(d->fRandom), std::move(proxy),
-                                     params, format, GrTest::TestMatrix(d->fRandom),
+    return GrBitmapTextGeoProc::Make(GrRandomColor(d->fRandom), std::move(proxy), samplerState,
+                                     format, GrTest::TestMatrix(d->fRandom),
                                      d->fRandom->nextBool());
 }
 #endif
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.h b/src/gpu/effects/GrBitmapTextGeoProc.h
index 2664b2e..c919d1c 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.h
+++ b/src/gpu/effects/GrBitmapTextGeoProc.h
@@ -16,15 +16,14 @@
 
 /**
  * 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). The input
+ * It allows explicit specification of the filtering and wrap modes (GrSamplerState). The input
  * coords are a custom attribute.
  */
 class GrBitmapTextGeoProc : public GrGeometryProcessor {
 public:
-    static sk_sp<GrGeometryProcessor> Make(GrColor color,
-                                           sk_sp<GrTextureProxy> proxy, const GrSamplerParams& p,
-                                           GrMaskFormat format, const SkMatrix& localMatrix,
-                                           bool usesLocalCoords) {
+    static sk_sp<GrGeometryProcessor> Make(GrColor color, sk_sp<GrTextureProxy> proxy,
+                                           const GrSamplerState& p, GrMaskFormat format,
+                                           const SkMatrix& localMatrix, bool usesLocalCoords) {
         return sk_sp<GrGeometryProcessor>(
             new GrBitmapTextGeoProc(color, std::move(proxy), p, format,
                                     localMatrix, usesLocalCoords));
@@ -48,8 +47,7 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override;
 
 private:
-    GrBitmapTextGeoProc(GrColor, sk_sp<GrTextureProxy>,
-                        const GrSamplerParams& params,
+    GrBitmapTextGeoProc(GrColor, sk_sp<GrTextureProxy>, const GrSamplerState& params,
                         GrMaskFormat format, const SkMatrix& localMatrix, bool usesLocalCoords);
 
     GrColor          fColor;
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index 3078786..81b3326 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -236,21 +236,21 @@
 GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color,
                                                            const SkMatrix& viewMatrix,
                                                            sk_sp<GrTextureProxy> proxy,
-                                                           const GrSamplerParams& params,
+                                                           const GrSamplerState& params,
 #ifdef SK_GAMMA_APPLY_TO_A8
                                                            float distanceAdjust,
 #endif
                                                            uint32_t flags,
                                                            bool usesLocalCoords)
-    : fColor(color)
-    , fViewMatrix(viewMatrix)
-    , fTextureSampler(std::move(proxy), params)
+        : fColor(color)
+        , fViewMatrix(viewMatrix)
+        , fTextureSampler(std::move(proxy), params)
 #ifdef SK_GAMMA_APPLY_TO_A8
-    , fDistanceAdjust(distanceAdjust)
+        , fDistanceAdjust(distanceAdjust)
 #endif
-    , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
-    , fInColor(nullptr)
-    , fUsesLocalCoords(usesLocalCoords) {
+        , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
+        , fInColor(nullptr)
+        , fUsesLocalCoords(usesLocalCoords) {
     SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
     this->initClassID<GrDistanceFieldA8TextGeoProc>();
     fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
@@ -281,17 +281,11 @@
                                         : GrProcessorUnitTest::kAlphaTextureIdx;
     sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
 
-    static const SkShader::TileMode kTileModes[] = {
-        SkShader::kClamp_TileMode,
-        SkShader::kRepeat_TileMode,
-        SkShader::kMirror_TileMode,
-    };
-    SkShader::TileMode tileModes[] = {
-        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);
+    GrSamplerState::WrapMode wrapModes[2];
+    GrTest::TestWrapModes(d->fRandom, wrapModes);
+    GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
+                                                   ? GrSamplerState::Filter::kBilerp
+                                                   : GrSamplerState::Filter::kNearest);
 
     uint32_t flags = 0;
     flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
@@ -300,13 +294,12 @@
     }
 
     return GrDistanceFieldA8TextGeoProc::Make(GrRandomColor(d->fRandom),
-                                              GrTest::TestMatrix(d->fRandom),
-                                              std::move(proxy), params,
+                                              GrTest::TestMatrix(d->fRandom), std::move(proxy),
+                                              samplerState,
 #ifdef SK_GAMMA_APPLY_TO_A8
                                               d->fRandom->nextF(),
 #endif
-                                              flags,
-                                              d->fRandom->nextBool());
+                                              flags, d->fRandom->nextBool());
 }
 #endif
 
@@ -495,7 +488,7 @@
 GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(GrColor color,
                                                        const SkMatrix& viewMatrix,
                                                        sk_sp<GrTextureProxy> proxy,
-                                                       const GrSamplerParams& params,
+                                                       const GrSamplerState& params,
                                                        uint32_t flags,
                                                        bool usesLocalCoords)
         : fColor(color)
@@ -534,17 +527,11 @@
                                         : GrProcessorUnitTest::kAlphaTextureIdx;
     sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
 
-    static const SkShader::TileMode kTileModes[] = {
-        SkShader::kClamp_TileMode,
-        SkShader::kRepeat_TileMode,
-        SkShader::kMirror_TileMode,
-    };
-    SkShader::TileMode tileModes[] = {
-        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);
+    GrSamplerState::WrapMode wrapModes[2];
+    GrTest::TestWrapModes(d->fRandom, wrapModes);
+    GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
+                                                   ? GrSamplerState::Filter::kBilerp
+                                                   : GrSamplerState::Filter::kNearest);
 
     uint32_t flags = 0;
     flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
@@ -555,7 +542,7 @@
     return GrDistanceFieldPathGeoProc::Make(GrRandomColor(d->fRandom),
                                             GrTest::TestMatrix(d->fRandom),
                                             std::move(proxy),
-                                            params,
+                                            samplerState,
                                             flags,
                                             d->fRandom->nextBool());
 }
@@ -806,18 +793,18 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
-GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(
-                                                  GrColor color, const SkMatrix& viewMatrix,
-                                                  sk_sp<GrTextureProxy> proxy,
-                                                  const GrSamplerParams& params,
-                                                  DistanceAdjust distanceAdjust,
-                                                  uint32_t flags, bool usesLocalCoords)
-    : fColor(color)
-    , fViewMatrix(viewMatrix)
-    , fTextureSampler(std::move(proxy), params)
-    , fDistanceAdjust(distanceAdjust)
-    , fFlags(flags & kLCD_DistanceFieldEffectMask)
-    , fUsesLocalCoords(usesLocalCoords) {
+GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(GrColor color,
+                                                             const SkMatrix& viewMatrix,
+                                                             sk_sp<GrTextureProxy> proxy,
+                                                             const GrSamplerState& params,
+                                                             DistanceAdjust distanceAdjust,
+                                                             uint32_t flags, bool usesLocalCoords)
+        : fColor(color)
+        , fViewMatrix(viewMatrix)
+        , fTextureSampler(std::move(proxy), params)
+        , fDistanceAdjust(distanceAdjust)
+        , fFlags(flags & kLCD_DistanceFieldEffectMask)
+        , fUsesLocalCoords(usesLocalCoords) {
     SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
     this->initClassID<GrDistanceFieldLCDTextGeoProc>();
     fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType,
@@ -847,17 +834,11 @@
                                           GrProcessorUnitTest::kAlphaTextureIdx;
     sk_sp<GrTextureProxy> proxy = d->textureProxy(texIdx);
 
-    static const SkShader::TileMode kTileModes[] = {
-        SkShader::kClamp_TileMode,
-        SkShader::kRepeat_TileMode,
-        SkShader::kMirror_TileMode,
-    };
-    SkShader::TileMode tileModes[] = {
-        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);
+    GrSamplerState::WrapMode wrapModes[2];
+    GrTest::TestWrapModes(d->fRandom, wrapModes);
+    GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
+                                                   ? GrSamplerState::Filter::kBilerp
+                                                   : GrSamplerState::Filter::kNearest);
     DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
     uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
     flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
@@ -866,10 +847,7 @@
     }
     flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
     return GrDistanceFieldLCDTextGeoProc::Make(GrRandomColor(d->fRandom),
-                                               GrTest::TestMatrix(d->fRandom),
-                                               std::move(proxy), params,
-                                               wa,
-                                               flags,
-                                               d->fRandom->nextBool());
+                                               GrTest::TestMatrix(d->fRandom), std::move(proxy),
+                                               samplerState, wa, flags, d->fRandom->nextBool());
 }
 #endif
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.h b/src/gpu/effects/GrDistanceFieldGeoProc.h
index 344ac4a..b1836dd 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.h
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.h
@@ -45,7 +45,7 @@
 /**
  * The output color of this effect is a modulation of the input color and a sample from a
  * distance field texture (using a smoothed step function near 0.5).
- * It allows explicit specification of the filtering and wrap modes (GrSamplerParams). The input
+ * It allows explicit specification of the filtering and wrap modes (GrSamplerState). The input
  * coords are a custom attribute. Gamma correction is handled via a texture LUT.
  */
 class GrDistanceFieldA8TextGeoProc : public GrGeometryProcessor {
@@ -53,8 +53,8 @@
 #ifdef SK_GAMMA_APPLY_TO_A8
     static sk_sp<GrGeometryProcessor> Make(GrColor color, const SkMatrix& viewMatrix,
                                            sk_sp<GrTextureProxy> proxy,
-                                           const GrSamplerParams& params,
-                                           float lum, uint32_t flags, bool usesLocalCoords) {
+                                           const GrSamplerState& params, float lum, uint32_t flags,
+                                           bool usesLocalCoords) {
         return sk_sp<GrGeometryProcessor>(
             new GrDistanceFieldA8TextGeoProc(color, viewMatrix, std::move(proxy),
                                              params, lum, flags, usesLocalCoords));
@@ -62,8 +62,8 @@
 #else
     static sk_sp<GrGeometryProcessor> Make(GrColor color, const SkMatrix& viewMatrix,
                                            sk_sp<GrTextureProxy> proxy,
-                                           const GrSamplerParams& params,
-                                           uint32_t flags, bool usesLocalCoords) {
+                                           const GrSamplerState& params, uint32_t flags,
+                                           bool usesLocalCoords) {
         return sk_sp<GrGeometryProcessor>(
             new GrDistanceFieldA8TextGeoProc(color, viewMatrix, std::move(proxy),
                                              params, flags, usesLocalCoords));
@@ -90,8 +90,8 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
 
 private:
-    GrDistanceFieldA8TextGeoProc(GrColor, const SkMatrix& viewMatrix,
-                                 sk_sp<GrTextureProxy> proxy, const GrSamplerParams& params,
+    GrDistanceFieldA8TextGeoProc(GrColor, const SkMatrix& viewMatrix, sk_sp<GrTextureProxy> proxy,
+                                 const GrSamplerState& params,
 #ifdef SK_GAMMA_APPLY_TO_A8
                                  float distanceAdjust,
 #endif
@@ -114,19 +114,18 @@
     typedef GrGeometryProcessor INHERITED;
 };
 
-
 /**
-* The output color of this effect is a modulation of the input color and a sample from a
-* distance field texture (using a smoothed step function near 0.5).
-* It allows explicit specification of the filtering and wrap modes (GrSamplerParams). The input
-* coords are a custom attribute. No gamma correct blending is applied. Used for paths only.
-*/
+ * The output color of this effect is a modulation of the input color and a sample from a
+ * distance field texture (using a smoothed step function near 0.5).
+ * It allows explicit specification of the filtering and wrap modes (GrSamplerState). The input
+ * coords are a custom attribute. No gamma correct blending is applied. Used for paths only.
+ */
 class GrDistanceFieldPathGeoProc : public GrGeometryProcessor {
 public:
-    static sk_sp<GrGeometryProcessor> Make(GrColor color,
-                                           const SkMatrix& viewMatrix, sk_sp<GrTextureProxy> proxy,
-                                           const GrSamplerParams& params,
-                                           uint32_t flags, bool usesLocalCoords) {
+    static sk_sp<GrGeometryProcessor> Make(GrColor color, const SkMatrix& viewMatrix,
+                                           sk_sp<GrTextureProxy> proxy,
+                                           const GrSamplerState& params, uint32_t flags,
+                                           bool usesLocalCoords) {
         return sk_sp<GrGeometryProcessor>(
             new GrDistanceFieldPathGeoProc(color, viewMatrix, std::move(proxy),
                                            params, flags, usesLocalCoords));
@@ -149,9 +148,8 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
 
 private:
-    GrDistanceFieldPathGeoProc(GrColor, const SkMatrix& viewMatrix,
-                               sk_sp<GrTextureProxy>, const GrSamplerParams&, uint32_t flags,
-                               bool usesLocalCoords);
+    GrDistanceFieldPathGeoProc(GrColor, const SkMatrix& viewMatrix, sk_sp<GrTextureProxy>,
+                               const GrSamplerState&, uint32_t flags, bool usesLocalCoords);
 
     GrColor          fColor;
     SkMatrix         fViewMatrix;
@@ -170,7 +168,7 @@
 /**
  * The output color of this effect is a modulation of the input color and samples from a
  * distance field texture (using a smoothed step function near 0.5), adjusted for LCD displays.
- * It allows explicit specification of the filtering and wrap modes (GrSamplerParams). The input
+ * It allows explicit specification of the filtering and wrap modes (GrSamplerState). The input
  * coords are a custom attribute. Gamma correction is handled via a texture LUT.
  */
 class GrDistanceFieldLCDTextGeoProc : public GrGeometryProcessor {
@@ -193,7 +191,7 @@
     static sk_sp<GrGeometryProcessor> Make(GrColor color,
                                            const SkMatrix& viewMatrix,
                                            sk_sp<GrTextureProxy> proxy,
-                                           const GrSamplerParams& params,
+                                           const GrSamplerState& params,
                                            DistanceAdjust distanceAdjust,
                                            uint32_t flags,
                                            bool usesLocalCoords) {
@@ -221,9 +219,8 @@
     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
 
 private:
-    GrDistanceFieldLCDTextGeoProc(GrColor, const SkMatrix& viewMatrix,
-                                  sk_sp<GrTextureProxy> proxy, const GrSamplerParams& params,
-                                  DistanceAdjust wa, uint32_t flags,
+    GrDistanceFieldLCDTextGeoProc(GrColor, const SkMatrix& viewMatrix, sk_sp<GrTextureProxy> proxy,
+                                  const GrSamplerState& params, DistanceAdjust wa, uint32_t flags,
                                   bool usesLocalCoords);
 
     GrColor          fColor;
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index ed2734b..3301694 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -88,16 +88,11 @@
         GrProcessorTestData* testData) {
     int texIdx = testData->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
                                                : GrProcessorUnitTest::kAlphaTextureIdx;
-    static const SkShader::TileMode kTileModes[] = {
-            SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode,
-    };
-    SkShader::TileMode tileModes[] = {
-            kTileModes[testData->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
-            kTileModes[testData->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
-    };
-    GrSamplerParams params(tileModes, testData->fRandom->nextBool()
-                                              ? GrSamplerParams::kBilerp_FilterMode
-                                              : GrSamplerParams::kNone_FilterMode);
+    GrSamplerState::WrapMode wrapModes[2];
+    GrTest::TestWrapModes(testData->fRandom, wrapModes);
+    GrSamplerState params(wrapModes, testData->fRandom->nextBool()
+                                             ? GrSamplerState::Filter::kBilerp
+                                             : GrSamplerState::Filter::kNearest);
 
     const SkMatrix& matrix = GrTest::TestMatrix(testData->fRandom);
     sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(testData->fRandom);
diff --git a/src/gpu/effects/GrSimpleTextureEffect.fp b/src/gpu/effects/GrSimpleTextureEffect.fp
index 80824fe..a4275b5 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.fp
+++ b/src/gpu/effects/GrSimpleTextureEffect.fp
@@ -10,7 +10,7 @@
 in float4x4 matrix;
 
 @constructorParams {
-    GrSamplerParams samplerParams
+    GrSamplerState samplerParams
 }
 
 @coordTransform(image) {
@@ -27,23 +27,23 @@
                                                      const SkMatrix& matrix) {
         return std::unique_ptr<GrFragmentProcessor>(
             new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix,
-                    GrSamplerParams(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode)));
+                    GrSamplerState(GrSamplerState::WrapMode::kClamp, GrSamplerState::Filter::kNearest)));
     }
 
     /* clamp mode */
     static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
                                                      sk_sp<GrColorSpaceXform> colorSpaceXform,
                                                      const SkMatrix& matrix,
-                                                     GrSamplerParams::FilterMode filterMode) {
+                                                     GrSamplerState::Filter filter) {
         return std::unique_ptr<GrFragmentProcessor>(
             new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix,
-                                      GrSamplerParams(SkShader::kClamp_TileMode, filterMode)));
+                                      GrSamplerState(GrSamplerState::WrapMode::kClamp, filter)));
      }
 
     static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
                                                      sk_sp<GrColorSpaceXform> colorSpaceXform,
                                                      const SkMatrix& matrix,
-                                                     const GrSamplerParams& p) {
+                                                     const GrSamplerState& p) {
         return std::unique_ptr<GrFragmentProcessor>(
             new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix, p));
     }
@@ -62,18 +62,11 @@
 @test(testData) {
     int texIdx = testData->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
                                                : GrProcessorUnitTest::kAlphaTextureIdx;
-    static const SkShader::TileMode kTileModes[] = {
-        SkShader::kClamp_TileMode,
-        SkShader::kRepeat_TileMode,
-        SkShader::kMirror_TileMode,
-    };
-    SkShader::TileMode tileModes[] = {
-        kTileModes[testData->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
-        kTileModes[testData->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
-    };
-    GrSamplerParams params(tileModes, testData->fRandom->nextBool()
-                                                               ? GrSamplerParams::kBilerp_FilterMode
-                                                               : GrSamplerParams::kNone_FilterMode);
+    GrSamplerState::WrapMode wrapModes[2];
+    GrTest::TestWrapModes(testData->fRandom, wrapModes);
+    GrSamplerState params(wrapModes, testData->fRandom->nextBool()
+                                                               ? GrSamplerState::Filter::kBilerp
+                                                               : GrSamplerState::Filter::kNearest);
 
     const SkMatrix& matrix = GrTest::TestMatrix(testData->fRandom);
     sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(testData->fRandom);
diff --git a/src/gpu/effects/GrSimpleTextureEffect.h b/src/gpu/effects/GrSimpleTextureEffect.h
index 11564bb..8d3fba1 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.h
+++ b/src/gpu/effects/GrSimpleTextureEffect.h
@@ -24,26 +24,27 @@
                                                      sk_sp<GrColorSpaceXform>
                                                              colorSpaceXform,
                                                      const SkMatrix& matrix) {
-        return std::unique_ptr<GrFragmentProcessor>(new GrSimpleTextureEffect(
-                std::move(proxy), std::move(colorSpaceXform), matrix,
-                GrSamplerParams(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode)));
-    }
-
-    static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
-                                                     sk_sp<GrColorSpaceXform>
-                                                             colorSpaceXform,
-                                                     const SkMatrix& matrix,
-                                                     GrSamplerParams::FilterMode filterMode) {
         return std::unique_ptr<GrFragmentProcessor>(
                 new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix,
-                                          GrSamplerParams(SkShader::kClamp_TileMode, filterMode)));
+                                          GrSamplerState(GrSamplerState::WrapMode::kClamp,
+                                                         GrSamplerState::Filter::kNearest)));
     }
 
     static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
                                                      sk_sp<GrColorSpaceXform>
                                                              colorSpaceXform,
                                                      const SkMatrix& matrix,
-                                                     const GrSamplerParams& p) {
+                                                     GrSamplerState::Filter filter) {
+        return std::unique_ptr<GrFragmentProcessor>(new GrSimpleTextureEffect(
+                std::move(proxy), std::move(colorSpaceXform), matrix,
+                GrSamplerState(GrSamplerState::WrapMode::kClamp, filter)));
+    }
+
+    static std::unique_ptr<GrFragmentProcessor> Make(sk_sp<GrTextureProxy> proxy,
+                                                     sk_sp<GrColorSpaceXform>
+                                                             colorSpaceXform,
+                                                     const SkMatrix& matrix,
+                                                     const GrSamplerState& p) {
         return std::unique_ptr<GrFragmentProcessor>(
                 new GrSimpleTextureEffect(std::move(proxy), std::move(colorSpaceXform), matrix, p));
     }
@@ -53,7 +54,7 @@
 
 private:
     GrSimpleTextureEffect(sk_sp<GrTextureProxy> image, sk_sp<GrColorSpaceXform> colorXform,
-                          SkMatrix44 matrix, GrSamplerParams samplerParams)
+                          SkMatrix44 matrix, GrSamplerState samplerParams)
             : INHERITED((OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag |
                         (GrPixelConfigIsOpaque(image->config())
                                  ? kPreservesOpaqueInput_OptimizationFlag
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
index 5101762..3bb96b2 100644
--- a/src/gpu/effects/GrTextureDomain.cpp
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -212,7 +212,7 @@
         const SkMatrix& matrix,
         const SkRect& domain,
         GrTextureDomain::Mode mode,
-        GrSamplerParams::FilterMode filterMode) {
+        GrSamplerState::Filter filterMode) {
     if (GrTextureDomain::kIgnore_Mode == mode ||
         (GrTextureDomain::kClamp_Mode == mode && can_ignore_rect(proxy.get(), domain))) {
         return GrSimpleTextureEffect::Make(std::move(proxy),
@@ -228,14 +228,14 @@
                                              const SkMatrix& matrix,
                                              const SkRect& domain,
                                              GrTextureDomain::Mode mode,
-                                             GrSamplerParams::FilterMode filterMode)
+                                             GrSamplerState::Filter filterMode)
         : INHERITED(OptFlags(proxy->config(), mode))
         , fCoordTransform(matrix, proxy.get())
         , fTextureDomain(proxy.get(), domain, mode)
         , fTextureSampler(std::move(proxy), filterMode)
         , fColorSpaceXform(std::move(colorSpaceXform)) {
     SkASSERT(mode != GrTextureDomain::kRepeat_Mode ||
-             filterMode == GrSamplerParams::kNone_FilterMode);
+             filterMode == GrSamplerState::Filter::kNearest);
     this->initClassID<GrTextureDomainEffect>();
     this->addCoordTransform(&fCoordTransform);
     this->addTextureSampler(&fTextureSampler);
@@ -325,13 +325,13 @@
     const SkMatrix& matrix = GrTest::TestMatrix(d->fRandom);
     bool bilerp = mode != GrTextureDomain::kRepeat_Mode ? d->fRandom->nextBool() : false;
     sk_sp<GrColorSpaceXform> colorSpaceXform = GrTest::TestColorXform(d->fRandom);
-    return GrTextureDomainEffect::Make(std::move(proxy),
-                                       std::move(colorSpaceXform),
-                                       matrix,
-                                       domain,
-                                       mode,
-                                       bilerp ? GrSamplerParams::kBilerp_FilterMode
-                                              : GrSamplerParams::kNone_FilterMode);
+    return GrTextureDomainEffect::Make(
+            std::move(proxy),
+            std::move(colorSpaceXform),
+            matrix,
+            domain,
+            mode,
+            bilerp ? GrSamplerState::Filter::kBilerp : GrSamplerState::Filter::kNearest);
 }
 #endif
 
@@ -343,11 +343,9 @@
 }
 
 GrDeviceSpaceTextureDecalFragmentProcessor::GrDeviceSpaceTextureDecalFragmentProcessor(
-                    sk_sp<GrTextureProxy> proxy,
-                    const SkIRect& subset,
-                    const SkIPoint& deviceSpaceOffset)
+        sk_sp<GrTextureProxy> proxy, const SkIRect& subset, const SkIPoint& deviceSpaceOffset)
         : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
-        , fTextureSampler(proxy, GrSamplerParams::ClampNoFilter())
+        , fTextureSampler(proxy, GrSamplerState::ClampNearest())
         , fTextureDomain(proxy.get(), GrTextureDomain::MakeTexelDomain(subset),
                          GrTextureDomain::kDecal_Mode) {
     this->addTextureSampler(&fTextureSampler);
diff --git a/src/gpu/effects/GrTextureDomain.h b/src/gpu/effects/GrTextureDomain.h
index 0db7d2c..ec0ef4e 100644
--- a/src/gpu/effects/GrTextureDomain.h
+++ b/src/gpu/effects/GrTextureDomain.h
@@ -158,7 +158,7 @@
                                                      const SkMatrix&,
                                                      const SkRect& domain,
                                                      GrTextureDomain::Mode,
-                                                     GrSamplerParams::FilterMode filterMode);
+                                                     GrSamplerState::Filter filterMode);
 
     const char* name() const override { return "TextureDomain"; }
 
@@ -186,7 +186,7 @@
                           const SkMatrix&,
                           const SkRect& domain,
                           GrTextureDomain::Mode,
-                          GrSamplerParams::FilterMode);
+                          GrSamplerState::Filter);
 
     explicit GrTextureDomainEffect(const GrTextureDomainEffect&);
 
diff --git a/src/gpu/effects/GrYUVEffect.cpp b/src/gpu/effects/GrYUVEffect.cpp
index 80e87c2..5bf4a75 100644
--- a/src/gpu/effects/GrYUVEffect.cpp
+++ b/src/gpu/effects/GrYUVEffect.cpp
@@ -79,13 +79,13 @@
             SkMatrix::MakeScale(w[1] / w[0], h[1] / h[0]),
             SkMatrix::MakeScale(w[2] / w[0], h[2] / h[0])
         };
-        GrSamplerParams::FilterMode uvFilterMode =
+        GrSamplerState::Filter uvFilterMode =
             ((sizes[1].fWidth  != sizes[0].fWidth) ||
              (sizes[1].fHeight != sizes[0].fHeight) ||
              (sizes[2].fWidth  != sizes[0].fWidth) ||
              (sizes[2].fHeight != sizes[0].fHeight)) ?
-            GrSamplerParams::kBilerp_FilterMode :
-            GrSamplerParams::kNone_FilterMode;
+            GrSamplerState::Filter::kBilerp :
+            GrSamplerState::Filter::kNearest;
         return std::unique_ptr<GrFragmentProcessor>(
                 new YUVtoRGBEffect(std::move(yProxy), std::move(uProxy), std::move(vProxy),
                                    yuvMatrix, uvFilterMode, colorSpace, nv12));
@@ -159,7 +159,7 @@
 private:
     YUVtoRGBEffect(sk_sp<GrTextureProxy> yProxy, sk_sp<GrTextureProxy> uProxy,
                    sk_sp<GrTextureProxy> vProxy, const SkMatrix yuvMatrix[3],
-                   GrSamplerParams::FilterMode uvFilterMode, SkYUVColorSpace colorSpace, bool nv12)
+                   GrSamplerState::Filter uvFilterMode, SkYUVColorSpace colorSpace, bool nv12)
             : INHERITED(kPreservesOpaqueInput_OptimizationFlag)
             , fYTransform(yuvMatrix[0], yProxy.get())
             , fYSampler(std::move(yProxy))
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index a127c37..29df888 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2879,17 +2879,17 @@
     }
 }
 
-static inline GrGLenum tile_to_gl_wrap(SkShader::TileMode tm) {
-    static const GrGLenum gWrapModes[] = {
-        GR_GL_CLAMP_TO_EDGE,
-        GR_GL_REPEAT,
-        GR_GL_MIRRORED_REPEAT
+static inline GrGLenum wrap_mode_to_gl_wrap(GrSamplerState::WrapMode wrapMode) {
+    switch (wrapMode) {
+        case GrSamplerState::WrapMode::kClamp:
+            return GR_GL_CLAMP_TO_EDGE;
+        case GrSamplerState::WrapMode::kRepeat:
+            return GR_GL_REPEAT;
+        case GrSamplerState::WrapMode::kMirrorRepeat:
+            return GR_GL_MIRRORED_REPEAT;
     };
-    GR_STATIC_ASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gWrapModes));
-    GR_STATIC_ASSERT(0 == SkShader::kClamp_TileMode);
-    GR_STATIC_ASSERT(1 == SkShader::kRepeat_TileMode);
-    GR_STATIC_ASSERT(2 == SkShader::kMirror_TileMode);
-    return gWrapModes[tm];
+    SK_ABORT("Unknown wrap mode");
+    return 0;
 }
 
 static GrGLenum get_component_enum_from_char(char component) {
@@ -2919,15 +2919,39 @@
     }
 }
 
-void GrGLGpu::bindTexture(int unitIdx, const GrSamplerParams& params, bool allowSRGBInputs,
+static GrGLenum filter_to_gl_mag_filter(GrSamplerState::Filter filter) {
+    switch (filter) {
+        case GrSamplerState::Filter::kNearest:
+            return GR_GL_NEAREST;
+        case GrSamplerState::Filter::kBilerp:
+            return GR_GL_LINEAR;
+        case GrSamplerState::Filter::kMipMap:
+            return GR_GL_LINEAR;
+    }
+    SK_ABORT("Unknown filter");
+    return 0;
+}
+
+static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter) {
+    switch (filter) {
+        case GrSamplerState::Filter::kNearest:
+            return GR_GL_NEAREST;
+        case GrSamplerState::Filter::kBilerp:
+            return GR_GL_LINEAR;
+        case GrSamplerState::Filter::kMipMap:
+            return GR_GL_LINEAR_MIPMAP_LINEAR;
+    }
+    SK_ABORT("Unknown filter");
+    return 0;
+}
+
+void GrGLGpu::bindTexture(int unitIdx, const GrSamplerState& samplerState, bool allowSRGBInputs,
                           GrGLTexture* texture, GrSurfaceOrigin textureOrigin) {
     SkASSERT(texture);
 
 #ifdef SK_DEBUG
     if (!this->caps()->npotTextureTileSupport()) {
-        const bool tileX = SkShader::kClamp_TileMode != params.getTileModeX();
-        const bool tileY = SkShader::kClamp_TileMode != params.getTileModeY();
-        if (tileX || tileY) {
+        if (samplerState.isRepeated()) {
             const int w = texture->width();
             const int h = texture->height();
             SkASSERT(SkIsPow2(w) && SkIsPow2(h));
@@ -2956,26 +2980,16 @@
     bool setAll = timestamp < this->getResetTimestamp();
     GrGLTexture::TexParams newTexParams;
 
-    static GrGLenum glMinFilterModes[] = {
-        GR_GL_NEAREST,
-        GR_GL_LINEAR,
-        GR_GL_LINEAR_MIPMAP_LINEAR
-    };
-    static GrGLenum glMagFilterModes[] = {
-        GR_GL_NEAREST,
-        GR_GL_LINEAR,
-        GR_GL_LINEAR
-    };
-    GrSamplerParams::FilterMode filterMode = params.filterMode();
+    GrSamplerState::Filter filterMode = samplerState.filter();
 
-    if (GrSamplerParams::kMipMap_FilterMode == filterMode) {
+    if (GrSamplerState::Filter::kMipMap == filterMode) {
         if (!this->caps()->mipMapSupport()) {
-            filterMode = GrSamplerParams::kBilerp_FilterMode;
+            filterMode = GrSamplerState::Filter::kBilerp;
         }
     }
 
-    newTexParams.fMinFilter = glMinFilterModes[filterMode];
-    newTexParams.fMagFilter = glMagFilterModes[filterMode];
+    newTexParams.fMinFilter = filter_to_gl_min_filter(filterMode);
+    newTexParams.fMagFilter = filter_to_gl_mag_filter(filterMode);
 
     if (this->glCaps().srgbDecodeDisableSupport() && GrPixelConfigIsSRGB(texture->config())) {
         newTexParams.fSRGBDecode = allowSRGBInputs ? GR_GL_DECODE_EXT : GR_GL_SKIP_DECODE_EXT;
@@ -2987,7 +3001,7 @@
 
 #ifdef SK_DEBUG
     // We were supposed to ensure MipMaps were up-to-date and built correctly before getting here.
-    if (GrSamplerParams::kMipMap_FilterMode == filterMode) {
+    if (GrSamplerState::Filter::kMipMap == filterMode) {
         SkASSERT(!texture->texturePriv().mipMapsAreDirty());
         if (GrPixelConfigIsSRGB(texture->config())) {
             SkDestinationSurfaceColorMode colorMode = allowSRGBInputs
@@ -3000,8 +3014,8 @@
 
     newTexParams.fMaxMipMapLevel = texture->texturePriv().maxMipMapLevel();
 
-    newTexParams.fWrapS = tile_to_gl_wrap(params.getTileModeX());
-    newTexParams.fWrapT = tile_to_gl_wrap(params.getTileModeY());
+    newTexParams.fWrapS = wrap_mode_to_gl_wrap(samplerState.wrapModeX());
+    newTexParams.fWrapT = wrap_mode_to_gl_wrap(samplerState.wrapModeY());
     get_tex_param_swizzle(texture->config(), this->glCaps(), newTexParams.fSwizzleRGBA);
     if (setAll || newTexParams.fMagFilter != oldTexParams.fMagFilter) {
         this->setTextureUnit(unitIdx);
@@ -3107,20 +3121,20 @@
     }
 }
 
-void GrGLGpu::generateMipmaps(const GrSamplerParams& params, bool allowSRGBInputs,
+void GrGLGpu::generateMipmaps(const GrSamplerState& params, bool allowSRGBInputs,
                               GrGLTexture* texture, GrSurfaceOrigin textureOrigin) {
     SkASSERT(texture);
 
     // First, figure out if we need mips for this texture at all:
-    GrSamplerParams::FilterMode filterMode = params.filterMode();
+    GrSamplerState::Filter filterMode = params.filter();
 
-    if (GrSamplerParams::kMipMap_FilterMode == filterMode) {
+    if (GrSamplerState::Filter::kMipMap == filterMode) {
         if (!this->caps()->mipMapSupport()) {
-            filterMode = GrSamplerParams::kBilerp_FilterMode;
+            filterMode = GrSamplerState::Filter::kBilerp;
         }
     }
 
-    if (GrSamplerParams::kMipMap_FilterMode != filterMode) {
+    if (GrSamplerState::Filter::kMipMap != filterMode) {
         return;
     }
 
@@ -3841,8 +3855,7 @@
     int w = srcRect.width();
     int h = srcRect.height();
 
-    GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
-    this->bindTexture(0, params, true, srcTex, srcOrigin);
+    this->bindTexture(0, GrSamplerState::ClampNearest(), true, srcTex, srcOrigin);
 
     GrGLIRect dstVP;
     this->bindSurfaceFBOForPixelOps(dst, GR_GL_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget);
@@ -4067,8 +4080,7 @@
     // Bind the texture, to get things configured for filtering.
     // We'll be changing our base level further below:
     this->setTextureUnit(0);
-    GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
-    this->bindTexture(0, params, gammaCorrect, texture, textureOrigin);
+    this->bindTexture(0, GrSamplerState::ClampBilerp(), gammaCorrect, texture, textureOrigin);
 
     // Vertex data:
     if (!fMipmapProgramArrayBuffer) {
@@ -4297,7 +4309,7 @@
 }
 
 bool GrGLGpu::onIsACopyNeededForTextureParams(GrTextureProxy* proxy,
-                                              const GrSamplerParams& textureParams,
+                                              const GrSamplerState& textureParams,
                                               GrTextureProducer::CopyParams* copyParams,
                                               SkScalar scaleAdjust[2]) const {
     const GrTexture* texture = proxy->priv().peekTexture();
@@ -4307,12 +4319,11 @@
         return false;
     }
 
-    if (textureParams.isTiled() ||
-        GrSamplerParams::kMipMap_FilterMode == textureParams.filterMode()) {
+    if (textureParams.isRepeated() || GrSamplerState::Filter::kMipMap == textureParams.filter()) {
         const GrGLTexture* glTexture = static_cast<const GrGLTexture*>(texture);
         if (GR_GL_TEXTURE_EXTERNAL == glTexture->target() ||
             GR_GL_TEXTURE_RECTANGLE == glTexture->target()) {
-            copyParams->fFilter = GrSamplerParams::kNone_FilterMode;
+            copyParams->fFilter = GrSamplerState::Filter::kNearest;
             copyParams->fWidth = texture->width();
             copyParams->fHeight = texture->height();
             return true;
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index 479217e..000b565 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -59,15 +59,15 @@
     }
 
     // Used by GrGLProgram to configure OpenGL state.
-    void bindTexture(int unitIdx, const GrSamplerParams& params, bool allowSRGBInputs,
+    void bindTexture(int unitIdx, const GrSamplerState& samplerState, bool allowSRGBInputs,
                      GrGLTexture* texture, GrSurfaceOrigin textureOrigin);
 
     void bindTexelBuffer(int unitIdx, GrPixelConfig, GrGLBuffer*);
 
     void bindImageStorage(int unitIdx, GrIOType, GrGLTexture *);
 
-    void generateMipmaps(const GrSamplerParams& params, bool allowSRGBInputs,
-                         GrGLTexture* texture, GrSurfaceOrigin textureOrigin);
+    void generateMipmaps(const GrSamplerState& params, bool allowSRGBInputs, GrGLTexture* texture,
+                         GrSurfaceOrigin textureOrigin);
 
     bool onGetReadPixelsInfo(GrSurface* srcSurface, GrSurfaceOrigin srcOrigin,
                              int readWidth, int readHeight, size_t rowBytes,
@@ -226,7 +226,7 @@
                            bool renderTarget, GrGLTexture::TexParams* initialTexParams,
                            const GrMipLevel texels[], int mipLevelCount);
 
-    bool onIsACopyNeededForTextureParams(GrTextureProxy*, const GrSamplerParams&,
+    bool onIsACopyNeededForTextureParams(GrTextureProxy*, const GrSamplerState&,
                                          GrTextureProducer::CopyParams*,
                                          SkScalar scaleAdjust[2]) const override;
 
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index f7e337c..04b2138a 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -96,7 +96,7 @@
 
     fXferProcessor->setData(fProgramDataManager, xp, dstTexture, offset);
     if (dstTexture) {
-        fGpu->bindTexture(nextTexSamplerIdx++, GrSamplerParams::ClampNoFilter(), true,
+        fGpu->bindTexture(nextTexSamplerIdx++, GrSamplerState::ClampNearest(), true,
                           static_cast<GrGLTexture*>(dstTexture),
                           pipeline.dstTextureProxy()->origin());
     }
@@ -172,8 +172,8 @@
                                int* nextImageStorageIdx) {
     for (int i = 0; i < processor.numTextureSamplers(); ++i) {
         const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i);
-        fGpu->bindTexture((*nextTexSamplerIdx)++, sampler.params(),
-                          allowSRGBInputs, static_cast<GrGLTexture*>(sampler.peekTexture()),
+        fGpu->bindTexture((*nextTexSamplerIdx)++, sampler.samplerState(), allowSRGBInputs,
+                          static_cast<GrGLTexture*>(sampler.peekTexture()),
                           sampler.proxy()->origin());
     }
     for (int i = 0; i < processor.numBuffers(); ++i) {
@@ -191,7 +191,7 @@
 void GrGLProgram::generateMipmaps(const GrResourceIOProcessor& processor, bool allowSRGBInputs) {
     for (int i = 0; i < processor.numTextureSamplers(); ++i) {
         const GrResourceIOProcessor::TextureSampler& sampler = processor.textureSampler(i);
-        fGpu->generateMipmaps(sampler.params(), allowSRGBInputs,
+        fGpu->generateMipmaps(sampler.samplerState(), allowSRGBInputs,
                               static_cast<GrGLTexture*>(sampler.peekTexture()),
                               sampler.proxy()->origin());
     }
diff --git a/src/gpu/gl/GrGLTexture.cpp b/src/gpu/gl/GrGLTexture.cpp
index b8497bd..0d71321 100644
--- a/src/gpu/gl/GrGLTexture.cpp
+++ b/src/gpu/gl/GrGLTexture.cpp
@@ -33,18 +33,18 @@
 }
 
 // This method parallels GrTextureProxy::highestFilterMode
-static inline GrSamplerParams::FilterMode highest_filter_mode(const GrGLTexture::IDDesc& idDesc,
-                                                              GrPixelConfig config) {
+static inline GrSamplerState::Filter highest_filter_mode(const GrGLTexture::IDDesc& idDesc,
+                                                         GrPixelConfig config) {
     if (GrPixelConfigIsSint(config)) {
         // Integer textures in GL can use GL_NEAREST_MIPMAP_NEAREST. This is a mode we don't support
         // and don't currently have a use for.
-        return GrSamplerParams::kNone_FilterMode;
+        return GrSamplerState::Filter::kNearest;
     }
     if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_RECTANGLE ||
         idDesc.fInfo.fTarget == GR_GL_TEXTURE_EXTERNAL) {
-        return GrSamplerParams::kBilerp_FilterMode;
+        return GrSamplerState::Filter::kBilerp;
     }
-    return GrSamplerParams::kMipMap_FilterMode;
+    return GrSamplerState::Filter::kMipMap;
 }
 
 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
diff --git a/src/gpu/mock/GrMockTexture.h b/src/gpu/mock/GrMockTexture.h
index a3bad02..c5c2102 100644
--- a/src/gpu/mock/GrMockTexture.h
+++ b/src/gpu/mock/GrMockTexture.h
@@ -39,7 +39,7 @@
     GrMockTexture(GrMockGpu* gpu, const GrSurfaceDesc& desc, bool hasMipLevels,
                   const GrMockTextureInfo& info)
             : GrSurface(gpu, desc)
-            , INHERITED(gpu, desc, kITexture2DSampler_GrSLType, GrSamplerParams::kMipMap_FilterMode,
+            , INHERITED(gpu, desc, kITexture2DSampler_GrSLType, GrSamplerState::Filter::kMipMap,
                         hasMipLevels)
             , fInfo(info)
             , fReleaseProc(nullptr)
diff --git a/src/gpu/ops/GrAtlasTextOp.cpp b/src/gpu/ops/GrAtlasTextOp.cpp
index f0681a6..bfdbfdb 100644
--- a/src/gpu/ops/GrAtlasTextOp.cpp
+++ b/src/gpu/ops/GrAtlasTextOp.cpp
@@ -100,10 +100,9 @@
                 this->setupDfProcessor(this->viewMatrix(),
                                        fLuminanceColor, this->color(), std::move(proxy));
     } else {
-        GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
-        flushInfo.fGeometryProcessor =
-                GrBitmapTextGeoProc::Make(this->color(), std::move(proxy), params, maskFormat,
-                                          localMatrix, this->usesLocalCoords());
+        flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
+                this->color(), std::move(proxy), GrSamplerState::ClampNearest(), maskFormat,
+                localMatrix, this->usesLocalCoords());
     }
 
     flushInfo.fGlyphsToFlush = 0;
@@ -223,7 +222,6 @@
                                                            SkColor luminanceColor,
                                                            GrColor color,
                                                            sk_sp<GrTextureProxy> proxy) const {
-    GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
     bool isLCD = this->isLCD();
     // set up any flags
     uint32_t flags = viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
@@ -249,8 +247,9 @@
                 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(
                         redCorrection, greenCorrection, blueCorrection);
 
-        return GrDistanceFieldLCDTextGeoProc::Make(color, viewMatrix, std::move(proxy), params,
-                                                   widthAdjust, flags, this->usesLocalCoords());
+        return GrDistanceFieldLCDTextGeoProc::Make(color, viewMatrix, std::move(proxy),
+                                                   GrSamplerState::ClampBilerp(), widthAdjust,
+                                                   flags, this->usesLocalCoords());
     } else {
 #ifdef SK_GAMMA_APPLY_TO_A8
         float correction = 0;
@@ -259,12 +258,13 @@
             correction = fDistanceAdjustTable->getAdjustment(lum >> kDistanceAdjustLumShift,
                                                              fUseGammaCorrectDistanceTable);
         }
-        return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, std::move(proxy), params,
-                                                  correction, flags, this->usesLocalCoords());
+        return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, std::move(proxy),
+                                                  GrSamplerState::ClampBilerp(), correction, flags,
+                                                  this->usesLocalCoords());
 #else
-        return GrDistanceFieldA8TextGeoProc::Make(color,
-                                                  viewMatrix, std::move(proxy),
-                                                  params, flags, this->usesLocalCoords());
+        return GrDistanceFieldA8TextGeoProc::Make(color, viewMatrix, std::move(proxy),
+                                                  GrSamplerState::ClampBilerp(), flags,
+                                                  this->usesLocalCoords());
 #endif
     }
 }
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index 7e7a496..cfdf873 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -225,19 +225,15 @@
         // Setup GrGeometryProcessor
         GrDrawOpAtlas* atlas = fAtlas;
         if (fUsesDistanceField) {
-            GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kBilerp_FilterMode);
-
             uint32_t flags = 0;
             flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
             flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
             flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0;
 
             flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make(
-                    this->color(), this->viewMatrix(), atlas->getProxy(), params, flags,
-                    fHelper.usesLocalCoords());
+                    this->color(), this->viewMatrix(), atlas->getProxy(),
+                    GrSamplerState::ClampBilerp(), flags, fHelper.usesLocalCoords());
         } else {
-            GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
-
             SkMatrix invert;
             if (fHelper.usesLocalCoords()) {
                 if (!this->viewMatrix().invert(&invert)) {
@@ -249,9 +245,9 @@
                 invert.preTranslate(-fShapes[0].fTranslate.fX, -fShapes[0].fTranslate.fY);
             }
 
-            flushInfo.fGeometryProcessor =
-                    GrBitmapTextGeoProc::Make(this->color(), atlas->getProxy(), params,
-                                              kA8_GrMaskFormat, invert, fHelper.usesLocalCoords());
+            flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
+                    this->color(), atlas->getProxy(), GrSamplerState::ClampNearest(),
+                    kA8_GrMaskFormat, invert, fHelper.usesLocalCoords());
         }
 
         // allocate vertices
diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp
index e16472a..3cb4dc0 100644
--- a/src/gpu/ops/GrTextureOp.cpp
+++ b/src/gpu/ops/GrTextureOp.cpp
@@ -37,7 +37,7 @@
     };
     static sk_sp<GrGeometryProcessor> Make(sk_sp<GrTextureProxy> proxy,
                                            sk_sp<GrColorSpaceXform> csxf,
-                                           GrSamplerParams::FilterMode filter) {
+                                           GrSamplerState::Filter filter) {
         return sk_sp<TextureGeometryProcessor>(
                 new TextureGeometryProcessor(std::move(proxy), std::move(csxf), filter));
     }
@@ -100,7 +100,7 @@
 
 private:
     TextureGeometryProcessor(sk_sp<GrTextureProxy> proxy, sk_sp<GrColorSpaceXform> csxf,
-                             GrSamplerParams::FilterMode filter)
+                             GrSamplerState::Filter filter)
             : fSampler(std::move(proxy), filter), fColorSpaceXform(std::move(csxf)) {
         this->initClassID<TextureGeometryProcessor>();
         fPositions =
@@ -125,7 +125,7 @@
 class TextureOp final : public GrMeshDrawOp {
 public:
     static std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy> proxy,
-                                          GrSamplerParams::FilterMode filter, GrColor color,
+                                          GrSamplerState::Filter filter, GrColor color,
                                           const SkRect srcRect, const SkRect dstRect,
                                           const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> csxf,
                                           bool allowSRBInputs) {
@@ -140,7 +140,8 @@
 
     SkString dumpInfo() const override {
         SkString str;
-        str.appendf("Filter: %d AllowSRGBInputs: %d\n", fFilter, fAllowSRGBInputs);
+        str.appendf("Filter: %d AllowSRGBInputs: %d\n", static_cast<int>(fFilter),
+                    fAllowSRGBInputs);
         str.appendf("# draws: %d\n", fDraws.count());
         for (int i = 0; i < fDraws.count(); ++i) {
             const Draw& draw = fDraws[i];
@@ -170,7 +171,7 @@
     DEFINE_OP_CLASS_ID
 
 private:
-    TextureOp(sk_sp<GrTextureProxy> proxy, GrSamplerParams::FilterMode filter, GrColor color,
+    TextureOp(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter, GrColor color,
               const SkRect& srcRect, const SkRect& dstRect, const SkMatrix& viewMatrix,
               sk_sp<GrColorSpaceXform> csxf, bool allowSRGBInputs)
             : INHERITED(ClassID())
@@ -298,7 +299,7 @@
     };
     SkSTArray<1, Draw, true> fDraws;
     GrTextureProxy* fProxy;
-    GrSamplerParams::FilterMode fFilter;
+    GrSamplerState::Filter fFilter;
     sk_sp<GrColorSpaceXform> fColorSpaceXform;
     // Used to track whether fProxy is ref'ed or has a pending IO after finalize() is called.
     bool fFinalized : 1;
@@ -310,7 +311,7 @@
 
 namespace GrTextureOp {
 
-std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy> proxy, GrSamplerParams::FilterMode filter,
+std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter,
                                GrColor color, const SkRect& srcRect, const SkRect& dstRect,
                                const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> csxf,
                                bool allowSRGBInputs) {
@@ -341,8 +342,8 @@
     srcRect.fBottom = random->nextRangeScalar(0.f, proxy->height()) + proxy->height() / 2.f;
     SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
     GrColor color = SkColorToPremulGrColor(random->nextU());
-    GrSamplerParams::FilterMode filter = (GrSamplerParams::FilterMode)random->nextULessThan(
-            GrSamplerParams::kMipMap_FilterMode + 1);
+    GrSamplerState::Filter filter = (GrSamplerState::Filter)random->nextULessThan(
+            static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
     auto csxf = GrTest::TestColorXform(random);
     bool allowSRGBInputs = random->nextBool();
     return GrTextureOp::Make(std::move(proxy), filter, color, srcRect, rect, viewMatrix,
diff --git a/src/gpu/ops/GrTextureOp.h b/src/gpu/ops/GrTextureOp.h
index cf6a227..2aea02e 100644
--- a/src/gpu/ops/GrTextureOp.h
+++ b/src/gpu/ops/GrTextureOp.h
@@ -7,7 +7,7 @@
 
 #include "GrColor.h"
 #include "GrColorSpaceXform.h"
-#include "GrSamplerParams.h"
+#include "GrSamplerState.h"
 
 class GrDrawOp;
 class GrTextureProxy;
@@ -21,7 +21,7 @@
  * the rectangle to draw in local coords which will be transformed by 'viewMatrix' to be in device
  * space. 'viewMatrix' must be affine.
  */
-std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy>, GrSamplerParams::FilterMode, GrColor,
+std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy>, GrSamplerState::Filter, GrColor,
                                const SkRect& srcRect, const SkRect& dstRect,
                                const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform>,
                                bool allowSRGBInputs);
diff --git a/src/gpu/vk/GrVkCopyManager.cpp b/src/gpu/vk/GrVkCopyManager.cpp
index 9e1decf..2b54d37 100644
--- a/src/gpu/vk/GrVkCopyManager.cpp
+++ b/src/gpu/vk/GrVkCopyManager.cpp
@@ -7,7 +7,7 @@
 
 #include "GrVkCopyManager.h"
 
-#include "GrSamplerParams.h"
+#include "GrSamplerState.h"
 #include "GrShaderCaps.h"
 #include "GrSurface.h"
 #include "GrTexturePriv.h"
@@ -259,10 +259,10 @@
     const GrVkDescriptorSet* samplerDS =
         gpu->resourceProvider().getSamplerDescriptorSet(fSamplerDSHandle);
 
-    GrSamplerParams params(SkShader::kClamp_TileMode, GrSamplerParams::kNone_FilterMode);
+    GrSamplerState samplerState = GrSamplerState::ClampNearest();
 
-    GrVkSampler* sampler =
-        resourceProv.findOrCreateCompatibleSampler(params, srcTex->texturePriv().maxMipMapLevel());
+    GrVkSampler* sampler = resourceProv.findOrCreateCompatibleSampler(
+            samplerState, srcTex->texturePriv().maxMipMapLevel());
 
     VkDescriptorImageInfo imageInfo;
     memset(&imageInfo, 0, sizeof(VkDescriptorImageInfo));
diff --git a/src/gpu/vk/GrVkGpuCommandBuffer.cpp b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
index 15fdf4a..e6eb4c3 100644
--- a/src/gpu/vk/GrVkGpuCommandBuffer.cpp
+++ b/src/gpu/vk/GrVkGpuCommandBuffer.cpp
@@ -566,9 +566,8 @@
             gpu->onResolveRenderTarget(texRT, sampler.proxy()->origin());
         }
 
-        const GrSamplerParams& params = sampler.params();
         // Check if we need to regenerate any mip maps
-        if (GrSamplerParams::kMipMap_FilterMode == params.filterMode()) {
+        if (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter()) {
             if (vkTexture->texturePriv().mipMapsAreDirty()) {
                 gpu->generateMipmap(vkTexture, sampler.proxy()->origin());
                 vkTexture->texturePriv().dirtyMipMaps(false);
diff --git a/src/gpu/vk/GrVkPipelineState.cpp b/src/gpu/vk/GrVkPipelineState.cpp
index ee24135..1719775 100644
--- a/src/gpu/vk/GrVkPipelineState.cpp
+++ b/src/gpu/vk/GrVkPipelineState.cpp
@@ -376,12 +376,12 @@
     SkASSERT(fNumSamplers == textureBindings.count());
 
     for (int i = 0; i < textureBindings.count(); ++i) {
-        const GrSamplerParams& params = textureBindings[i]->params();
+        GrSamplerState state = textureBindings[i]->samplerState();
 
         GrVkTexture* texture = static_cast<GrVkTexture*>(textureBindings[i]->peekTexture());
 
-        fSamplers.push(gpu->resourceProvider().findOrCreateCompatibleSampler(params,
-                                                          texture->texturePriv().maxMipMapLevel()));
+        fSamplers.push(gpu->resourceProvider().findOrCreateCompatibleSampler(
+                state, texture->texturePriv().maxMipMapLevel()));
 
         const GrVkResource* textureResource = texture->resource();
         textureResource->ref();
diff --git a/src/gpu/vk/GrVkResourceProvider.cpp b/src/gpu/vk/GrVkResourceProvider.cpp
index cfce75f..e0f6776 100644
--- a/src/gpu/vk/GrVkResourceProvider.cpp
+++ b/src/gpu/vk/GrVkResourceProvider.cpp
@@ -7,7 +7,7 @@
 
 #include "GrVkResourceProvider.h"
 
-#include "GrSamplerParams.h"
+#include "GrSamplerState.h"
 #include "GrVkCommandBuffer.h"
 #include "GrVkCopyPipeline.h"
 #include "GrVkGpu.h"
@@ -165,7 +165,7 @@
     return new GrVkDescriptorPool(fGpu, type, count);
 }
 
-GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrSamplerParams& params,
+GrVkSampler* GrVkResourceProvider::findOrCreateCompatibleSampler(const GrSamplerState& params,
                                                                  uint32_t maxMipLevel) {
     GrVkSampler* sampler = fSamplers.find(GrVkSampler::GenerateKey(params, maxMipLevel));
     if (!sampler) {
diff --git a/src/gpu/vk/GrVkResourceProvider.h b/src/gpu/vk/GrVkResourceProvider.h
index ba11c8d..f48590a 100644
--- a/src/gpu/vk/GrVkResourceProvider.h
+++ b/src/gpu/vk/GrVkResourceProvider.h
@@ -24,7 +24,7 @@
 
 class GrPipeline;
 class GrPrimitiveProcessor;
-class GrSamplerParams;
+class GrSamplerState;
 class GrVkCopyPipeline;
 class GrVkGpu;
 class GrVkPipeline;
@@ -96,9 +96,9 @@
     //       of our cache of GrVkDescriptorPools.
     GrVkDescriptorPool* findOrCreateCompatibleDescriptorPool(VkDescriptorType type, uint32_t count);
 
-    // Finds or creates a compatible GrVkSampler based on the GrSamplerParams.
+    // Finds or creates a compatible GrVkSampler based on the GrSamplerState.
     // The refcount is incremented and a pointer returned.
-    GrVkSampler* findOrCreateCompatibleSampler(const GrSamplerParams&, uint32_t maxMipLevel);
+    GrVkSampler* findOrCreateCompatibleSampler(const GrSamplerState&, uint32_t maxMipLevel);
 
     sk_sp<GrVkPipelineState> findOrCreateCompatiblePipelineState(const GrPipeline&,
                                                                  const GrPrimitiveProcessor&,
diff --git a/src/gpu/vk/GrVkSampler.cpp b/src/gpu/vk/GrVkSampler.cpp
index 740c14b..822817b 100644
--- a/src/gpu/vk/GrVkSampler.cpp
+++ b/src/gpu/vk/GrVkSampler.cpp
@@ -9,20 +9,21 @@
 
 #include "GrVkGpu.h"
 
-static inline VkSamplerAddressMode tile_to_vk_sampler_address(SkShader::TileMode tm) {
-    static const VkSamplerAddressMode gWrapModes[] = {
-        VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
-        VK_SAMPLER_ADDRESS_MODE_REPEAT,
-        VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT
-    };
-    GR_STATIC_ASSERT(SkShader::kTileModeCount == SK_ARRAY_COUNT(gWrapModes));
-    GR_STATIC_ASSERT(0 == SkShader::kClamp_TileMode);
-    GR_STATIC_ASSERT(1 == SkShader::kRepeat_TileMode);
-    GR_STATIC_ASSERT(2 == SkShader::kMirror_TileMode);
-    return gWrapModes[tm];
+static inline VkSamplerAddressMode wrap_mode_to_vk_sampler_address(
+        GrSamplerState::WrapMode wrapMode) {
+    switch (wrapMode) {
+        case GrSamplerState::WrapMode::kClamp:
+            return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
+        case GrSamplerState::WrapMode::kRepeat:
+            return VK_SAMPLER_ADDRESS_MODE_REPEAT;
+        case GrSamplerState::WrapMode::kMirrorRepeat:
+            return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
+    }
+    SK_ABORT("Unknown wrap mode.");
+    return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
 }
 
-GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrSamplerParams& params,
+GrVkSampler* GrVkSampler::Create(const GrVkGpu* gpu, const GrSamplerState& samplerState,
                                  uint32_t maxMipLevel) {
     static VkFilter vkMinFilterModes[] = {
         VK_FILTER_NEAREST,
@@ -40,11 +41,11 @@
     createInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
     createInfo.pNext = 0;
     createInfo.flags = 0;
-    createInfo.magFilter = vkMagFilterModes[params.filterMode()];
-    createInfo.minFilter = vkMinFilterModes[params.filterMode()];
+    createInfo.magFilter = vkMagFilterModes[static_cast<int>(samplerState.filter())];
+    createInfo.minFilter = vkMinFilterModes[static_cast<int>(samplerState.filter())];
     createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
-    createInfo.addressModeU = tile_to_vk_sampler_address(params.getTileModeX());
-    createInfo.addressModeV = tile_to_vk_sampler_address(params.getTileModeY());
+    createInfo.addressModeU = wrap_mode_to_vk_sampler_address(samplerState.wrapModeX());
+    createInfo.addressModeV = wrap_mode_to_vk_sampler_address(samplerState.wrapModeY());
     createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; // Shouldn't matter
     createInfo.mipLodBias = 0.0f;
     createInfo.anisotropyEnable = VK_FALSE;
@@ -57,7 +58,7 @@
     // level mip). If the filters weren't the same we could set min = 0 and max = 0.25 to force
     // the minFilter on mip level 0.
     createInfo.minLod = 0.0f;
-    bool useMipMaps = GrSamplerParams::kMipMap_FilterMode == params.filterMode() && maxMipLevel > 0;
+    bool useMipMaps = GrSamplerState::Filter::kMipMap == samplerState.filter() && maxMipLevel > 0;
     createInfo.maxLod = !useMipMaps ? 0.0f : (float)(maxMipLevel);
     createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
     createInfo.unnormalizedCoordinates = VK_FALSE;
@@ -68,7 +69,7 @@
                                                           nullptr,
                                                           &sampler));
 
-    return new GrVkSampler(sampler, GenerateKey(params, maxMipLevel));
+    return new GrVkSampler(sampler, GenerateKey(samplerState, maxMipLevel));
 }
 
 void GrVkSampler::freeGPUData(const GrVkGpu* gpu) const {
@@ -76,18 +77,18 @@
     GR_VK_CALL(gpu->vkInterface(), DestroySampler(gpu->device(), fSampler, nullptr));
 }
 
-uint16_t GrVkSampler::GenerateKey(const GrSamplerParams& params, uint32_t maxMipLevel) {
+uint16_t GrVkSampler::GenerateKey(const GrSamplerState& samplerState, uint32_t maxMipLevel) {
     const int kTileModeXShift = 2;
     const int kTileModeYShift = 4;
     const int kMipLevelShift = 6;
 
-    uint16_t key = params.filterMode();
+    uint16_t key = static_cast<uint16_t>(samplerState.filter());
 
-    SkASSERT(params.filterMode() <= 3);
-    key |= (params.getTileModeX() << kTileModeXShift);
+    SkASSERT(static_cast<int>(samplerState.filter()) <= 3);
+    key |= (static_cast<uint16_t>(samplerState.wrapModeX()) << kTileModeXShift);
 
     GR_STATIC_ASSERT(SkShader::kTileModeCount <= 4);
-    key |= (params.getTileModeY() << kTileModeYShift);
+    key |= (static_cast<uint16_t>(samplerState.wrapModeY()) << kTileModeYShift);
 
     SkASSERT(maxMipLevel < 1024);
     key |= (maxMipLevel << kMipLevelShift);
diff --git a/src/gpu/vk/GrVkSampler.h b/src/gpu/vk/GrVkSampler.h
index a413ea8..59a56e7 100644
--- a/src/gpu/vk/GrVkSampler.h
+++ b/src/gpu/vk/GrVkSampler.h
@@ -12,18 +12,18 @@
 
 #include "vk/GrVkDefines.h"
 
-class GrSamplerParams;
+class GrSamplerState;
 class GrVkGpu;
 
 
 class GrVkSampler : public GrVkResource {
 public:
-    static GrVkSampler* Create(const GrVkGpu* gpu, const GrSamplerParams&, uint32_t maxMipLevel);
+    static GrVkSampler* Create(const GrVkGpu* gpu, const GrSamplerState&, uint32_t maxMipLevel);
 
     VkSampler sampler() const { return fSampler; }
 
     // Helpers for hashing GrVkSampler
-    static uint16_t GenerateKey(const GrSamplerParams&, uint32_t maxMipLevel);
+    static uint16_t GenerateKey(const GrSamplerState&, uint32_t maxMipLevel);
 
     static const uint16_t& GetKey(const GrVkSampler& sampler) { return sampler.fKey; }
     static uint32_t Hash(const uint16_t& key) { return key; }
diff --git a/src/gpu/vk/GrVkTexture.cpp b/src/gpu/vk/GrVkTexture.cpp
index ce1d487..1049e53 100644
--- a/src/gpu/vk/GrVkTexture.cpp
+++ b/src/gpu/vk/GrVkTexture.cpp
@@ -18,12 +18,12 @@
 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
 
 // This method parallels GrTextureProxy::highestFilterMode
-static inline GrSamplerParams::FilterMode highest_filter_mode(GrPixelConfig config) {
+static inline GrSamplerState::Filter highest_filter_mode(GrPixelConfig config) {
     if (GrPixelConfigIsSint(config)) {
         // We only ever want to nearest-neighbor sample signed int textures.
-        return GrSamplerParams::kNone_FilterMode;
+        return GrSamplerState::Filter::kNearest;
     }
-    return GrSamplerParams::kMipMap_FilterMode;
+    return GrSamplerState::Filter::kMipMap;
 }
 
 // Because this class is virtually derived from GrSurface we must explicitly call its constructor.
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index 6500418..9db69f3 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -20,7 +20,7 @@
 
 #include <new>
 
-class GrSamplerParams;
+class GrSamplerState;
 class SkImageCacherator;
 
 enum {
@@ -48,7 +48,7 @@
 #if SK_SUPPORT_GPU
     virtual GrTextureProxy* peekProxy() const { return nullptr; }
     virtual sk_sp<GrTextureProxy> asTextureProxyRef() const { return nullptr; }
-    virtual sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerParams&,
+    virtual sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerState&,
                                                     SkColorSpace*, sk_sp<SkColorSpace>*,
                                                     SkScalar scaleAdjust[2]) const = 0;
     virtual sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const {
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index 3458075..d3a1865 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -110,7 +110,7 @@
 }
 
 sk_sp<GrTextureProxy> SkImage_Gpu::asTextureProxyRef(GrContext* context,
-                                                     const GrSamplerParams& params,
+                                                     const GrSamplerState& params,
                                                      SkColorSpace* dstColorSpace,
                                                      sk_sp<SkColorSpace>* texColorSpace,
                                                      SkScalar scaleAdjust[2]) const {
@@ -433,9 +433,8 @@
                                               SkAlphaType at, uint32_t id,
                                               SkColorSpace* dstColorSpace) {
     sk_sp<SkColorSpace> texColorSpace;
-    sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(GrSamplerParams::ClampNoFilter(),
-                                                                dstColorSpace,
-                                                                &texColorSpace, nullptr));
+    sk_sp<GrTextureProxy> proxy(maker->refTextureProxyForParams(
+            GrSamplerState::ClampNearest(), dstColorSpace, &texColorSpace, nullptr));
     if (!proxy) {
         return nullptr;
     }
@@ -480,11 +479,11 @@
     // Turn the codec image into a GrTextureProxy
     GrImageTextureMaker maker(context, codecImage.get(), kDisallow_CachingHint);
     sk_sp<SkColorSpace> texColorSpace;
-    GrSamplerParams params(SkShader::kClamp_TileMode,
-                           buildMips ? GrSamplerParams::kMipMap_FilterMode
-                                     : GrSamplerParams::kBilerp_FilterMode);
-    sk_sp<GrTextureProxy> proxy(maker.refTextureProxyForParams(params, dstColorSpace,
-                                                               &texColorSpace, nullptr));
+    GrSamplerState samplerState(
+            GrSamplerState::WrapMode::kClamp,
+            buildMips ? GrSamplerState::Filter::kMipMap : GrSamplerState::Filter::kBilerp);
+    sk_sp<GrTextureProxy> proxy(
+            maker.refTextureProxyForParams(samplerState, dstColorSpace, &texColorSpace, nullptr));
     if (!proxy) {
         return codecImage;
     }
diff --git a/src/image/SkImage_Gpu.h b/src/image/SkImage_Gpu.h
index 9c3517b..9cc28c3 100644
--- a/src/image/SkImage_Gpu.h
+++ b/src/image/SkImage_Gpu.h
@@ -40,7 +40,7 @@
     sk_sp<GrTextureProxy> asTextureProxyRef() const override {
         return fProxy;
     }
-    sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerParams&, SkColorSpace*,
+    sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerState&, SkColorSpace*,
                                             sk_sp<SkColorSpace>*,
                                             SkScalar scaleAdjust[2]) const override;
 
diff --git a/src/image/SkImage_Lazy.cpp b/src/image/SkImage_Lazy.cpp
index 14c8e19..41be5bf 100644
--- a/src/image/SkImage_Lazy.cpp
+++ b/src/image/SkImage_Lazy.cpp
@@ -24,7 +24,7 @@
 #include "GrImageTextureMaker.h"
 #include "GrResourceKey.h"
 #include "GrResourceProvider.h"
-#include "GrSamplerParams.h"
+#include "GrSamplerState.h"
 #include "GrYUVProvider.h"
 #include "SkGr.h"
 #endif
@@ -78,8 +78,9 @@
     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY,
                       CachingHint) const override;
 #if SK_SUPPORT_GPU
-    sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerParams&,
-                                            SkColorSpace*, sk_sp<SkColorSpace>*,
+    sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*,
+                                            const GrSamplerState&, SkColorSpace*,
+                                            sk_sp<SkColorSpace>*,
                                             SkScalar scaleAdjust[2]) const override;
 #endif
     SkData* onRefEncoded() const override;
@@ -613,7 +614,7 @@
 
 #if SK_SUPPORT_GPU
 sk_sp<GrTextureProxy> SkImage_Lazy::asTextureProxyRef(GrContext* context,
-                                                      const GrSamplerParams& params,
+                                                      const GrSamplerState& params,
                                                       SkColorSpace* dstColorSpace,
                                                       sk_sp<SkColorSpace>* texColorSpace,
                                                       SkScalar scaleAdjust[2]) const {
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 5b7e83f..bade1b6 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -88,8 +88,8 @@
     const SkBitmap* onPeekBitmap() const override { return &fBitmap; }
 
 #if SK_SUPPORT_GPU
-    sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerParams&,
-                                            SkColorSpace*, sk_sp<SkColorSpace>*,
+    sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerState&, SkColorSpace*,
+                                            sk_sp<SkColorSpace>*,
                                             SkScalar scaleAdjust[2]) const override;
 #endif
 
@@ -171,7 +171,7 @@
 
 #if SK_SUPPORT_GPU
 sk_sp<GrTextureProxy> SkImage_Raster::asTextureProxyRef(GrContext* context,
-                                                        const GrSamplerParams& params,
+                                                        const GrSamplerState& params,
                                                         SkColorSpace* dstColorSpace,
                                                         sk_sp<SkColorSpace>* texColorSpace,
                                                         SkScalar scaleAdjust[2]) const {
@@ -215,8 +215,8 @@
     } else {
         SkASSERT(fPinnedCount == 0);
         SkASSERT(fPinnedUniqueID == 0);
-        fPinnedProxy = GrRefCachedBitmapTextureProxy(ctx, fBitmap,
-                                                     GrSamplerParams::ClampNoFilter(), nullptr);
+        fPinnedProxy = GrRefCachedBitmapTextureProxy(ctx, fBitmap, GrSamplerState::ClampNearest(),
+                                                     nullptr);
         if (!fPinnedProxy) {
             return false;
         }
diff --git a/src/shaders/SkImageShader.cpp b/src/shaders/SkImageShader.cpp
index f5756fe..ded75d4 100644
--- a/src/shaders/SkImageShader.cpp
+++ b/src/shaders/SkImageShader.cpp
@@ -171,6 +171,19 @@
 #include "effects/GrBicubicEffect.h"
 #include "effects/GrSimpleTextureEffect.h"
 
+static GrSamplerState::WrapMode tile_mode_to_wrap_mode(const SkShader::TileMode tileMode) {
+    switch (tileMode) {
+        case SkShader::TileMode::kClamp_TileMode:
+            return GrSamplerState::WrapMode::kClamp;
+        case SkShader::TileMode::kRepeat_TileMode:
+            return GrSamplerState::WrapMode::kRepeat;
+        case SkShader::TileMode::kMirror_TileMode:
+            return GrSamplerState::WrapMode::kMirrorRepeat;
+    }
+    SK_ABORT("Unknown tile mode.");
+    return GrSamplerState::WrapMode::kClamp;
+}
+
 std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
         const AsFPArgs& args) const {
     SkMatrix lmInverse;
@@ -185,22 +198,21 @@
         lmInverse.postConcat(inv);
     }
 
-    SkShader::TileMode tm[] = { fTileModeX, fTileModeY };
+    GrSamplerState::WrapMode wrapModes[] = {tile_mode_to_wrap_mode(fTileModeX),
+                                            tile_mode_to_wrap_mode(fTileModeY)};
 
     // Must set wrap and filter on the sampler before requesting a texture. In two places below
     // we check the matrix scale factors to determine how to interpret the filter quality setting.
     // This completely ignores the complexity of the drawVertices case where explicit local coords
     // are provided by the caller.
     bool doBicubic;
-    GrSamplerParams::FilterMode textureFilterMode =
-    GrSkFilterQualityToGrFilterMode(args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(),
-                                    &doBicubic);
-    GrSamplerParams params(tm, textureFilterMode);
+    GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode(
+            args.fFilterQuality, *args.fViewMatrix, this->getLocalMatrix(), &doBicubic);
+    GrSamplerState samplerState(wrapModes, textureFilterMode);
     sk_sp<SkColorSpace> texColorSpace;
     SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
-    sk_sp<GrTextureProxy> proxy(as_IB(fImage)->asTextureProxyRef(args.fContext, params,
-                                                                 args.fDstColorSpace,
-                                                                 &texColorSpace, scaleAdjust));
+    sk_sp<GrTextureProxy> proxy(as_IB(fImage)->asTextureProxyRef(
+            args.fContext, samplerState, args.fDstColorSpace, &texColorSpace, scaleAdjust));
     if (!proxy) {
         return nullptr;
     }
@@ -213,11 +225,11 @@
                                                                        args.fDstColorSpace);
     std::unique_ptr<GrFragmentProcessor> inner;
     if (doBicubic) {
-        inner = GrBicubicEffect::Make(std::move(proxy),
-                                      std::move(colorSpaceXform), lmInverse, tm);
+        inner = GrBicubicEffect::Make(std::move(proxy), std::move(colorSpaceXform), lmInverse,
+                                      wrapModes);
     } else {
-        inner = GrSimpleTextureEffect::Make(std::move(proxy),
-                                            std::move(colorSpaceXform), lmInverse, params);
+        inner = GrSimpleTextureEffect::Make(std::move(proxy), std::move(colorSpaceXform), lmInverse,
+                                            samplerState);
     }
 
     if (isAlphaOnly) {
diff --git a/src/shaders/SkPerlinNoiseShader.cpp b/src/shaders/SkPerlinNoiseShader.cpp
index cc9a569..0d951cd 100644
--- a/src/shaders/SkPerlinNoiseShader.cpp
+++ b/src/shaders/SkPerlinNoiseShader.cpp
@@ -1412,8 +1412,8 @@
     m.setTranslateY(-localMatrix.getTranslateY() + SK_Scalar1);
 
     if (fType == kImprovedNoise_Type) {
-        GrSamplerParams textureParams(SkShader::TileMode::kRepeat_TileMode,
-                                      GrSamplerParams::FilterMode::kNone_FilterMode);
+        GrSamplerState textureParams(GrSamplerState::WrapMode::kRepeat,
+                                     GrSamplerState::Filter::kNearest);
         sk_sp<GrTextureProxy> permutationsTexture(
             GrRefCachedBitmapTextureProxy(args.fContext,
                                           paintingData->getImprovedPermutationsBitmap(),
diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp
index 4eb68c9..64d3b48 100644
--- a/src/shaders/gradients/SkGradientShader.cpp
+++ b/src/shaders/gradients/SkGradientShader.cpp
@@ -1530,12 +1530,16 @@
         key |= kHardStopZeroOneOneKey;
     }
 
-    if (SkShader::TileMode::kClamp_TileMode == e.fTileMode) {
-        key |= kClampTileMode;
-    } else if (SkShader::TileMode::kRepeat_TileMode == e.fTileMode) {
-        key |= kRepeatTileMode;
-    } else {
-        key |= kMirrorTileMode;
+    switch (e.fWrapMode) {
+        case GrSamplerState::WrapMode::kClamp:
+            key |= kClampTileMode;
+            break;
+        case GrSamplerState::WrapMode::kRepeat:
+            key |= kRepeatTileMode;
+            break;
+        case GrSamplerState::WrapMode::kMirrorRepeat:
+            key |= kMirrorTileMode;
+            break;
     }
 
     key |= GrColorSpaceXform::XformKey(e.fColorSpaceXform.get()) << kReservedBits;
@@ -1551,17 +1555,17 @@
                                                           const char* outputColor,
                                                           const char* inputColor) {
     // First, apply tiling rules.
-    switch (ge.fTileMode) {
-    case SkShader::kClamp_TileMode:
-        fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
-        break;
-    case SkShader::kRepeat_TileMode:
-        fragBuilder->codeAppendf("float clamp_t = fract(%s);", t);
-        break;
-    case SkShader::kMirror_TileMode:
-        fragBuilder->codeAppendf("float t_1 = %s - 1.0;", t);
-        fragBuilder->codeAppendf("float clamp_t = abs(t_1 - 2.0 * floor(t_1 * 0.5) - 1.0);");
-        break;
+    switch (ge.fWrapMode) {
+        case GrSamplerState::WrapMode::kClamp:
+            fragBuilder->codeAppendf("float clamp_t = clamp(%s, 0.0, 1.0);", t);
+            break;
+        case GrSamplerState::WrapMode::kRepeat:
+            fragBuilder->codeAppendf("float clamp_t = fract(%s);", t);
+            break;
+        case GrSamplerState::WrapMode::kMirrorRepeat:
+            fragBuilder->codeAppendf("float t_1 = %s - 1.0;", t);
+            fragBuilder->codeAppendf("float clamp_t = abs(t_1 - 2.0 * floor(t_1 * 0.5) - 1.0);");
+            break;
     }
 
     // Calculate the color.
@@ -1589,7 +1593,7 @@
         case kHardStopLeftEdged_ColorType: {
             fragBuilder->codeAppendf("float4 colorTemp = mix(%s[1], %s[2], clamp_t);", colors,
                                      colors);
-            if (SkShader::kClamp_TileMode == ge.fTileMode) {
+            if (GrSamplerState::WrapMode::kClamp == ge.fWrapMode) {
                 fragBuilder->codeAppendf("if (%s < 0.0) {", t);
                 fragBuilder->codeAppendf("    colorTemp = %s[0];", colors);
                 fragBuilder->codeAppendf("}");
@@ -1601,7 +1605,7 @@
         case kHardStopRightEdged_ColorType: {
             fragBuilder->codeAppendf("float4 colorTemp = mix(%s[0], %s[1], clamp_t);", colors,
                                      colors);
-            if (SkShader::kClamp_TileMode == ge.fTileMode) {
+            if (GrSamplerState::WrapMode::kClamp == ge.fWrapMode) {
                 fragBuilder->codeAppendf("if (%s > 1.0) {", t);
                 fragBuilder->codeAppendf("    colorTemp = %s[2];", colors);
                 fragBuilder->codeAppendf("}");
@@ -1705,7 +1709,7 @@
         }
     }
 
-    fTileMode = args.fTileMode;
+    fWrapMode = args.fWrapMode;
 
     switch (fColorType) {
         // The two and three color specializations do not currently support tiling.
@@ -1760,18 +1764,16 @@
 
             // We always filter the gradient table. Each table is one row of a texture, always
             // y-clamp.
-            GrSamplerParams params;
-            params.setFilterMode(GrSamplerParams::kBilerp_FilterMode);
-            params.setTileModeX(args.fTileMode);
+            GrSamplerState samplerState(args.fWrapMode, GrSamplerState::Filter::kBilerp);
 
             fRow = fAtlas->lockRow(bitmap);
             if (-1 != fRow) {
                 fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight();
                 // This is 1/2 places where auto-normalization is disabled
                 fCoordTransform.reset(*args.fMatrix, fAtlas->asTextureProxyRef().get(), false);
-                fTextureSampler.reset(fAtlas->asTextureProxyRef(), params);
+                fTextureSampler.reset(fAtlas->asTextureProxyRef(), samplerState);
             } else {
-                // In this instance we know the params are:
+                // In this instance we know the samplerState state is:
                 //   clampY, bilerp
                 // and the proxy is:
                 //   exact fit, power of two in both dimensions
@@ -1787,7 +1789,7 @@
                 }
                 // This is 2/2 places where auto-normalization is disabled
                 fCoordTransform.reset(*args.fMatrix, proxy.get(), false);
-                fTextureSampler.reset(std::move(proxy), params);
+                fTextureSampler.reset(std::move(proxy), samplerState);
                 fYCoord = SK_ScalarHalf;
             }
 
@@ -1805,7 +1807,7 @@
         , fColors4f(that.fColors4f)
         , fColorSpaceXform(that.fColorSpaceXform)
         , fPositions(that.fPositions)
-        , fTileMode(that.fTileMode)
+        , fWrapMode(that.fWrapMode)
         , fCoordTransform(that.fCoordTransform)
         , fTextureSampler(that.fTextureSampler)
         , fYCoord(that.fYCoord)
@@ -1832,7 +1834,7 @@
 bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
     const GrGradientEffect& ge = processor.cast<GrGradientEffect>();
 
-    if (fTileMode != ge.fTileMode || fColorType != ge.getColorType()) {
+    if (fWrapMode != ge.fWrapMode || fColorType != ge.getColorType()) {
         return false;
     }
     SkASSERT(this->useAtlas() == ge.useAtlas());
diff --git a/src/shaders/gradients/SkGradientShaderPriv.h b/src/shaders/gradients/SkGradientShaderPriv.h
index 6d7c1b8..97c1e84 100644
--- a/src/shaders/gradients/SkGradientShaderPriv.h
+++ b/src/shaders/gradients/SkGradientShaderPriv.h
@@ -340,17 +340,41 @@
                    SkShader::TileMode tileMode,
                    sk_sp<GrColorSpaceXform> colorSpaceXform,
                    bool gammaCorrect)
-            : fContext(context)
-            , fShader(shader)
-            , fMatrix(matrix)
-            , fTileMode(tileMode)
-            , fColorSpaceXform(std::move(colorSpaceXform))
-            , fGammaCorrect(gammaCorrect) {}
+                : fContext(context)
+                , fShader(shader)
+                , fMatrix(matrix)
+                , fColorSpaceXform(std::move(colorSpaceXform))
+                , fGammaCorrect(gammaCorrect) {
+            switch (tileMode) {
+                case SkShader::kClamp_TileMode:
+                    fWrapMode = GrSamplerState::WrapMode::kClamp;
+                    break;
+                case SkShader::kRepeat_TileMode:
+                    fWrapMode = GrSamplerState::WrapMode::kRepeat;
+                    break;
+                case SkShader::kMirror_TileMode:
+                    fWrapMode = GrSamplerState::WrapMode::kMirrorRepeat;
+                    break;
+            }
+        }
+
+        CreateArgs(GrContext* context,
+                   const SkGradientShaderBase* shader,
+                   const SkMatrix* matrix,
+                   GrSamplerState::WrapMode wrapMode,
+                   sk_sp<GrColorSpaceXform> colorSpaceXform,
+                   bool gammaCorrect)
+                : fContext(context)
+                , fShader(shader)
+                , fMatrix(matrix)
+                , fWrapMode(wrapMode)
+                , fColorSpaceXform(std::move(colorSpaceXform))
+                , fGammaCorrect(gammaCorrect) {}
 
         GrContext*                  fContext;
         const SkGradientShaderBase* fShader;
         const SkMatrix*             fMatrix;
-        SkShader::TileMode          fTileMode;
+        GrSamplerState::WrapMode    fWrapMode;
         sk_sp<GrColorSpaceXform>    fColorSpaceXform;
         bool                        fGammaCorrect;
     };
@@ -442,13 +466,13 @@
 
     // If we're in legacy mode, then fColors will be populated. If we're gamma-correct, then
     // fColors4f and fColorSpaceXform will be populated.
-    SkTDArray<SkColor>       fColors;
+    SkTDArray<SkColor> fColors;
 
-    SkTDArray<SkColor4f>     fColors4f;
+    SkTDArray<SkColor4f> fColors4f;
     sk_sp<GrColorSpaceXform> fColorSpaceXform;
 
-    SkTDArray<SkScalar>      fPositions;
-    SkShader::TileMode       fTileMode;
+    SkTDArray<SkScalar> fPositions;
+    GrSamplerState::WrapMode fWrapMode;
 
     GrCoordTransform fCoordTransform;
     TextureSampler fTextureSampler;
diff --git a/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp b/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp
index caada92..b58ac2a 100644
--- a/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp
+++ b/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp
@@ -1356,7 +1356,7 @@
         matrix.postConcat(inv);
     }
 
-    GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fTileMode,
+    GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fWrapMode,
                                          std::move(args.fColorSpaceXform), args.fGammaCorrect);
 
     if (shader.getStartRadius() < kErrorTol) {