Move texture domains onto a GrCustomStage, off of GrSamplerState.

This will require gyp changes to roll into Chrome.

http://codereview.appspot.com/6405050/



git-svn-id: http://skia.googlecode.com/svn/trunk@4641 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp
index 4a708d8..523ba52 100644
--- a/gyp/gpu.gyp
+++ b/gyp/gpu.gyp
@@ -295,6 +295,8 @@
         '../src/gpu/effects/GrMorphologyEffect.h',
         '../src/gpu/effects/GrSingleTextureEffect.cpp',
         '../src/gpu/effects/GrSingleTextureEffect.h',
+        '../src/gpu/effects/GrTextureDomainEffect.cpp',
+        '../src/gpu/effects/GrTextureDomainEffect.h',
 
         '../src/gpu/gl/GrGLCaps.cpp',
         '../src/gpu/gl/GrGLCaps.h',
diff --git a/include/gpu/GrSamplerState.h b/include/gpu/GrSamplerState.h
index 1f81afa..0731848 100644
--- a/include/gpu/GrSamplerState.h
+++ b/include/gpu/GrSamplerState.h
@@ -79,7 +79,6 @@
         fFilter = s.fFilter;
         fMatrix = s.fMatrix;
         fSwapRAndB = s.fSwapRAndB;
-        fTextureDomain = s.fTextureDomain;
 
         GrSafeAssign(fCustomStage, s.fCustomStage);
 
@@ -89,8 +88,6 @@
     WrapMode getWrapX() const { return fWrapX; }
     WrapMode getWrapY() const { return fWrapY; }
     const GrMatrix& getMatrix() const { return fMatrix; }
-    const GrRect& getTextureDomain() const { return fTextureDomain; }
-    bool hasTextureDomain() const {return SkIntToScalar(0) != fTextureDomain.right();}
     Filter getFilter() const { return fFilter; }
     bool swapsRAndB() const { return fSwapRAndB; }
 
@@ -104,13 +101,6 @@
     GrMatrix* matrix() { return &fMatrix; }
 
     /**
-     * Sets the sampler's texture coordinate domain to a 
-     * custom rectangle, rather than the default (0,1).
-     * This option is currently only supported with kClamp_WrapMode
-     */
-    void setTextureDomain(const GrRect& textureDomain) { fTextureDomain = textureDomain; }
-
-    /**
      * Swaps the R and B components when reading from the texture. Has no effect
      * if the texture is alpha only.
      */
@@ -141,7 +131,6 @@
         fWrapY = wrapXAndY;
         fFilter = filter;
         fMatrix = matrix;
-        fTextureDomain.setEmpty();
         fSwapRAndB = false;
         GrSafeSetNull(fCustomStage);
     }
@@ -167,7 +156,6 @@
     Filter              fFilter : 8;
     bool                fSwapRAndB;
     GrMatrix            fMatrix;
-    GrRect              fTextureDomain;
 
     GrCustomStage*      fCustomStage;
 };
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index dfded26..d0d4604 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -8,6 +8,7 @@
 #include "SkGpuDevice.h"
 
 #include "effects/GrGradientEffects.h"
+#include "effects/GrTextureDomainEffect.h"
 
 #include "GrContext.h"
 #include "GrTextContext.h"
@@ -1453,8 +1454,10 @@
             top = bottom = GrScalarHalf(paintRect.top() + paintRect.bottom());
         }
         textureDomain.setLTRB(left, top, right, bottom);  
+        sampler->setCustomStage(SkNEW_ARGS(GrTextureDomainEffect,
+                     (texture,
+                      textureDomain)))->unref();
     }
-    sampler->setTextureDomain(textureDomain);
 
     fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
 }
diff --git a/src/gpu/effects/GrTextureDomainEffect.cpp b/src/gpu/effects/GrTextureDomainEffect.cpp
new file mode 100644
index 0000000..e639df8
--- /dev/null
+++ b/src/gpu/effects/GrTextureDomainEffect.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrTextureDomainEffect.h"
+#include "gl/GrGLProgramStage.h"
+#include "GrProgramStageFactory.h"
+
+class GrGLTextureDomainEffect : public GrGLProgramStage {
+public:
+    GrGLTextureDomainEffect(const GrProgramStageFactory& factory,
+                            const GrCustomStage& stage);
+
+    virtual void setupVariables(GrGLShaderBuilder* state,
+                                int stage) SK_OVERRIDE;
+    virtual void emitVS(GrGLShaderBuilder* state,
+                        const char* vertexCoords) SK_OVERRIDE { }
+    virtual void emitFS(GrGLShaderBuilder* state,
+                        const char* outputColor,
+                        const char* inputColor,
+                        const char* samplerName) SK_OVERRIDE;
+
+    virtual void initUniforms(const GrGLInterface*, int programID) SK_OVERRIDE;
+
+    virtual void setData(const GrGLInterface*,
+                         const GrCustomStage&,
+                         const GrRenderTarget*,
+                         int stageNum) SK_OVERRIDE;
+
+    static inline StageKey GenKey(const GrCustomStage&) { return 0; }
+
+private:
+    const GrGLShaderVar* fNameVar;
+    int                  fNameLocation;
+
+    typedef GrGLProgramStage INHERITED;
+};
+
+GrGLTextureDomainEffect::GrGLTextureDomainEffect(const GrProgramStageFactory& factory,
+                                                 const GrCustomStage& stage)
+    : GrGLProgramStage(factory)
+    , fNameVar(NULL)
+    , fNameLocation(0) {
+}
+
+void GrGLTextureDomainEffect::setupVariables(GrGLShaderBuilder* state,
+                                             int stage) {
+    fNameVar = &state->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                  kVec4f_GrSLType, "uTexDom", stage);
+    fNameLocation = kUseUniform;
+};
+
+void GrGLTextureDomainEffect::emitFS(GrGLShaderBuilder* state,
+                                     const char* outputColor,
+                                     const char* inputColor,
+                                     const char* samplerName) {
+    SkString coordVar("clampCoord");
+    state->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
+                           GrGLShaderVar::TypeString(GrSLFloatVectorType(state->fCoordDims)),
+                           coordVar.c_str(),
+                           state->fSampleCoords.c_str(),
+                           fNameVar->getName().c_str(),
+                           fNameVar->getName().c_str());
+    state->fSampleCoords = coordVar;
+
+    state->emitDefaultFetch(outputColor, samplerName);
+}
+
+void GrGLTextureDomainEffect::initUniforms(const GrGLInterface* gl, int programID) {
+    GR_GL_CALL_RET(gl, fNameLocation,
+                   GetUniformLocation(programID, fNameVar->getName().c_str()));
+    GrAssert(kUnusedUniform != fNameLocation);
+}
+
+void GrGLTextureDomainEffect::setData(const GrGLInterface* gl,
+                         const GrCustomStage& data,
+                         const GrRenderTarget*,
+                         int stageNum) {
+    const GrTextureDomainEffect& effect = static_cast<const GrTextureDomainEffect&>(data);
+    const GrRect& domain = effect.domain();
+
+    float values[4] = {
+        GrScalarToFloat(domain.left()),
+        GrScalarToFloat(domain.top()),
+        GrScalarToFloat(domain.right()),
+        GrScalarToFloat(domain.bottom())
+    };
+    // vertical flip if necessary
+    const GrGLTexture* texture = static_cast<const GrGLTexture*>(effect.texture(0));
+    if (GrGLTexture::kBottomUp_Orientation == texture->orientation()) {
+        values[1] = 1.0f - values[1];
+        values[3] = 1.0f - values[3];
+        // The top and bottom were just flipped, so correct the ordering
+        // of elements so that values = (l, t, r, b).
+        SkTSwap(values[1], values[3]);
+    }
+
+    GR_GL_CALL(gl, Uniform4fv(fNameLocation, 1, values));
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture, GrRect domain)
+    : GrSingleTextureEffect(texture)
+    , fTextureDomain(domain) {
+
+}
+
+GrTextureDomainEffect::~GrTextureDomainEffect() {
+
+}
+
+const GrProgramStageFactory& GrTextureDomainEffect::getFactory() const {
+    return GrTProgramStageFactory<GrTextureDomainEffect>::getInstance();
+}
+
+bool GrTextureDomainEffect::isEqual(const GrCustomStage& sBase) const {
+    const GrTextureDomainEffect& s = static_cast<const GrTextureDomainEffect&>(sBase);
+    return (INHERITED::isEqual(sBase) && this->fTextureDomain == s.fTextureDomain);
+}
+
+
diff --git a/src/gpu/effects/GrTextureDomainEffect.h b/src/gpu/effects/GrTextureDomainEffect.h
new file mode 100644
index 0000000..6157175
--- /dev/null
+++ b/src/gpu/effects/GrTextureDomainEffect.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrTextureDomainEffect_DEFINED
+#define GrTextureDomainEffect_DEFINED
+
+//#include "GrCustomStage.h"
+#include "GrSingleTextureEffect.h"
+#include "GrRect.h"
+
+class GrGLTextureDomainEffect;
+
+/**
+ * Limits a texture's lookup coordinates to a domain.
+ */
+class GrTextureDomainEffect : public GrSingleTextureEffect {
+
+public:
+
+    GrTextureDomainEffect(GrTexture*, GrRect domain);
+    virtual ~GrTextureDomainEffect();
+
+    static const char* Name() { return "TextureDomain"; }
+
+    typedef GrGLTextureDomainEffect GLProgramStage;
+
+    virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
+    virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
+
+    const GrRect& domain() const { return fTextureDomain; }
+
+protected:
+
+    GrRect fTextureDomain;
+
+private:
+
+    typedef GrSingleTextureEffect INHERITED;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 4f549d0..49cb161 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -86,11 +86,6 @@
     *s = "uSampler";
     s->appendS32(stage);
 }
-
-inline void tex_domain_name(int stage, SkString* s) {
-    *s = "uTexDom";
-    s->appendS32(stage);
-}
 }
 
 GrGLProgram::GrGLProgram() {
@@ -1023,14 +1018,6 @@
                 GrAssert(kUnusedUniform != locations.fSamplerUni);
             }
 
-            if (kUseUniform == locations.fTexDomUni) {
-                SkString texDomName;
-                tex_domain_name(s, &texDomName);
-                GL_CALL_RET(locations.fTexDomUni,
-                            GetUniformLocation(fProgramID, texDomName.c_str()));
-                GrAssert(kUnusedUniform != locations.fTexDomUni);
-            }
-
             if (NULL != fProgramStage[s]) {
                 fProgramStage[s]->initUniforms(&builder, gl.interface(), fProgramID);
             }
@@ -1044,7 +1031,6 @@
             GL_CALL(Uniform1i(fUniLocations.fStages[s].fSamplerUni, s));
         }
         fTextureMatrices[s] = GrMatrix::InvalidMatrix();
-        fTextureDomain[s].setEmpty();
         // this is arbitrary, just initialize to something
         fTextureOrientation[s] = GrGLTexture::kBottomUp_Orientation;
         // Must not reset fStageOverride[] here.
@@ -1154,22 +1140,6 @@
         (StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
          StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
 
-    if (desc.fOptFlags & StageDesc::kCustomTextureDomain_OptFlagBit) {
-        SkString texDomainName;
-        tex_domain_name(stageNum, &texDomainName);
-        segments->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                             kVec4f_GrSLType, texDomainName.c_str());
-        SkString coordVar("clampCoord");
-        segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
-                                  float_vector_type_str(segments->fCoordDims),
-                                  coordVar.c_str(),
-                                  segments->fSampleCoords.c_str(),
-                                  texDomainName.c_str(),
-                                  texDomainName.c_str());
-        segments->fSampleCoords = coordVar;
-        locations.fTexDomUni = kUseUniform;
-    }
-
     // NOTE: GrGLProgramStages are now responsible for fetching
     if (NULL == customStage) {
         if (desc.fInConfigFlags & kMulByAlphaMask) {
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index c397d74..9381cfb 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -112,7 +112,6 @@
             enum OptFlagBits {
                 kNoPerspective_OptFlagBit       = 1 << 0,
                 kIdentityMatrix_OptFlagBit      = 1 << 1,
-                kCustomTextureDomain_OptFlagBit = 1 << 2,
                 kIsEnabled_OptFlagBit           = 1 << 7
             };
 
@@ -322,10 +321,9 @@
     GrColor                     fColor;
     GrColor                     fCoverage;
     GrColor                     fColorFilterColor;
+    /// When it is sent to GL, the texture matrix will be flipped if the texture orientation
+    /// (below) requires.
     GrMatrix                    fTextureMatrices[GrDrawState::kNumStages];
-    GrRect                      fTextureDomain[GrDrawState::kNumStages];
-    // The texture domain and texture matrix sent to GL depend upon the
-    // orientation.
     GrGLTexture::Orientation    fTextureOrientation[GrDrawState::kNumStages];
 
     GrGLProgramStage*           fProgramStage[GrDrawState::kNumStages];
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 077f807..7f982e7 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -248,30 +248,6 @@
             fCurrentProgram->fTextureMatrices[s] = samplerMatrix;
         }
 
-        const GrGLint& domUni =  fCurrentProgram->fUniLocations.fStages[s].fTexDomUni;
-        const GrRect &texDom = drawState.getSampler(s).getTextureDomain();
-        if (GrGLProgram::kUnusedUniform != domUni &&
-            (orientationChange ||fCurrentProgram->fTextureDomain[s] != texDom)) {
-
-            fCurrentProgram->fTextureDomain[s] = texDom;
-
-            float values[4] = {
-                GrScalarToFloat(texDom.left()),
-                GrScalarToFloat(texDom.top()),
-                GrScalarToFloat(texDom.right()),
-                GrScalarToFloat(texDom.bottom())
-            };
-
-            // vertical flip if necessary
-            if (GrGLTexture::kBottomUp_Orientation == texture->orientation()) {
-                values[1] = 1.0f - values[1];
-                values[3] = 1.0f - values[3];
-                // The top and bottom were just flipped, so correct the ordering
-                // of elements so that values = (l, t, r, b).
-                SkTSwap(values[1], values[3]);
-            }
-            GL_CALL(Uniform4fv(domUni, 1, values));
-        }
         fCurrentProgram->fTextureOrientation[s] = texture->orientation();
     }
 }
@@ -768,14 +744,6 @@
                 stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit;
             }
 
-            if (sampler.hasTextureDomain()) {
-                GrAssert(GrSamplerState::kClamp_WrapMode ==
-                            sampler.getWrapX() &&
-                         GrSamplerState::kClamp_WrapMode ==
-                            sampler.getWrapY());
-                stage.fOptFlags |= StageDesc::kCustomTextureDomain_OptFlagBit;
-            }
-
             stage.fInConfigFlags = 0;
             if (!this->glCaps().textureSwizzleSupport()) {
                 if (GrPixelConfigIsAlphaOnly(texture->config())) {