Move filter/wrap out of GrSamplerState into GrTextureParams

Review URL: http://codereview.appspot.com/6440046/




git-svn-id: http://skia.googlecode.com/svn/trunk@4773 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 18abd4e..e0f5827 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -119,18 +119,16 @@
      *  Create a new entry, based on the specified key and texture, and return
      *  its "locked" entry. Must call be balanced with an unlockTexture() call.
      *
-     *  @param sampler  The sampler state used to draw a texture may be used
-     *                  to determine how to store the pixel data in the texture
-     *                  cache. (e.g. different versions may exist for different
-     *                  wrap modes on GPUs with limited or no NPOT texture
-     *                  support). Only the wrap and filter fields are used. NULL
-     *                  implies clamp wrap modes and nearest filtering.
+     * @param params    The tex params used to draw a texture may help determine
+     *                  the cache entry used. (e.g. different versions may exist
+     *                  for different wrap modes on GPUs with limited NPOT
+     *                  texture support). NULL implies clamp wrap modes.
      * @param desc      Description of the texture properties.
      * @param srcData   Pointer to the pixel values.
      * @param rowBytes  The number of bytes between rows of the texture. Zero
      *                  implies tightly packed rows.
      */
-    TextureCacheEntry createAndLockTexture(const GrSamplerState* sampler,
+    TextureCacheEntry createAndLockTexture(const GrTextureParams* params,
                                            const GrTextureDesc& desc,
                                            void* srcData, size_t rowBytes);
 
@@ -139,23 +137,21 @@
      *  return it. The entry's texture() function will return NULL if not found.
      *  Must be balanced with an unlockTexture() call.
      *
-     *  @param desc      Description of the texture properties.
-     *  @param sampler  The sampler state used to draw a texture may be used
-     *                  to determine the cache entry used. (e.g. different
-     *                  versions may exist for different wrap modes on GPUs with
-     *                  limited or no NPOT texture support). Only the wrap and 
-     *                  filter fields are used. NULL implies clamp wrap modes
-     *                  and nearest filtering.
+     *  @param desc     Description of the texture properties.
+     *  @param params   The tex params used to draw a texture may help determine
+     *                  the cache entry used. (e.g. different versions may exist
+     *                  for different wrap modes on GPUs with limited NPOT
+     *                  texture support). NULL implies clamp wrap modes.
      */
     TextureCacheEntry findAndLockTexture(const GrTextureDesc& desc,
-                                         const GrSamplerState* sampler);
+                                         const GrTextureParams* params);
     /**
      * Determines whether a texture is in the cache. If the texture is found it
      * will not be locked or returned. This call does not affect the priority of
      * the texture for deletion.
      */
     bool isTextureInCache(const GrTextureDesc& desc,
-                          const GrSamplerState* sampler) const;
+                          const GrTextureParams* params) const;
 
     /**
      * Enum that determines how closely a returned scratch texture must match
@@ -212,9 +208,12 @@
                                      size_t rowBytes);
 
     /**
-     *  Returns true if the specified use of an indexed texture is supported.
+     * Returns true if the specified use of an indexed texture is supported.
+     * Support may depend upon whether the texture params indicate that the
+     * texture will be tiled. Passing NULL for the texture params indicates
+     * clamp mode.
      */
-    bool supportsIndex8PixelConfig(const GrSamplerState* sampler,
+    bool supportsIndex8PixelConfig(const GrTextureParams*,
                                    int width,
                                    int height) const;
 
diff --git a/include/gpu/GrSamplerState.h b/include/gpu/GrSamplerState.h
index 0731848..04fbe00 100644
--- a/include/gpu/GrSamplerState.h
+++ b/include/gpu/GrSamplerState.h
@@ -15,31 +15,76 @@
 #include "GrMatrix.h"
 #include "GrTypes.h"
 
+#include "SkShader.h"
+
+class GrTextureParams {
+public:
+    GrTextureParams() {
+        this->reset();
+    }
+
+    GrTextureParams(const GrTextureParams& params) {
+        *this = params;
+    }
+
+    GrTextureParams& operator =(const GrTextureParams& params) {
+        fTileModes[0] = params.fTileModes[0];
+        fTileModes[1] = params.fTileModes[1];
+        fBilerp = params.fBilerp;
+        return *this;
+    }
+
+    void reset() {
+        this->reset(SkShader::kClamp_TileMode, false);
+    }
+
+    void reset(SkShader::TileMode tileXAndY, bool filter) {
+        fTileModes[0] = fTileModes[1] = tileXAndY;
+        fBilerp = filter;
+    }
+    void reset(SkShader::TileMode tileModes[2], bool filter) {
+        fTileModes[0] = tileModes[0];
+        fTileModes[1] = tileModes[1];
+        fBilerp = filter;
+    }
+
+    void setClampNoFilter() {
+        fTileModes[0] = fTileModes[1] = SkShader::kClamp_TileMode;
+        fBilerp = false;
+    }
+
+    void setClamp() {
+        fTileModes[0] = fTileModes[1] = SkShader::kClamp_TileMode;
+    }
+
+    void setBilerp(bool bilerp) { fBilerp = bilerp; }
+
+    void setTileModeX(const SkShader::TileMode tm) { fTileModes[0] = tm; }
+    void setTileModeY(const SkShader::TileMode tm) { fTileModes[1] = tm; }
+    void setTileModeXAndY(const SkShader::TileMode tm) { fTileModes[0] = fTileModes[1] = tm; }
+
+    SkShader::TileMode getTileModeX() const { return fTileModes[0]; }
+
+    SkShader::TileMode getTileModeY() const { return fTileModes[1]; }
+
+    bool isTiled() const {
+        return SkShader::kClamp_TileMode != fTileModes[0] ||
+               SkShader::kClamp_TileMode != fTileModes[1];
+    }
+
+    bool isBilerp() const { return fBilerp; }
+
+private:
+
+    SkShader::TileMode fTileModes[2];
+    bool               fBilerp;
+};
+
 class GrSamplerState {
 public:
-    enum Filter {
-        /**
-         * Read the closest src texel to the sample position
-         */
-        kNearest_Filter,
-        /**
-         * Blend between closest 4 src texels to sample position (tent filter)
-         */
-        kBilinear_Filter,
-        kDefault_Filter = kNearest_Filter
-    };
+    static const bool kBilerpDefault = false;
 
-    /**
-     * Describes how a texture is sampled when coordinates are outside the
-     * texture border
-     */
-    enum WrapMode {
-        kClamp_WrapMode,
-        kRepeat_WrapMode,
-        kMirror_WrapMode,
-
-        kDefault_WrapMode = kClamp_WrapMode
-    };
+    static const SkShader::TileMode kTileModeDefault = SkShader::kClamp_TileMode;
 
     /**
      * Default sampler state is set to clamp, use normal sampling mode, be
@@ -74,9 +119,7 @@
 
     GrSamplerState& operator =(const GrSamplerState& s) {
         // memcpy() breaks refcounting
-        fWrapX = s.fWrapX;
-        fWrapY = s.fWrapY;
-        fFilter = s.fFilter;
+        fTextureParams = s.fTextureParams;
         fMatrix = s.fMatrix;
         fSwapRAndB = s.fSwapRAndB;
 
@@ -85,15 +128,11 @@
         return *this;
     }
 
-    WrapMode getWrapX() const { return fWrapX; }
-    WrapMode getWrapY() const { return fWrapY; }
     const GrMatrix& getMatrix() const { return fMatrix; }
-    Filter getFilter() const { return fFilter; }
     bool swapsRAndB() const { return fSwapRAndB; }
 
-    void setWrapX(WrapMode mode) { fWrapX = mode; }
-    void setWrapY(WrapMode mode) { fWrapY = mode; }
-    
+    GrTextureParams* textureParams() { return &fTextureParams; }
+    const GrTextureParams& getTextureParams() const { return fTextureParams; }
     /**
      * Access the sampler's matrix. See SampleMode for explanation of
      * relationship between the matrix and sample mode.
@@ -118,30 +157,22 @@
      */
     void preConcatMatrix(const GrMatrix& matrix) { fMatrix.preConcat(matrix); }
 
-    /**
-     * Sets filtering type.
-     * @param filter    type of filtering to apply
-     */
-    void setFilter(Filter filter) { fFilter = filter; }
-
-    void reset(WrapMode wrapXAndY,
-               Filter filter,
+    void reset(SkShader::TileMode tileXAndY,
+               bool filter,
                const GrMatrix& matrix) {
-        fWrapX = wrapXAndY;
-        fWrapY = wrapXAndY;
-        fFilter = filter;
+        fTextureParams.reset(tileXAndY, filter);
         fMatrix = matrix;
         fSwapRAndB = false;
         GrSafeSetNull(fCustomStage);
     }
-    void reset(WrapMode wrapXAndY, Filter filter) {
+    void reset(SkShader::TileMode wrapXAndY, bool filter) {
         this->reset(wrapXAndY, filter, GrMatrix::I());
     }
     void reset(const GrMatrix& matrix) {
-        this->reset(kDefault_WrapMode, kDefault_Filter, matrix);
+        this->reset(kTileModeDefault, kBilerpDefault, matrix);
     }
     void reset() {
-        this->reset(kDefault_WrapMode, kDefault_Filter, GrMatrix::I());
+        this->reset(kTileModeDefault, kBilerpDefault, GrMatrix::I());
     }
 
     GrCustomStage* setCustomStage(GrCustomStage* stage) {
@@ -151,9 +182,7 @@
     GrCustomStage* getCustomStage() const { return fCustomStage; }
 
 private:
-    WrapMode            fWrapX : 8;
-    WrapMode            fWrapY : 8;
-    Filter              fFilter : 8;
+    GrTextureParams     fTextureParams;
     bool                fSwapRAndB;
     GrMatrix            fMatrix;
 
diff --git a/include/gpu/GrTexture.h b/include/gpu/GrTexture.h
index 783a147..d4a7cc6 100644
--- a/include/gpu/GrTexture.h
+++ b/include/gpu/GrTexture.h
@@ -13,7 +13,7 @@
 
 class GrRenderTarget;
 class GrResourceKey;
-class GrSamplerState;
+class GrTextureParams;
 
 /*
  * All uncached textures should have this value as their fClientCacheID
@@ -162,7 +162,7 @@
 #endif
 
     static GrResourceKey ComputeKey(const GrGpu* gpu,
-                                    const GrSamplerState* sampler,
+                                    const GrTextureParams* sampler,
                                     const GrTextureDesc& desc,
                                     bool scratch);
 
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 2af1149..4a62813 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -118,7 +118,7 @@
 protected:
     typedef GrContext::TextureCacheEntry TexCache;
     bool isBitmapInTextureCache(const SkBitmap& bitmap,
-                                const GrSamplerState& sampler) const;
+                                const GrTextureParams& params) const;
 
     // overrides from SkDevice
     virtual bool onReadPixels(const SkBitmap& bitmap,
@@ -157,7 +157,7 @@
 
     void prepareRenderTarget(const SkDraw&);
     bool shouldTileBitmap(const SkBitmap& bitmap,
-                          const GrSamplerState& sampler,
+                          const GrTextureParams& sampler,
                           const SkIRect* srcRectPtr,
                           int* tileSize) const;
     void internalDrawBitmap(const SkDraw&, const SkBitmap&,
diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h
index ea79c63..6c6e3da 100644
--- a/include/gpu/SkGr.h
+++ b/include/gpu/SkGr.h
@@ -24,7 +24,6 @@
 #include "SkPath.h"
 #include "SkPoint.h"
 #include "SkRegion.h"
-#include "SkShader.h"
 #include "SkClipStack.h"
 
 #if (GR_DEBUG && defined(SK_RELEASE)) || (GR_RELEASE && defined(SK_DEBUG))
@@ -34,14 +33,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Sk to Gr Type conversions
 
-GR_STATIC_ASSERT((int)GrSamplerState::kClamp_WrapMode == (int)SkShader::kClamp_TileMode);
-GR_STATIC_ASSERT((int)GrSamplerState::kRepeat_WrapMode ==(
-                 int)SkShader::kRepeat_TileMode);
-GR_STATIC_ASSERT((int)GrSamplerState::kMirror_WrapMode ==
-                 (int)SkShader::kMirror_TileMode);
-
-#define sk_tile_mode_to_grwrap(X) ((GrSamplerState::WrapMode)(X))
-
 GR_STATIC_ASSERT((int)kZero_GrBlendCoeff == (int)SkXfermode::kZero_Coeff);
 GR_STATIC_ASSERT((int)kOne_GrBlendCoeff  == (int)SkXfermode::kOne_Coeff);
 GR_STATIC_ASSERT((int)kSC_GrBlendCoeff   == (int)SkXfermode::kSC_Coeff);
@@ -85,11 +76,11 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-GrContext::TextureCacheEntry GrLockCachedBitmapTexture(GrContext* ctx, 
-                                               const SkBitmap& bitmap,
-                                               const GrSamplerState* sampler);
+GrContext::TextureCacheEntry GrLockCachedBitmapTexture(GrContext*,
+                                                       const SkBitmap&,
+                                                       const GrTextureParams*);
 
-void GrUnlockCachedBitmapTexture(GrContext* ctx, GrContext::TextureCacheEntry cache);
+void GrUnlockCachedBitmapTexture(GrContext*, GrContext::TextureCacheEntry);
 
 ////////////////////////////////////////////////////////////////////////////////
 // Classes
diff --git a/src/effects/SkGradientShader.cpp b/src/effects/SkGradientShader.cpp
index 7a55bbb..ad27cd0 100644
--- a/src/effects/SkGradientShader.cpp
+++ b/src/effects/SkGradientShader.cpp
@@ -1050,9 +1050,9 @@
                                                  GrSamplerState* sampler) const {
     SkASSERT(NULL != context && NULL != sampler);
     sampler->matrix()->preConcat(fPtsToUnit);
-    sampler->setWrapX(sk_tile_mode_to_grwrap(fTileMode));
-    sampler->setWrapY(sk_tile_mode_to_grwrap(kClamp_TileMode));
-    sampler->setFilter(GrSamplerState::kBilinear_Filter);
+    sampler->textureParams()->setTileModeX(fTileMode);
+    sampler->textureParams()->setTileModeY(kClamp_TileMode);
+    sampler->textureParams()->setBilerp(true);
     return SkNEW_ARGS(GrLinearGradient, (context, *this, sampler));
 }
 
@@ -1468,9 +1468,9 @@
         GrSamplerState* sampler) const SK_OVERRIDE {
         SkASSERT(NULL != context && NULL != sampler);
         sampler->matrix()->preConcat(fPtsToUnit);
-        sampler->setWrapX(sk_tile_mode_to_grwrap(fTileMode));
-        sampler->setWrapY(sk_tile_mode_to_grwrap(kClamp_TileMode));
-        sampler->setFilter(GrSamplerState::kBilinear_Filter);
+        sampler->textureParams()->setTileModeX(fTileMode);
+        sampler->textureParams()->setTileModeY(kClamp_TileMode);
+        sampler->textureParams()->setBilerp(true);
         return SkNEW_ARGS(GrRadialGradient, (context, *this, sampler));
     }
 
@@ -1930,9 +1930,9 @@
             sampler->matrix()->reset();
         }
         sampler->matrix()->preConcat(fPtsToUnit);
-        sampler->setWrapX(sk_tile_mode_to_grwrap(fTileMode));
-        sampler->setWrapY(sk_tile_mode_to_grwrap(kClamp_TileMode));
-        sampler->setFilter(GrSamplerState::kBilinear_Filter);
+        sampler->textureParams()->setTileModeX(fTileMode);
+        sampler->textureParams()->setTileModeY(kClamp_TileMode);
+        sampler->textureParams()->setBilerp(true);
         return SkNEW_ARGS(GrRadial2Gradient, (context, *this, sampler, 
             diffLen, fStartRadius, fDiffRadius));
     }
@@ -2395,9 +2395,9 @@
             sampler->matrix()->reset();
         }
         sampler->matrix()->preTranslate(-fCenter1.fX, -fCenter1.fY);
-        sampler->setWrapX(sk_tile_mode_to_grwrap(fTileMode));
-        sampler->setWrapY(sk_tile_mode_to_grwrap(kClamp_TileMode));
-        sampler->setFilter(GrSamplerState::kBilinear_Filter);
+        sampler->textureParams()->setTileModeX(fTileMode);
+        sampler->textureParams()->setTileModeY(kClamp_TileMode);
+        sampler->textureParams()->setBilerp(true);
         return SkNEW_ARGS(GrConical2Gradient, (context, *this, sampler, 
                           diffLen, fRadius1, fRadius2 - fRadius1));
     }
@@ -2471,9 +2471,9 @@
     virtual GrCustomStage* asNewCustomStage(GrContext* context,
         GrSamplerState* sampler) const SK_OVERRIDE {
         sampler->matrix()->preConcat(fPtsToUnit);
-        sampler->setWrapX(sk_tile_mode_to_grwrap(fTileMode));
-        sampler->setWrapY(sk_tile_mode_to_grwrap(kClamp_TileMode));
-        sampler->setFilter(GrSamplerState::kBilinear_Filter);
+        sampler->textureParams()->setTileModeX(fTileMode);
+        sampler->textureParams()->setTileModeY(kClamp_TileMode);
+        sampler->textureParams()->setBilerp(true);
         return SkNEW_ARGS(GrSweepGradient, (context, *this, sampler));
     }
 
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 4deebf4..d7287ea 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -37,9 +37,7 @@
     mat.preTranslate(SkIntToScalar(-bound.fLeft), SkIntToScalar(-bound.fTop));
     mat.preConcat(drawState->getViewMatrix());
 
-    drawState->sampler(maskStage)->reset(GrSamplerState::kClamp_WrapMode,
-                                         GrSamplerState::kNearest_Filter,
-                                         mat);
+    drawState->sampler(maskStage)->reset(mat);
 
     drawState->createTextureEffect(maskStage, result);
 }
@@ -481,9 +479,7 @@
     GrMatrix sampleM;
     sampleM.setIDiv(texture->width(), texture->height());
 
-    drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
-                                 GrSamplerState::kNearest_Filter,
-                                 sampleM);
+    drawState->sampler(0)->reset(sampleM);
     drawState->createTextureEffect(0, texture);
 
     GrRect rect = GrRect::MakeWH(SkIntToScalar(target->width()), 
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 7321ffb..cd2b5a6 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -254,17 +254,16 @@
 
 }
 
-GrContext::TextureCacheEntry GrContext::findAndLockTexture(
-        const GrTextureDesc& desc,
-        const GrSamplerState* sampler) {
-    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, desc, false);
+GrContext::TextureCacheEntry GrContext::findAndLockTexture(const GrTextureDesc& desc,
+                                                           const GrTextureParams* params) {
+    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, false);
     return TextureCacheEntry(fTextureCache->findAndLock(resourceKey,
                                             GrResourceCache::kNested_LockType));
 }
 
 bool GrContext::isTextureInCache(const GrTextureDesc& desc,
-                                 const GrSamplerState* sampler) const {
-    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler, desc, false);
+                                 const GrTextureParams* params) const {
+    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, false);
     return fTextureCache->hasKey(resourceKey);
 }
 
@@ -324,7 +323,7 @@
 }
 
 GrContext::TextureCacheEntry GrContext::createAndLockTexture(
-        const GrSamplerState* sampler,
+        const GrTextureParams* params,
         const GrTextureDesc& desc,
         void* srcData,
         size_t rowBytes) {
@@ -336,19 +335,16 @@
 
     TextureCacheEntry entry;
 
-    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, sampler,
-                                                      desc, false);
+    GrResourceKey resourceKey = GrTexture::ComputeKey(fGpu, params, desc, false);
 
     if (GrTexture::NeedsResizing(resourceKey)) {
         // The desired texture is NPOT and tiled but that isn't supported by 
         // the current hardware. Resize the texture to be a POT
-        GrAssert(NULL != sampler);
-        TextureCacheEntry clampEntry = this->findAndLockTexture(desc,
-                                                                NULL);
+        GrAssert(NULL != params);
+        TextureCacheEntry clampEntry = this->findAndLockTexture(desc, NULL);
 
         if (NULL == clampEntry.texture()) {
-            clampEntry = this->createAndLockTexture(NULL, desc,
-                                                    srcData, rowBytes);
+            clampEntry = this->createAndLockTexture(NULL, desc, srcData, rowBytes);
             GrAssert(NULL != clampEntry.texture());
             if (NULL == clampEntry.texture()) {
                 return entry;
@@ -364,22 +360,15 @@
         GrTexture* texture = fGpu->createTexture(rtDesc, NULL, 0);
 
         if (NULL != texture) {
-            GrDrawTarget::AutoStateRestore asr(fGpu,
-                                               GrDrawTarget::kReset_ASRInit);
+            GrDrawTarget::AutoStateRestore asr(fGpu, GrDrawTarget::kReset_ASRInit);
             GrDrawState* drawState = fGpu->drawState();
             drawState->setRenderTarget(texture->asRenderTarget());
 
-            GrSamplerState::Filter filter;
             // if filtering is not desired then we want to ensure all
             // texels in the resampled image are copies of texels from
             // the original.
-            if (GrTexture::NeedsFiltering(resourceKey)) {
-                filter = GrSamplerState::kBilinear_Filter;
-            } else {
-                filter = GrSamplerState::kNearest_Filter;
-            }
-            drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
-                                         filter);
+            drawState->sampler(0)->reset(SkShader::kClamp_TileMode,
+                                         GrTexture::NeedsFiltering(resourceKey));
             drawState->createTextureEffect(0, clampEntry.texture());
 
             static const GrVertexLayout layout =
@@ -570,7 +559,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-bool GrContext::supportsIndex8PixelConfig(const GrSamplerState* sampler,
+bool GrContext::supportsIndex8PixelConfig(const GrTextureParams* params,
                                           int width, int height) const {
     const GrDrawTarget::Caps& caps = fGpu->getCaps();
     if (!caps.f8BitPaletteSupport) {
@@ -580,9 +569,7 @@
     bool isPow2 = GrIsPow2(width) && GrIsPow2(height);
 
     if (!isPow2) {
-        bool tiled = NULL != sampler &&
-                     (sampler->getWrapX() != GrSamplerState::kClamp_WrapMode ||
-                      sampler->getWrapY() != GrSamplerState::kClamp_WrapMode);
+        bool tiled = NULL != params && params->isTiled();
         if (tiled && !caps.fNPOTTextureTileSupport) {
             return false;
         }
@@ -1540,9 +1527,7 @@
     drawState->setRenderTarget(target);
 
     matrix.setIDiv(texture->width(), texture->height());
-    drawState->sampler(0)->reset(GrSamplerState::kClamp_WrapMode,
-                                 GrSamplerState::kNearest_Filter,
-                                 matrix);
+    drawState->sampler(0)->reset(matrix);
     drawState->createTextureEffect(0, texture);
     drawState->sampler(0)->setRAndBSwap(swapRAndB);
 
@@ -1823,7 +1808,7 @@
 
     GrPaint paint;
     paint.reset();
-    paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
+    paint.textureSampler(0)->textureParams()->setBilerp(true);
 
     for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
         paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
@@ -1885,7 +1870,7 @@
                                       1, srcIRect.height());
         this->clear(&clearRect, 0x0);
         // FIXME:  This should be mitchell, not bilinear.
-        paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
+        paint.textureSampler(0)->textureParams()->setBilerp(true);
         paint.textureSampler(0)->matrix()->setIDiv(srcTexture->width(),
                                                    srcTexture->height());
         this->setRenderTarget(dstTexture->asRenderTarget());
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 051f112..75a2cd7 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -763,14 +763,13 @@
         }
     }
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-        // We don't support using unpremultiplied textures with filters (other than nearest). Alpha-
-        // premulling is not distributive WRT to filtering. We'd have to filter each texel before
-        // filtering. We could do this for our custom filters but we would also have to disable
-        // bilerp and do a custom bilerp in the shader. Until Skia itself supports unpremul configs
-        // there is no pressure to implement this.
+        // We don't support using unpremultiplied textures with bilerp. Alpha-multiplication is not
+        // distributive with respect to filtering. We'd have to alpha-mul each texel before
+        // filtering. Until Skia itself supports unpremultiplied configs there is no pressure to
+        // implement this.
         if (drawState.getTexture(s) &&
             GrPixelConfigIsUnpremultiplied(drawState.getTexture(s)->config()) &&
-            GrSamplerState::kNearest_Filter != drawState.getSampler(s).getFilter()) {
+            drawState.getSampler(s).getTextureParams().isBilerp()) {
             return false;
         }
     }
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index 1fb17b5..925fdb3 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -29,14 +29,8 @@
     GrDrawState* drawState = fDrawTarget->drawState();
     if (fCurrVertex > 0) {
         // setup our sampler state for our text texture/atlas
-        GrSamplerState::Filter filter;
-        if (fExtMatrix.isIdentity()) {
-            filter = GrSamplerState::kNearest_Filter;
-        } else {
-            filter = GrSamplerState::kBilinear_Filter;
-        }
-        drawState->sampler(kGlyphMaskStage)->reset(
-            GrSamplerState::kRepeat_WrapMode,filter);
+        drawState->sampler(kGlyphMaskStage)->reset(SkShader::kRepeat_TileMode,
+                                                   fExtMatrix.isIdentity());
 
         GrAssert(GrIsALIGN4(fCurrVertex));
         GrAssert(fCurrTexture);
diff --git a/src/gpu/GrTexture.cpp b/src/gpu/GrTexture.cpp
index 8c12bd2..fbc3893 100644
--- a/src/gpu/GrTexture.cpp
+++ b/src/gpu/GrTexture.cpp
@@ -135,7 +135,7 @@
 
 namespace {
 void gen_texture_key_values(const GrGpu* gpu,
-                            const GrSamplerState* sampler,
+                            const GrTextureParams* params,
                             const GrTextureDesc& desc,
                             bool scratch,
                             uint32_t v[4]) {
@@ -163,13 +163,11 @@
     if (!gpu->getCaps().fNPOTTextureTileSupport) {
         bool isPow2 = GrIsPow2(desc.fWidth) && GrIsPow2(desc.fHeight);
 
-        bool tiled = NULL != sampler &&
-                   ((sampler->getWrapX() != GrSamplerState::kClamp_WrapMode) ||
-                    (sampler->getWrapY() != GrSamplerState::kClamp_WrapMode));
+        bool tiled = NULL != params && params->isTiled();
 
         if (tiled && !isPow2) {
             v[3] |= kNPOT_TextureBit;
-            if (GrSamplerState::kNearest_Filter != sampler->getFilter()) {
+            if (params->isBilerp()) {
                 v[3] |= kFilter_TextureBit;
             }
         }
@@ -184,11 +182,11 @@
 }
 
 GrResourceKey GrTexture::ComputeKey(const GrGpu* gpu,
-                                    const GrSamplerState* sampler,
+                                    const GrTextureParams* params,
                                     const GrTextureDesc& desc,
                                     bool scratch) {
     uint32_t v[4];
-    gen_texture_key_values(gpu, sampler, desc, scratch, v);
+    gen_texture_key_values(gpu, params, desc, scratch, v);
     return GrResourceKey(v);
 }
 
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 80e3f37..f290239 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -85,10 +85,10 @@
     SkAutoCachedTexture() { }    
     SkAutoCachedTexture(SkGpuDevice* device,
                         const SkBitmap& bitmap,
-                        const GrSamplerState* sampler,
+                        const GrTextureParams* params,
                         GrTexture** texture) {
         GrAssert(texture);
-        *texture = this->set(device, bitmap, sampler);
+        *texture = this->set(device, bitmap, params);
     }
 
     ~SkAutoCachedTexture() {
@@ -99,7 +99,7 @@
 
     GrTexture* set(SkGpuDevice* device,
                    const SkBitmap& bitmap,
-                   const GrSamplerState* sampler) {
+                   const GrTextureParams* params) {
         if (fTex.texture()) {
             GrUnlockCachedBitmapTexture(fDevice->context(), fTex);
         }
@@ -110,7 +110,7 @@
             fTex.reset();
         } else {
             // look it up in our cache
-            fTex = GrLockCachedBitmapTexture(device->context(), bitmap, sampler);
+            fTex = GrLockCachedBitmapTexture(device->context(), bitmap, params);
             texture = fTex.texture();
         }
         return texture;
@@ -564,9 +564,9 @@
         grPaint->resetColorFilter();
 
         GrSamplerState* colorSampler = grPaint->textureSampler(kColorFilterTextureIdx);
-        GrTexture* texture = act->set(dev, colorTransformTable, colorSampler);
+        GrTexture* texture = act->set(dev, colorTransformTable, colorSampler->textureParams());
 
-        colorSampler->reset(GrSamplerState::kClamp_WrapMode, GrSamplerState::kNearest_Filter);
+        colorSampler->reset();
         colorSampler->setCustomStage(SkNEW_ARGS(GrColorTableEffect, (texture)))->unref();
     } else {
         grPaint->resetColorFilter();
@@ -641,14 +641,8 @@
     }
 
     // Must set wrap and filter on the sampler before requesting a texture.
-    sampler->setWrapX(sk_tile_mode_to_grwrap(tileModes[0]));
-    sampler->setWrapY(sk_tile_mode_to_grwrap(tileModes[1]));
-    GrSamplerState::Filter filter = GrSamplerState::kNearest_Filter;
-    if (skPaint.isFilterBitmap()) {
-        filter = GrSamplerState::kBilinear_Filter;
-    }
-    sampler->setFilter(filter);
-    GrTexture* texture = textures[kShaderTextureIdx].set(dev, bitmap, sampler);
+    sampler->textureParams()->reset(tileModes, skPaint.isFilterBitmap());
+    GrTexture* texture = textures[kShaderTextureIdx].set(dev, bitmap, sampler->textureParams());
 
     if (NULL == texture) {
         SkDebugf("Couldn't convert bitmap to texture.\n");
@@ -929,7 +923,7 @@
     if (!isNormalBlur) {
         GrPaint paint;
         paint.reset();
-        paint.textureSampler(0)->setFilter(GrSamplerState::kNearest_Filter);
+        paint.textureSampler(0)->textureParams()->setClampNoFilter();
         paint.textureSampler(0)->matrix()->setIDiv(pathTexture->width(),
                                                    pathTexture->height());
         // Blend pathTexture over blurTexture.
@@ -1197,7 +1191,7 @@
 }
 
 bool SkGpuDevice::shouldTileBitmap(const SkBitmap& bitmap,
-                                   const GrSamplerState& sampler,
+                                   const GrTextureParams& params,
                                    const SkIRect* srcRectPtr,
                                    int* tileSize) const {
     SkASSERT(NULL != tileSize);
@@ -1219,7 +1213,7 @@
         return false;
     }
     // if the entire texture is already in our cache then no reason to tile it
-    if (this->isBitmapInTextureCache(bitmap, sampler)) {
+    if (this->isBitmapInTextureCache(bitmap, params)) {
         return false;
     }
 
@@ -1298,15 +1292,11 @@
     if (!skPaint2GrPaintNoShader(this, paint, true, false, &colorLutTexture, &grPaint)) {
         return;
     }
-    GrSamplerState* sampler = grPaint.textureSampler(kBitmapTextureIdx);
-    if (paint.isFilterBitmap()) {
-        sampler->setFilter(GrSamplerState::kBilinear_Filter);
-    } else {
-        sampler->setFilter(GrSamplerState::kNearest_Filter);
-    }
+    GrTextureParams* params = grPaint.textureSampler(kBitmapTextureIdx)->textureParams();
+    params->setBilerp(paint.isFilterBitmap());
 
     int tileSize;
-    if (!this->shouldTileBitmap(bitmap, *sampler, srcRectPtr, &tileSize)) {
+    if (!this->shouldTileBitmap(bitmap, *params, srcRectPtr, &tileSize)) {
         // take the simple case
         this->internalDrawBitmap(draw, bitmap, srcRect, m, &grPaint);
         return;
@@ -1430,12 +1420,11 @@
 
     GrSamplerState* sampler = grPaint->textureSampler(kBitmapTextureIdx);
 
-    sampler->setWrapX(GrSamplerState::kClamp_WrapMode);
-    sampler->setWrapY(GrSamplerState::kClamp_WrapMode);
+    sampler->textureParams()->setClamp();
     sampler->matrix()->reset();
 
     GrTexture* texture;
-    SkAutoCachedTexture act(this, bitmap, sampler, &texture);
+    SkAutoCachedTexture act(this, bitmap, sampler->textureParams(), &texture);
     if (NULL == texture) {
         return;
     }
@@ -1454,11 +1443,9 @@
                       SkFloatToScalar(srcRect.fBottom * hInv));
 
     bool needsTextureDomain = false; 
-    if (GrSamplerState::kBilinear_Filter == sampler->getFilter())
-    {
+    if (sampler->textureParams()->isBilerp()) {
         // Need texture domain if drawing a sub rect.
-        needsTextureDomain = srcRect.width() < bitmap.width() ||
-            srcRect.height() < bitmap.height();
+        needsTextureDomain = srcRect.width() < bitmap.width() || srcRect.height() < bitmap.height();
         if (m.rectStaysRect() && draw.fMatrix->rectStaysRect()) {
             // sampling is axis-aligned
             GrRect floatSrcRect, transformedRect;
@@ -1469,7 +1456,7 @@
             
             if (hasAlignedSamples(floatSrcRect, transformedRect)) {
                 // Samples are texel-aligned, so filtering is futile
-                sampler->setFilter(GrSamplerState::kNearest_Filter);
+                sampler->textureParams()->setBilerp(false);
                 needsTextureDomain = false;
             } else {
                 needsTextureDomain = needsTextureDomain &&
@@ -1522,7 +1509,7 @@
     sampleM.setIDiv(srcTexture->width(), srcTexture->height());
     GrPaint paint;
     paint.reset();
-    paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
+    paint.textureSampler(0)->textureParams()->setBilerp(true);
     paint.textureSampler(0)->reset(sampleM);
     paint.textureSampler(0)->setCustomStage(stage);
     context->drawRect(paint, rect);
@@ -1589,7 +1576,7 @@
 
     GrTexture* texture;
     sampler->reset();
-    SkAutoCachedTexture act(this, bitmap, sampler, &texture);
+    SkAutoCachedTexture act(this, bitmap, sampler->textureParams(), &texture);
     grPaint.textureSampler(kBitmapTextureIdx)->setCustomStage(SkNEW_ARGS
         (GrSingleTextureEffect, (texture)))->unref();
 
@@ -1701,7 +1688,7 @@
     GrSamplerState* sampler = paint.textureSampler(kBitmapTextureIdx);
 
     GrTexture* texture;
-    SkAutoCachedTexture act(this, src, sampler, &texture);
+    SkAutoCachedTexture act(this, src, sampler->textureParams(), &texture);
 
     result->setConfig(src.config(), src.width(), src.height());
     GrRect rect = GrRect::MakeWH(SkIntToScalar(src.width()), 
@@ -1933,7 +1920,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool SkGpuDevice::isBitmapInTextureCache(const SkBitmap& bitmap,
-                                         const GrSamplerState& sampler) const {
+                                         const GrTextureParams& params) const {
     uint64_t key = bitmap.getGenerationID();
     key |= ((uint64_t) bitmap.pixelRefOffset()) << 32;
 
@@ -1943,7 +1930,7 @@
     desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config());
     desc.fClientCacheID = key;
 
-    return this->context()->isTextureInCache(desc, &sampler);
+    return this->context()->isTextureInCache(desc, &params);
 }
 
 
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 41f50f5..dca0858 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -58,7 +58,7 @@
 
 static GrContext::TextureCacheEntry sk_gr_create_bitmap_texture(GrContext* ctx,
                                                 uint64_t key,
-                                                const GrSamplerState* sampler,
+                                                const GrTextureParams* params,
                                                 const SkBitmap& origBitmap) {
     SkAutoLockPixels alp(origBitmap);
     GrContext::TextureCacheEntry entry;
@@ -80,7 +80,7 @@
     if (SkBitmap::kIndex8_Config == bitmap->config()) {
         // build_compressed_data doesn't do npot->pot expansion
         // and paletted textures can't be sub-updated
-        if (ctx->supportsIndex8PixelConfig(sampler,
+        if (ctx->supportsIndex8PixelConfig(params,
                                            bitmap->width(), bitmap->height())) {
             size_t imagesize = bitmap->width() * bitmap->height() +
                                 kGrColorTableSize;
@@ -92,7 +92,7 @@
             // "rowBytes", since they are the same now.
             
             if (kUncached_CacheID != key) {
-                return ctx->createAndLockTexture(sampler, desc, storage.get(),
+                return ctx->createAndLockTexture(params, desc, storage.get(),
                                                  bitmap->width());
             } else {
                 entry = ctx->lockScratchTexture(desc,
@@ -112,7 +112,7 @@
 
     desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap->config());
     if (kUncached_CacheID != key) {
-        return ctx->createAndLockTexture(sampler, desc,
+        return ctx->createAndLockTexture(params, desc,
                                          bitmap->getPixels(),
                                          bitmap->rowBytes());
     } else {
@@ -130,7 +130,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 GrContext::TextureCacheEntry GrLockCachedBitmapTexture(GrContext* ctx, 
-                      const SkBitmap& bitmap, const GrSamplerState* sampler) {
+                                                       const SkBitmap& bitmap,
+                                                       const GrTextureParams* params) {
     GrContext::TextureCacheEntry entry;
 
     if (!bitmap.isVolatile()) {
@@ -143,14 +144,12 @@
         desc.fConfig = SkBitmapConfig2GrPixelConfig(bitmap.config());
         desc.fClientCacheID = key;
 
-        entry = ctx->findAndLockTexture(desc, sampler);
+        entry = ctx->findAndLockTexture(desc, params);
         if (NULL == entry.texture()) {
-            entry = sk_gr_create_bitmap_texture(ctx, key, sampler,
-                                                bitmap);
+            entry = sk_gr_create_bitmap_texture(ctx, key, params, bitmap);
         }
     } else {
-        entry = sk_gr_create_bitmap_texture(ctx, kUncached_CacheID,
-                                            sampler, bitmap);
+        entry = sk_gr_create_bitmap_texture(ctx, kUncached_CacheID, params, bitmap);
     }
     if (NULL == entry.texture()) {
         GrPrintf("---- failed to create texture for cache [%d %d]\n",
diff --git a/src/gpu/effects/GrGradientEffects.cpp b/src/gpu/effects/GrGradientEffects.cpp
index 375b783..9c186e2 100644
--- a/src/gpu/effects/GrGradientEffects.cpp
+++ b/src/gpu/effects/GrGradientEffects.cpp
@@ -66,7 +66,7 @@
     shader.asABitmap(&bitmap, NULL, NULL);
 
     GrContext::TextureCacheEntry entry = GrLockCachedBitmapTexture(ctx, bitmap,
-                                                                   sampler);
+                                                                   sampler->textureParams());
     fTexture = entry.texture();
     SkSafeRef(fTexture);
     fUseTexture = true;
diff --git a/src/gpu/gl/GrGLTexture.cpp b/src/gpu/gl/GrGLTexture.cpp
index 16a5015..e360874 100644
--- a/src/gpu/gl/GrGLTexture.cpp
+++ b/src/gpu/gl/GrGLTexture.cpp
@@ -14,15 +14,6 @@
 
 #define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
 
-const GrGLenum* GrGLTexture::WrapMode2GLWrap() {
-    static const GrGLenum repeatModes[] = {
-        GR_GL_CLAMP_TO_EDGE,
-        GR_GL_REPEAT,
-        GR_GL_MIRRORED_REPEAT
-    };
-    return repeatModes;
-};
-
 void GrGLTexture::init(GrGpuGL* gpu,
                        const Desc& textureDesc,
                        const GrGLRenderTarget::Desc* rtDesc) {
diff --git a/src/gpu/gl/GrGLTexture.h b/src/gpu/gl/GrGLTexture.h
index 8e8c8c5..1095d53 100644
--- a/src/gpu/gl/GrGLTexture.h
+++ b/src/gpu/gl/GrGLTexture.h
@@ -105,8 +105,6 @@
     // and it is up to the GrGpuGL derivative to handle y-mirroing.
     Orientation orientation() const { return fOrientation; }
 
-    static const GrGLenum* WrapMode2GLWrap();
-
 protected:
 
     // overrides of GrTexture
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 21cf3b8..79ea706 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -2087,18 +2087,6 @@
 }
 namespace {
 
-unsigned gr_to_gl_filter(GrSamplerState::Filter filter) {
-    switch (filter) {
-        case GrSamplerState::kBilinear_Filter:
-            return GR_GL_LINEAR;
-        case GrSamplerState::kNearest_Filter:
-            return GR_GL_NEAREST;
-        default:
-            GrAssert(!"Unknown filter type");
-            return GR_GL_LINEAR;
-    }
-}
-
 // get_swizzle is only called from this .cpp so it is OK to inline it here
 inline const GrGLenum* get_swizzle(GrPixelConfig config,
                                    const GrSamplerState& sampler,
@@ -2129,28 +2117,43 @@
                                   GR_GL_TEXTURE_SWIZZLE_RGBA,
                                   reinterpret_cast<const GrGLint*>(swizzle)));
 }
+
+const GrGLenum tile_to_gl_wrap(SkShader::TileMode tm) {
+    static const GrGLenum gWrapModes[] = {
+        GR_GL_CLAMP_TO_EDGE,
+        GR_GL_REPEAT,
+        GR_GL_MIRRORED_REPEAT
+    };
+    GrAssert((unsigned) tm <= 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];
+}
+
 }
 
 void GrGpuGL::flushBoundTextureAndParams(int stage) {
     GrDrawState* drawState = this->drawState();
 
-    GrGLTexture* nextTexture = 
-        static_cast<GrGLTexture*>(drawState->getTexture(stage));
-
-    flushBoundTextureAndParams(stage, nextTexture);
+    GrGLTexture* nextTexture =  static_cast<GrGLTexture*>(drawState->getTexture(stage));
+    // Currently we always use the texture params from the GrSamplerState. Soon custom stages
+    // will provide their own params.
+    const GrTextureParams& texParams = drawState->getSampler(stage).getTextureParams();
+    this->flushBoundTextureAndParams(stage, texParams, nextTexture);
 }
 
-void GrGpuGL::flushBoundTextureAndParams(int stage, GrGLTexture* nextTexture) {
+void GrGpuGL::flushBoundTextureAndParams(int stage,
+                                         const GrTextureParams& params,
+                                         GrGLTexture* nextTexture) {
     GrDrawState* drawState = this->drawState();
 
     // true for now, but maybe not with GrEffect.
     GrAssert(NULL != nextTexture);
-    // if we created a rt/tex and rendered to it without using a
-    // texture and now we're texturing from the rt it will still be
-    // the last bound texture, but it needs resolving. So keep this
+    // If we created a rt/tex and rendered to it without using a texture and now we're texturing
+    // from the rt it will still be the last bound texture, but it needs resolving. So keep this
     // out of the "last != next" check.
-    GrGLRenderTarget* texRT = 
-        static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget());
+    GrGLRenderTarget* texRT =  static_cast<GrGLRenderTarget*>(nextTexture->asRenderTarget());
     if (NULL != texRT) {
         this->onResolveRenderTarget(texRT);
     }
@@ -2162,20 +2165,18 @@
         fHWBoundTextures[stage] = nextTexture;
     }
 
-    const GrSamplerState& sampler = drawState->getSampler(stage);
     ResetTimestamp timestamp;
     const GrGLTexture::TexParams& oldTexParams =
                             nextTexture->getCachedTexParams(&timestamp);
     bool setAll = timestamp < this->getResetTimestamp();
     GrGLTexture::TexParams newTexParams;
 
-    newTexParams.fFilter = gr_to_gl_filter(sampler.getFilter());
+    newTexParams.fFilter = params.isBilerp() ? GR_GL_LINEAR : GR_GL_NEAREST;
 
-    const GrGLenum* wraps =  GrGLTexture::WrapMode2GLWrap();
-    newTexParams.fWrapS = wraps[sampler.getWrapX()];
-    newTexParams.fWrapT = wraps[sampler.getWrapY()];
+    newTexParams.fWrapS = tile_to_gl_wrap(params.getTileModeX());
+    newTexParams.fWrapT = tile_to_gl_wrap(params.getTileModeY());
     memcpy(newTexParams.fSwizzleRGBA,
-           get_swizzle(nextTexture->config(), sampler, this->glCaps()),
+           get_swizzle(nextTexture->config(), drawState->getSampler(stage), this->glCaps()),
            sizeof(newTexParams.fSwizzleRGBA));
     if (setAll || newTexParams.fFilter != oldTexParams.fFilter) {
         this->setTextureUnit(stage);
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index b3e8cf8..2e338a1 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -217,7 +217,9 @@
     // call to flushScissor must occur after all textures have been flushed via
     // this function.
     void flushBoundTextureAndParams(int stage);
-    void flushBoundTextureAndParams(int stage, GrGLTexture* nextTexture);
+    void flushBoundTextureAndParams(int stage,
+                                    const GrTextureParams& params,
+                                    GrGLTexture* nextTexture);
 
     // sets the texture matrix for the currently bound program
     void flushTextureMatrix(int stage);