Attempt to reland 8264-5 with warning-as-error fixes.




git-svn-id: http://skia.googlecode.com/svn/trunk@8272 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkTLazy.h b/include/core/SkTLazy.h
index b9052f0..1934b5d 100644
--- a/include/core/SkTLazy.h
+++ b/include/core/SkTLazy.h
@@ -14,6 +14,9 @@
 #include "SkTypes.h"
 #include <new>
 
+template <typename T> class SkTLazy;
+template <typename T> void* operator new(size_t, SkTLazy<T>* lazy);
+
 /**
  *  Efficient way to defer allocating/initializing a class until it is needed
  *  (if ever).
@@ -44,7 +47,7 @@
 
     /**
      *  Return a pointer to a default-initialized instance of the class. If a
-     *  previous instance had been initialzied (either from init() or set()) it
+     *  previous instance had been initialized (either from init() or set()) it
      *  will first be destroyed, so that a freshly initialized instance is
      *  always returned.
      */
@@ -84,10 +87,27 @@
     T* get() const { SkASSERT(this->isValid()); return fPtr; }
 
 private:
+    friend void* operator new<T>(size_t, SkTLazy* lazy);
+
     T*   fPtr; // NULL or fStorage
     char fStorage[sizeof(T)];
 };
 
+// Use the below macro (SkNEW_IN_TLAZY) rather than calling this directly
+template <typename T> void* operator new(size_t, SkTLazy<T>* lazy) {
+    SkASSERT(!lazy->isValid());
+    lazy->fPtr = reinterpret_cast<T*>(lazy->fStorage);
+    return lazy->fPtr;
+}
+
+// Skia doesn't use C++ exceptions but it may be compiled with them enabled. Having an op delete
+// to match the op new silences warnings about missing op delete when a constructor throws an
+// exception.
+template <typename T> void operator delete(void*, SkTLazy<T>) { SK_CRASH(); }
+
+// Use this to construct a T inside an SkTLazy using a non-default constructor.
+#define SkNEW_IN_TLAZY(tlazy_ptr, type_name, args) (new (tlazy_ptr) type_name args)
+
 /**
  * A helper built on top of SkTLazy to do copy-on-first-write. The object is initialized
  * with a const pointer but provides a non-const pointer accessor. The first time the
diff --git a/include/gpu/GrBackendEffectFactory.h b/include/gpu/GrBackendEffectFactory.h
index 99d6a73..da296c9 100644
--- a/include/gpu/GrBackendEffectFactory.h
+++ b/include/gpu/GrBackendEffectFactory.h
@@ -24,16 +24,16 @@
  */
 
 class GrEffectRef;
-class GrEffectStage;
 class GrGLEffect;
 class GrGLCaps;
+class GrDrawEffect;
 
 class GrBackendEffectFactory : public GrNoncopyable {
 public:
     typedef uint32_t EffectKey;
     enum {
         kNoEffectKey = 0,
-        kEffectKeyBits = 12,
+        kEffectKeyBits = 16,
         /**
          * Some aspects of the generated code may be determined by the particular textures that are
          * associated with the effect. These manipulations are performed by GrGLShaderBuilder beyond
@@ -44,8 +44,8 @@
         kAttribKeyBits = 6
     };
 
-    virtual EffectKey glEffectKey(const GrEffectStage&, const GrGLCaps&) const = 0;
-    virtual GrGLEffect* createGLInstance(const GrEffectRef&) const = 0;
+    virtual EffectKey glEffectKey(const GrDrawEffect&, const GrGLCaps&) const = 0;
+    virtual GrGLEffect* createGLInstance(const GrDrawEffect&) const = 0;
 
     bool operator ==(const GrBackendEffectFactory& b) const {
         return fEffectClassID == b.fEffectClassID;
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 79edd0b..2d57660 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -390,25 +390,23 @@
                   const SkMatrix* matrix = NULL);
 
     /**
-     * Maps a rect of paint coordinates onto the a rect of destination
-     * coordinates. Each rect can optionally be transformed. The srcRect
+     * Maps a rect of local coordinates onto the a rect of destination
+     * coordinates. Each rect can optionally be transformed. The localRect
      * is stretched over the dstRect. The dstRect is transformed by the
-     * context's matrix and the srcRect is transformed by the paint's matrix.
-     * Additional optional matrices can be provided by parameters.
+     * context's matrix. Additional optional matrices for both rects can be
+     * provided by parameters.
      *
-     * @param paint     describes how to color pixels.
-     * @param dstRect   the destination rect to draw.
-     * @param srcRect   rect of paint coordinates to be mapped onto dstRect
-     * @param dstMatrix Optional matrix to transform dstRect. Applied before
-     *                  context's matrix.
-     * @param srcMatrix Optional matrix to transform srcRect Applied before
-     *                  paint's matrix.
+     * @param paint         describes how to color pixels.
+     * @param dstRect       the destination rect to draw.
+     * @param localRect     rect of local coordinates to be mapped onto dstRect
+     * @param dstMatrix     Optional matrix to transform dstRect. Applied before context's matrix.
+     * @param localMatrix   Optional matrix to transform localRect.
      */
     void drawRectToRect(const GrPaint& paint,
                         const GrRect& dstRect,
-                        const GrRect& srcRect,
+                        const GrRect& localRect,
                         const SkMatrix* dstMatrix = NULL,
-                        const SkMatrix* srcMatrix = NULL);
+                        const SkMatrix* localMatrix = NULL);
 
     /**
      * Draws a path.
@@ -699,7 +697,7 @@
             this->restore();
 
             if (NULL != paint) {
-                if (!paint->sourceCoordChangeByInverse(context->getMatrix())) {
+                if (!paint->localCoordChangeInverse(context->getMatrix())) {
                     return false;
                 }
             }
@@ -737,7 +735,7 @@
          */
         void preConcat(const SkMatrix& preConcat, GrPaint* paint = NULL) {
             if (NULL != paint) {
-                paint->sourceCoordChange(preConcat);
+                paint->localCoordChange(preConcat);
             }
             fContext->concatMatrix(preConcat);
         }
diff --git a/include/gpu/GrDrawEffect.h b/include/gpu/GrDrawEffect.h
new file mode 100644
index 0000000..005de41
--- /dev/null
+++ b/include/gpu/GrDrawEffect.h
@@ -0,0 +1,51 @@
+
+#ifndef GrDrawEffect_DEFINED
+#define GrDrawEffect_DEFINED
+
+#include "GrEffectStage.h"
+
+/**
+ * This class is used to communicate the particular GrEffect used in a draw to the backend-specific
+ * effect subclass (e.g. GrGLEffect). It is used to by the backend-specific class to generate a
+ * cache key for the effect, generate code on a program cache miss, and to upload uniform values to
+ * the program.
+ * In addition to the effect, it also communicates any changes between the relationship between
+ * the view matrix and local coordinate system since the effect was installed in its GrDrawState.
+ * The typical use case is that sometime after an effect was installed a decision was made to draw
+ * in device coordinates (i.e. use an identity view-matrix). In such a case the GrDrawEffect's
+ * coord-change-matrix would be the inverse of the view matrix that was set when the effect was
+ * installed. GrGLEffectMatrix is a handy class that implements a local coordinate matrix that
+ * automatically accounts for the coord-change matrix.
+ */
+class GrDrawEffect {
+public:
+    GrDrawEffect(const GrEffectStage& stage, bool explicitLocalCoords)
+        : fEffectStage(&stage)
+        , fExplicitLocalCoords(explicitLocalCoords) {
+        GrAssert(NULL != fEffectStage);
+        GrAssert(NULL != fEffectStage->getEffect());
+    }
+    const GrEffectRef* effect() const { return fEffectStage->getEffect(); }
+
+    template <typename T>
+    const T& castEffect() const { return *static_cast<const T*>(this->effect()->get()); }
+
+    const SkMatrix& getCoordChangeMatrix() const {
+        if (fExplicitLocalCoords) {
+            return SkMatrix::I();
+        } else {
+            return fEffectStage->getCoordChangeMatrix();
+        }
+    }
+
+    bool programHasExplicitLocalCoords() const { return fExplicitLocalCoords; }
+
+    const int* getVertexAttribIndices() const { return fEffectStage->getVertexAttribIndices(); }
+    int getVertexAttribIndexCount() const { return fEffectStage->getVertexAttribIndexCount(); }
+
+private:
+    const GrEffectStage*    fEffectStage;
+    bool                    fExplicitLocalCoords;
+};
+
+#endif
diff --git a/include/gpu/GrEffect.h b/include/gpu/GrEffect.h
index 1b26041..8834386 100644
--- a/include/gpu/GrEffect.h
+++ b/include/gpu/GrEffect.h
@@ -70,6 +70,20 @@
 public:
     SK_DECLARE_INST_COUNT(GrEffect)
 
+    /**
+     * The types of vertex coordinates available to an effect in the vertex shader. Effects can
+     * require their own vertex attribute but these coordinates are made available by the framework
+     * in all programs. kCustom_CoordsType is provided to signify that an alternative set of coords
+     * is used (usually an explicit vertex attribute) but its meaning is determined by the effect
+     * subclass.
+     */
+    enum CoordsType {
+        kLocal_CoordsType,
+        kPosition_CoordsType,
+
+        kCustom_CoordsType,
+    };
+
     virtual ~GrEffect();
 
     /**
diff --git a/include/gpu/GrEffectStage.h b/include/gpu/GrEffectStage.h
index f4e46b0..94ff779 100644
--- a/include/gpu/GrEffectStage.h
+++ b/include/gpu/GrEffectStage.h
@@ -58,9 +58,10 @@
     /**
      * This is called when the coordinate system in which the geometry is specified will change.
      *
-     * @param matrix    The transformation from the old coord system to the new one.
+     * @param matrix    The transformation from the old coord system in which geometry is specified
+     *                  to the new one from which it will actually be drawn.
      */
-    void preConcatCoordChange(const SkMatrix& matrix) { fCoordChangeMatrix.preConcat(matrix); }
+    void localCoordChange(const SkMatrix& matrix) { fCoordChangeMatrix.preConcat(matrix); }
 
     class SavedCoordChange {
     private:
@@ -72,7 +73,7 @@
 
     /**
      * This gets the current coordinate system change. It is the accumulation of
-     * preConcatCoordChange calls since the effect was installed. It is used when then caller
+     * localCoordChange calls since the effect was installed. It is used when then caller
      * wants to temporarily change the source geometry coord system, draw something, and then
      * restore the previous coord system (e.g. temporarily draw in device coords).
      */
diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h
index 0fd42f9..e0a9203 100644
--- a/include/gpu/GrPaint.h
+++ b/include/gpu/GrPaint.h
@@ -169,54 +169,6 @@
 
     bool hasStage() const { return this->hasColorStage() || this->hasCoverageStage(); }
 
-    /**
-     * Called when the source coord system is changing. preConcatInverse is the inverse of the
-     * transformation from the old coord system to the new coord system. Returns false if the matrix
-     * cannot be inverted.
-     */
-    bool sourceCoordChangeByInverse(const SkMatrix& preConcatInverse) {
-        SkMatrix inv;
-        bool computed = false;
-        for (int i = 0; i < kMaxColorStages; ++i) {
-            if (this->isColorStageEnabled(i)) {
-                if (!computed && !preConcatInverse.invert(&inv)) {
-                    return false;
-                } else {
-                    computed = true;
-                }
-                fColorStages[i].preConcatCoordChange(inv);
-            }
-        }
-        for (int i = 0; i < kMaxCoverageStages; ++i) {
-            if (this->isCoverageStageEnabled(i)) {
-                if (!computed && !preConcatInverse.invert(&inv)) {
-                    return false;
-                } else {
-                    computed = true;
-                }
-                fCoverageStages[i].preConcatCoordChange(inv);
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Called when the source coord system is changing. preConcat gives the transformation from the
-     * old coord system to the new coord system.
-     */
-    void sourceCoordChange(const SkMatrix& preConcat) {
-        for (int i = 0; i < kMaxColorStages; ++i) {
-            if (this->isColorStageEnabled(i)) {
-                fColorStages[i].preConcatCoordChange(preConcat);
-            }
-        }
-        for (int i = 0; i < kMaxCoverageStages; ++i) {
-            if (this->isCoverageStageEnabled(i)) {
-                fCoverageStages[i].preConcatCoordChange(preConcat);
-            }
-        }
-    }
-
     GrPaint& operator=(const GrPaint& paint) {
         fSrcBlendCoeff = paint.fSrcBlendCoeff;
         fDstBlendCoeff = paint.fDstBlendCoeff;
@@ -264,6 +216,51 @@
     };
 
 private:
+    /**
+     * Called when the source coord system from which geometry is rendered changes. It ensures that
+     * the local coordinates seen by effects remains unchanged. oldToNew gives the transformation
+     * from the previous coord system to the new coord system.
+     */
+    void localCoordChange(const SkMatrix& oldToNew) {
+        for (int i = 0; i < kMaxColorStages; ++i) {
+            if (this->isColorStageEnabled(i)) {
+                fColorStages[i].localCoordChange(oldToNew);
+            }
+        }
+        for (int i = 0; i < kMaxCoverageStages; ++i) {
+            if (this->isCoverageStageEnabled(i)) {
+                fCoverageStages[i].localCoordChange(oldToNew);
+            }
+        }
+    }
+
+    bool localCoordChangeInverse(const SkMatrix& newToOld) {
+        SkMatrix oldToNew;
+        bool computed = false;
+        for (int i = 0; i < kMaxColorStages; ++i) {
+            if (this->isColorStageEnabled(i)) {
+                if (!computed && !newToOld.invert(&oldToNew)) {
+                    return false;
+                } else {
+                    computed = true;
+                }
+                fColorStages[i].localCoordChange(oldToNew);
+            }
+        }
+        for (int i = 0; i < kMaxCoverageStages; ++i) {
+            if (this->isCoverageStageEnabled(i)) {
+                if (!computed && !newToOld.invert(&oldToNew)) {
+                    return false;
+                } else {
+                    computed = true;
+                }
+                fCoverageStages[i].localCoordChange(oldToNew);
+            }
+        }
+        return true;
+    }
+
+    friend class GrContext; // To access above two functions
 
     GrEffectStage               fColorStages[kMaxColorStages];
     GrEffectStage               fCoverageStages[kMaxCoverageStages];
diff --git a/include/gpu/GrTBackendEffectFactory.h b/include/gpu/GrTBackendEffectFactory.h
index 1b6f816..8697f8e 100644
--- a/include/gpu/GrTBackendEffectFactory.h
+++ b/include/gpu/GrTBackendEffectFactory.h
@@ -9,7 +9,7 @@
 #define GrTBackendEffectFactory_DEFINED
 
 #include "GrBackendEffectFactory.h"
-#include "GrEffectStage.h"
+#include "GrDrawEffect.h"
 
 /**
  * Implements GrBackendEffectFactory for a GrEffect subclass as a singleton.
@@ -30,12 +30,12 @@
         id identifies the GrEffect subclass. The remainder is based
         on the aspects of the GrEffect object's configuration that affect
         GLSL code generation. */
-    virtual EffectKey glEffectKey(const GrEffectStage& stage,
+    virtual EffectKey glEffectKey(const GrDrawEffect& drawEffect,
                                   const GrGLCaps& caps) const SK_OVERRIDE {
         GrAssert(kIllegalEffectClassID != fEffectClassID);
-        EffectKey effectKey = GLEffect::GenKey(stage, caps);
-        EffectKey textureKey = GLEffect::GenTextureKey(stage.getEffect(), caps);
-        EffectKey attribKey = GLEffect::GenAttribKey(stage);
+        EffectKey effectKey = GLEffect::GenKey(drawEffect, caps);
+        EffectKey textureKey = GLEffect::GenTextureKey(drawEffect, caps);
+        EffectKey attribKey = GLEffect::GenAttribKey(drawEffect);
 #if GR_DEBUG
         static const EffectKey kIllegalIDMask = (uint16_t) (~((1U << kEffectKeyBits) - 1));
         GrAssert(!(kIllegalIDMask & effectKey));
@@ -53,8 +53,8 @@
     /** Returns a new instance of the appropriate *GL* implementation class
         for the given GrEffect; caller is responsible for deleting
         the object. */
-    virtual GLEffect* createGLInstance(const GrEffectRef& effect) const SK_OVERRIDE {
-        return SkNEW_ARGS(GLEffect, (*this, effect));
+    virtual GLEffect* createGLInstance(const GrDrawEffect& drawEffect) const SK_OVERRIDE {
+        return SkNEW_ARGS(GLEffect, (*this, drawEffect));
     }
 
     /** This class is a singleton. This function returns the single instance.
diff --git a/src/effects/SkBicubicImageFilter.cpp b/src/effects/SkBicubicImageFilter.cpp
index f4d474d..507612e 100644
--- a/src/effects/SkBicubicImageFilter.cpp
+++ b/src/effects/SkBicubicImageFilter.cpp
@@ -185,18 +185,17 @@
 class GrGLBicubicEffect : public GrGLEffect {
 public:
     GrGLBicubicEffect(const GrBackendEffectFactory& factory,
-                      const GrEffectRef& effect);
+                      const GrDrawEffect&);
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 private:
     typedef GrGLUniformManager::UniformHandle        UniformHandle;
@@ -210,21 +209,21 @@
 };
 
 GrGLBicubicEffect::GrGLBicubicEffect(const GrBackendEffectFactory& factory,
-                                     const GrEffectRef& effect)
+                                     const GrDrawEffect& drawEffect)
     : INHERITED(factory)
     , fCoefficientsUni(GrGLUniformManager::kInvalidUniformHandle)
-    , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle) {
+    , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle)
+    , fEffectMatrix(drawEffect.castEffect<GrBicubicEffect>().coordsType()) {
 }
 
 void GrGLBicubicEffect::emitCode(GrGLShaderBuilder* builder,
-                                 const GrEffectStage&,
+                                 const GrDrawEffect&,
                                  EffectKey key,
-                                 const char* vertexCoords,
                                  const char* outputColor,
                                  const char* inputColor,
                                  const TextureSamplerArray& samplers) {
     const char* coords;
-    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
     fCoefficientsUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                            kMat44f_GrSLType, "Coefficients");
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
@@ -269,17 +268,18 @@
     builder->fsCodeAppendf("\t%s = %s(%s, f.y, s0, s1, s2, s3);\n", outputColor, cubicBlendName.c_str(), coeff);
 }
 
-GrGLEffect::EffectKey GrGLBicubicEffect::GenKey(const GrEffectStage& s, const GrGLCaps&) {
-    const GrBicubicEffect& m = GetEffectFromStage<GrBicubicEffect>(s);
-    EffectKey matrixKey = GrGLEffectMatrix::GenKey(m.getMatrix(),
-                                                   s.getCoordChangeMatrix(),
-                                                   m.texture(0));
+GrGLEffect::EffectKey GrGLBicubicEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+    const GrBicubicEffect& bicubic = drawEffect.castEffect<GrBicubicEffect>();
+    EffectKey matrixKey = GrGLEffectMatrix::GenKey(bicubic.getMatrix(),
+                                                   drawEffect,
+                                                   bicubic.coordsType(),
+                                                   bicubic.texture(0));
     return matrixKey;
 }
 
 void GrGLBicubicEffect::setData(const GrGLUniformManager& uman,
-                                const GrEffectStage& stage) {
-    const GrBicubicEffect& effect = GetEffectFromStage<GrBicubicEffect>(stage);
+                                const GrDrawEffect& drawEffect) {
+    const GrBicubicEffect& effect = drawEffect.castEffect<GrBicubicEffect>();
     GrTexture& texture = *effect.texture(0);
     float imageIncrement[2];
     imageIncrement[0] = 1.0f / texture.width();
@@ -288,7 +288,7 @@
     uman.setMatrix4f(fCoefficientsUni, effect.coefficients());
     fEffectMatrix.setData(uman,
                           effect.getMatrix(),
-                          stage.getCoordChangeMatrix(),
+                          drawEffect,
                           effect.texture(0));
 }
 
diff --git a/src/effects/SkBlendImageFilter.cpp b/src/effects/SkBlendImageFilter.cpp
index ae129eb..1c85fe5 100644
--- a/src/effects/SkBlendImageFilter.cpp
+++ b/src/effects/SkBlendImageFilter.cpp
@@ -94,23 +94,23 @@
 #if SK_SUPPORT_GPU
 class GrGLBlendEffect : public GrGLEffect {
 public:
-    GrGLBlendEffect(const GrBackendEffectFactory& factory,
-                    const GrEffectRef& effect);
+    GrGLBlendEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
     virtual ~GrGLBlendEffect();
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&);
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 private:
+    static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType;
+
     SkBlendImageFilter::Mode    fMode;
     GrGLEffectMatrix            fForegroundEffectMatrix;
     GrGLEffectMatrix            fBackgroundEffectMatrix;
@@ -131,13 +131,13 @@
 
     virtual ~GrBlendEffect();
 
-    const GrBackendEffectFactory& getFactory() const;
+    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
     SkBlendImageFilter::Mode mode() const { return fMode; }
 
     typedef GrGLBlendEffect GLEffect;
     static const char* Name() { return "Blend"; }
 
-    void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
 
 private:
     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
@@ -224,27 +224,27 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-GrGLBlendEffect::GrGLBlendEffect(const GrBackendEffectFactory& factory, const GrEffectRef& effect)
-    : INHERITED(factory),
-      fMode(CastEffect<GrBlendEffect>(effect).mode()) {
+GrGLBlendEffect::GrGLBlendEffect(const GrBackendEffectFactory& factory,
+                                 const GrDrawEffect& drawEffect)
+    : INHERITED(factory)
+    , fMode(drawEffect.castEffect<GrBlendEffect>().mode())
+    , fForegroundEffectMatrix(kCoordsType)
+    , fBackgroundEffectMatrix(kCoordsType) {
 }
 
 GrGLBlendEffect::~GrGLBlendEffect() {
 }
 
 void GrGLBlendEffect::emitCode(GrGLShaderBuilder* builder,
-                               const GrEffectStage&,
+                               const GrDrawEffect&,
                                EffectKey key,
-                               const char* vertexCoords,
                                const char* outputColor,
                                const char* inputColor,
                                const TextureSamplerArray& samplers) {
     const char* fgCoords;
     const char* bgCoords;
-    GrSLType fgCoordsType =  fForegroundEffectMatrix.emitCode(
-        builder, key, vertexCoords, &fgCoords, NULL, "FG");
-    GrSLType bgCoordsType =  fBackgroundEffectMatrix.emitCode(
-        builder, key, vertexCoords, &bgCoords, NULL, "BG");
+    GrSLType fgCoordsType = fForegroundEffectMatrix.emitCode(builder, key, &fgCoords, NULL, "FG");
+    GrSLType bgCoordsType = fBackgroundEffectMatrix.emitCode(builder, key, &bgCoords, NULL, "BG");
 
     const char* bgColor = "bgColor";
     const char* fgColor = "fgColor";
@@ -283,33 +283,35 @@
     }
 }
 
-void GrGLBlendEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    const GrBlendEffect& blend = GetEffectFromStage<GrBlendEffect>(stage);
+void GrGLBlendEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
+    const GrBlendEffect& blend = drawEffect.castEffect<GrBlendEffect>();
     GrTexture* fgTex = blend.texture(0);
     GrTexture* bgTex = blend.texture(1);
     fForegroundEffectMatrix.setData(uman,
                                     GrEffect::MakeDivByTextureWHMatrix(fgTex),
-                                    stage.getCoordChangeMatrix(),
+                                    drawEffect,
                                     fgTex);
     fBackgroundEffectMatrix.setData(uman,
                                     GrEffect::MakeDivByTextureWHMatrix(bgTex),
-                                    stage.getCoordChangeMatrix(),
+                                    drawEffect,
                                     bgTex);
 
 }
 
-GrGLEffect::EffectKey GrGLBlendEffect::GenKey(const GrEffectStage& stage, const GrGLCaps&) {
-    const GrBlendEffect& blend = GetEffectFromStage<GrBlendEffect>(stage);
+GrGLEffect::EffectKey GrGLBlendEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+    const GrBlendEffect& blend = drawEffect.castEffect<GrBlendEffect>();
 
     GrTexture* fgTex = blend.texture(0);
     GrTexture* bgTex = blend.texture(1);
 
     EffectKey fgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(fgTex),
-                                               stage.getCoordChangeMatrix(),
+                                               drawEffect,
+                                               kCoordsType,
                                                fgTex);
 
     EffectKey bgKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(bgTex),
-                                               stage.getCoordChangeMatrix(),
+                                               drawEffect,
+                                               kCoordsType,
                                                bgTex);
     bgKey <<= GrGLEffectMatrix::kKeyBits;
     EffectKey modeKey = blend.mode() << (2 * GrGLEffectMatrix::kKeyBits);
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index b39c5f8..55e8bba 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -386,18 +386,17 @@
     class GLEffect : public GrGLEffect {
     public:
         // this class always generates the same code.
-        static EffectKey GenKey(const GrEffectStage&, const GrGLCaps&) { return 0; }
+        static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { return 0; }
 
         GLEffect(const GrBackendEffectFactory& factory,
-                 const GrEffectRef& effect)
+                 const GrDrawEffect&)
         : INHERITED(factory)
         , fMatrixHandle(GrGLUniformManager::kInvalidUniformHandle)
         , fVectorHandle(GrGLUniformManager::kInvalidUniformHandle) {}
 
         virtual void emitCode(GrGLShaderBuilder* builder,
-                              const GrEffectStage&,
+                              const GrDrawEffect&,
                               EffectKey,
-                              const char* vertexCoords,
                               const char* outputColor,
                               const char* inputColor,
                               const TextureSamplerArray&) SK_OVERRIDE {
@@ -424,8 +423,8 @@
         }
 
         virtual void setData(const GrGLUniformManager& uniManager,
-                             const GrEffectStage& stage) SK_OVERRIDE {
-            const ColorMatrixEffect& cme = GetEffectFromStage<ColorMatrixEffect>(stage);
+                             const GrDrawEffect& drawEffect) SK_OVERRIDE {
+            const ColorMatrixEffect& cme = drawEffect.castEffect<ColorMatrixEffect>();
             const float* m = cme.fMatrix.fMat;
             // The GL matrix is transposed from SkColorMatrix.
             GrGLfloat mt[]  = {
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index 9c89a6a..ae570ce 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -201,22 +201,23 @@
 class GrGLDisplacementMapEffect : public GrGLEffect {
 public:
     GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
-                              const GrEffectRef& effect);
+                              const GrDrawEffect& drawEffect);
     virtual ~GrGLDisplacementMapEffect();
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&);
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 private:
+    static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType;
+
     SkDisplacementMapEffect::ChannelSelectorType fXChannelSelector;
     SkDisplacementMapEffect::ChannelSelectorType fYChannelSelector;
     GrGLEffectMatrix fDisplacementEffectMatrix;
@@ -245,7 +246,7 @@
 
     virtual ~GrDisplacementMapEffect();
 
-    const GrBackendEffectFactory& getFactory() const;
+    virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
     SkDisplacementMapEffect::ChannelSelectorType xChannelSelector() const
         { return fXChannelSelector; }
     SkDisplacementMapEffect::ChannelSelectorType yChannelSelector() const
@@ -255,9 +256,10 @@
     typedef GrGLDisplacementMapEffect GLEffect;
     static const char* Name() { return "DisplacementMap"; }
 
-    void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
 
 private:
+    
     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
 
     GrDisplacementMapEffect(SkDisplacementMapEffect::ChannelSelectorType xChannelSelector,
@@ -382,32 +384,33 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 GrGLDisplacementMapEffect::GrGLDisplacementMapEffect(const GrBackendEffectFactory& factory,
-                                                     const GrEffectRef& effect)
+                                                     const GrDrawEffect& drawEffect)
     : INHERITED(factory)
-    , fXChannelSelector(CastEffect<GrDisplacementMapEffect>(effect).xChannelSelector())
-    , fYChannelSelector(CastEffect<GrDisplacementMapEffect>(effect).yChannelSelector()) {
+    , fXChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().xChannelSelector())
+    , fYChannelSelector(drawEffect.castEffect<GrDisplacementMapEffect>().yChannelSelector())
+    , fDisplacementEffectMatrix(kCoordsType)
+    , fColorEffectMatrix(kCoordsType) {
 }
 
 GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
 }
 
 void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder,
-                               const GrEffectStage&,
-                               EffectKey key,
-                               const char* vertexCoords,
-                               const char* outputColor,
-                               const char* inputColor,
-                               const TextureSamplerArray& samplers) {
+                                         const GrDrawEffect&,
+                                         EffectKey key,
+                                         const char* outputColor,
+                                         const char* inputColor,
+                                         const TextureSamplerArray& samplers) {
     fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                     kVec2f_GrSLType, "Scale");
     const char* scaleUni = builder->getUniformCStr(fScaleUni);
 
     const char* dCoordsIn;
     GrSLType dCoordsType = fDisplacementEffectMatrix.emitCode(
-                                builder, key, vertexCoords, &dCoordsIn, NULL, "DISPL");
+                                builder, key, &dCoordsIn, NULL, "DISPL");
     const char* cCoordsIn;
     GrSLType cCoordsType = fColorEffectMatrix.emitCode(
-                                builder, key, vertexCoords, &cCoordsIn, NULL, "COLOR");
+                                builder, key, &cCoordsIn, NULL, "COLOR");
 
     const char* dColor = "dColor";
     const char* cCoords = "cCoords";
@@ -478,17 +481,19 @@
     builder->fsCodeAppend(";\n");
 }
 
-void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    const GrDisplacementMapEffect& displacementMap = GetEffectFromStage<GrDisplacementMapEffect>(stage);
+void GrGLDisplacementMapEffect::setData(const GrGLUniformManager& uman,
+                                        const GrDrawEffect& drawEffect) {
+    const GrDisplacementMapEffect& displacementMap =
+        drawEffect.castEffect<GrDisplacementMapEffect>();
     GrTexture* displTex = displacementMap.texture(0);
     GrTexture* colorTex = displacementMap.texture(1);
     fDisplacementEffectMatrix.setData(uman,
                                      GrEffect::MakeDivByTextureWHMatrix(displTex),
-                                     stage.getCoordChangeMatrix(),
+                                     drawEffect,
                                      displTex);
     fColorEffectMatrix.setData(uman,
                                GrEffect::MakeDivByTextureWHMatrix(colorTex),
-                               stage.getCoordChangeMatrix(),
+                               drawEffect,
                                colorTex);
 
     SkScalar scaleX = SkScalarDiv(displacementMap.scale(), SkIntToScalar(colorTex->width()));
@@ -498,20 +503,22 @@
                SkScalarToFloat(scaleY) : SkScalarToFloat(-scaleY));
 }
 
-GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrEffectStage& stage,
+GrGLEffect::EffectKey GrGLDisplacementMapEffect::GenKey(const GrDrawEffect& drawEffect,
                                                         const GrGLCaps&) {
     const GrDisplacementMapEffect& displacementMap =
-        GetEffectFromStage<GrDisplacementMapEffect>(stage);
+        drawEffect.castEffect<GrDisplacementMapEffect>();
 
     GrTexture* displTex = displacementMap.texture(0);
     GrTexture* colorTex = displacementMap.texture(1);
 
     EffectKey displKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(displTex),
-                                                  stage.getCoordChangeMatrix(),
+                                                  drawEffect,
+                                                  kCoordsType,
                                                   displTex);
 
     EffectKey colorKey = GrGLEffectMatrix::GenKey(GrEffect::MakeDivByTextureWHMatrix(colorTex),
-                                                  stage.getCoordChangeMatrix(),
+                                                  drawEffect,
+                                                  kCoordsType,
                                                   colorTex);
 
     colorKey <<= GrGLEffectMatrix::kKeyBits;
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 177ba09..8ada08a 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -980,23 +980,22 @@
 class GrGLLightingEffect  : public GrGLEffect {
 public:
     GrGLLightingEffect(const GrBackendEffectFactory& factory,
-                       const GrEffectRef& effect);
+                       const GrDrawEffect& effect);
     virtual ~GrGLLightingEffect();
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
     /**
      * Subclasses of GrGLLightingEffect must call INHERITED::setData();
      */
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 protected:
     virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
@@ -1015,9 +1014,9 @@
 class GrGLDiffuseLightingEffect  : public GrGLLightingEffect {
 public:
     GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
-                              const GrEffectRef& effect);
+                              const GrDrawEffect& drawEffect);
     virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 private:
     typedef GrGLLightingEffect INHERITED;
@@ -1030,9 +1029,9 @@
 class GrGLSpecularLightingEffect  : public GrGLLightingEffect {
 public:
     GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
-                               const GrEffectRef& effect);
+                               const GrDrawEffect& effect);
     virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 private:
     typedef GrGLLightingEffect INHERITED;
@@ -1093,11 +1092,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 GrGLLightingEffect::GrGLLightingEffect(const GrBackendEffectFactory& factory,
-                                       const GrEffectRef& effect)
+                                       const GrDrawEffect& drawEffect)
     : INHERITED(factory)
     , fImageIncrementUni(kInvalidUniformHandle)
-    , fSurfaceScaleUni(kInvalidUniformHandle) {
-    const GrLightingEffect& m = CastEffect<GrLightingEffect>(effect);
+    , fSurfaceScaleUni(kInvalidUniformHandle)
+    , fEffectMatrix(drawEffect.castEffect<GrLightingEffect>().coordsType()) {
+    const GrLightingEffect& m = drawEffect.castEffect<GrLightingEffect>();
     fLight = m.light()->createGLLight();
 }
 
@@ -1106,14 +1106,13 @@
 }
 
 void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
-                                  const GrEffectStage&,
+                                  const GrDrawEffect&,
                                   EffectKey key,
-                                  const char* vertexCoords,
                                   const char* outputColor,
                                   const char* inputColor,
                                   const TextureSamplerArray& samplers) {
     const char* coords;
-    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
 
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                               kVec2f_GrSLType,
@@ -1207,28 +1206,30 @@
     builder->fsCodeAppend(modulate.c_str());
 }
 
-GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrEffectStage& s,
+GrGLEffect::EffectKey GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
                                                  const GrGLCaps& caps) {
-    const GrLightingEffect& effect = GetEffectFromStage<GrLightingEffect>(s);
-    EffectKey key = effect.light()->type();
+    const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
+    EffectKey key = lighting.light()->type();
     key <<= GrGLEffectMatrix::kKeyBits;
-    EffectKey matrixKey = GrGLEffectMatrix::GenKey(effect.getMatrix(),
-                                                   s.getCoordChangeMatrix(),
-                                                   effect.texture(0));
+    EffectKey matrixKey = GrGLEffectMatrix::GenKey(lighting.getMatrix(),
+                                                   drawEffect,
+                                                   lighting.coordsType(),
+                                                   lighting.texture(0));
     return key | matrixKey;
 }
 
-void GrGLLightingEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    const GrLightingEffect& effect = GetEffectFromStage<GrLightingEffect>(stage);
-    GrTexture* texture = effect.texture(0);
+void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
+                                 const GrDrawEffect& drawEffect) {
+    const GrLightingEffect& lighting = drawEffect.castEffect<GrLightingEffect>();
+    GrTexture* texture = lighting.texture(0);
     float ySign = texture->origin() == kTopLeft_GrSurfaceOrigin ? -1.0f : 1.0f;
     uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
-    uman.set1f(fSurfaceScaleUni, effect.surfaceScale());
-    fLight->setData(uman, effect.light());
+    uman.set1f(fSurfaceScaleUni, lighting.surfaceScale());
+    fLight->setData(uman, lighting.light());
     fEffectMatrix.setData(uman,
-                          effect.getMatrix(),
-                          stage.getCoordChangeMatrix(),
-                          effect.texture(0));
+                          lighting.getMatrix(),
+                          drawEffect,
+                          lighting.texture(0));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1236,8 +1237,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
-                                                     const GrEffectRef& effect)
-    : INHERITED(factory, effect)
+                                                     const GrDrawEffect& drawEffect)
+    : INHERITED(factory, drawEffect)
     , fKDUni(kInvalidUniformHandle) {
 }
 
@@ -1266,10 +1267,10 @@
 }
 
 void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
-                                        const GrEffectStage& stage) {
-    INHERITED::setData(uman, stage);
-    const GrDiffuseLightingEffect& effect = GetEffectFromStage<GrDiffuseLightingEffect>(stage);
-    uman.set1f(fKDUni, effect.kd());
+                                        const GrDrawEffect& drawEffect) {
+    INHERITED::setData(uman, drawEffect);
+    const GrDiffuseLightingEffect& diffuse = drawEffect.castEffect<GrDiffuseLightingEffect>();
+    uman.set1f(fKDUni, diffuse.kd());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1307,8 +1308,8 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 GrGLSpecularLightingEffect::GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
-                                                       const GrEffectRef& effect)
-    : GrGLLightingEffect(factory, effect)
+                                                       const GrDrawEffect& drawEffect)
+    : GrGLLightingEffect(factory, drawEffect)
     , fKSUni(kInvalidUniformHandle)
     , fShininessUni(kInvalidUniformHandle) {
 }
@@ -1342,11 +1343,11 @@
 }
 
 void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
-                                         const GrEffectStage& stage) {
-    INHERITED::setData(uman, stage);
-    const GrSpecularLightingEffect& effect = GetEffectFromStage<GrSpecularLightingEffect>(stage);
-    uman.set1f(fKSUni, effect.ks());
-    uman.set1f(fShininessUni, effect.shininess());
+                                         const GrDrawEffect& drawEffect) {
+    INHERITED::setData(uman, drawEffect);
+    const GrSpecularLightingEffect& spec = drawEffect.castEffect<GrSpecularLightingEffect>();
+    uman.set1f(fKSUni, spec.ks());
+    uman.set1f(fShininessUni, spec.shininess());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1360,8 +1361,7 @@
     builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
 }
 
-void GrGLLight::setData(const GrGLUniformManager& uman,
-                        const SkLight* light) const {
+void GrGLLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
     setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
 }
 
@@ -1383,8 +1383,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrGLPointLight::setData(const GrGLUniformManager& uman,
-                             const SkLight* light) const {
+void GrGLPointLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
     INHERITED::setData(uman, light);
     SkASSERT(light->type() == SkLight::kPoint_LightType);
     const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
@@ -1400,8 +1399,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrGLSpotLight::setData(const GrGLUniformManager& uman,
-                            const SkLight* light) const {
+void GrGLSpotLight::setData(const GrGLUniformManager& uman, const SkLight* light) const {
     INHERITED::setData(uman, light);
     SkASSERT(light->type() == SkLight::kSpot_LightType);
     const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index 215ebc0..0c4cde1 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -92,22 +92,20 @@
 
 class GrGLMagnifierEffect : public GrGLEffect {
 public:
-    GrGLMagnifierEffect(const GrBackendEffectFactory& factory, const GrEffectRef& effect);
+    GrGLMagnifierEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
-    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
 private:
-
     UniformHandle       fOffsetVar;
     UniformHandle       fZoomVar;
     UniformHandle       fInsetVar;
@@ -117,22 +115,23 @@
     typedef GrGLEffect INHERITED;
 };
 
-GrGLMagnifierEffect::GrGLMagnifierEffect(const GrBackendEffectFactory& factory, const GrEffectRef&)
+GrGLMagnifierEffect::GrGLMagnifierEffect(const GrBackendEffectFactory& factory,
+                                         const GrDrawEffect& drawEffect)
     : INHERITED(factory)
     , fOffsetVar(GrGLUniformManager::kInvalidUniformHandle)
     , fZoomVar(GrGLUniformManager::kInvalidUniformHandle)
-    , fInsetVar(GrGLUniformManager::kInvalidUniformHandle) {
+    , fInsetVar(GrGLUniformManager::kInvalidUniformHandle)
+    , fEffectMatrix(drawEffect.castEffect<GrMagnifierEffect>().coordsType()) {
 }
 
 void GrGLMagnifierEffect::emitCode(GrGLShaderBuilder* builder,
-                                   const GrEffectStage&,
+                                   const GrDrawEffect&,
                                    EffectKey key,
-                                   const char* vertexCoords,
                                    const char* outputColor,
                                    const char* inputColor,
                                    const TextureSamplerArray& samplers) {
     const char* coords;
-    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
     fOffsetVar = builder->addUniform(
         GrGLShaderBuilder::kFragment_ShaderType |
         GrGLShaderBuilder::kVertex_ShaderType,
@@ -179,18 +178,20 @@
 }
 
 void GrGLMagnifierEffect::setData(const GrGLUniformManager& uman,
-                                  const GrEffectStage& stage) {
-    const GrMagnifierEffect& zoom = GetEffectFromStage<GrMagnifierEffect>(stage);
+                                  const GrDrawEffect& drawEffect) {
+    const GrMagnifierEffect& zoom = drawEffect.castEffect<GrMagnifierEffect>();
     uman.set2f(fOffsetVar, zoom.x_offset(), zoom.y_offset());
     uman.set2f(fZoomVar, zoom.x_zoom(), zoom.y_zoom());
     uman.set2f(fInsetVar, zoom.x_inset(), zoom.y_inset());
-    fEffectMatrix.setData(uman, zoom.getMatrix(), stage.getCoordChangeMatrix(), zoom.texture(0));
+    fEffectMatrix.setData(uman, zoom.getMatrix(), drawEffect, zoom.texture(0));
 }
 
-GrGLEffect::EffectKey GrGLMagnifierEffect::GenKey(const GrEffectStage& stage, const GrGLCaps&) {
-    const GrMagnifierEffect& zoom = GetEffectFromStage<GrMagnifierEffect>(stage);
+GrGLEffect::EffectKey GrGLMagnifierEffect::GenKey(const GrDrawEffect& drawEffect,
+                                                  const GrGLCaps&) {
+    const GrMagnifierEffect& zoom = drawEffect.castEffect<GrMagnifierEffect>();
     return GrGLEffectMatrix::GenKey(zoom.getMatrix(),
-                                    stage.getCoordChangeMatrix(),
+                                    drawEffect,
+                                    zoom.coordsType(),
                                     zoom.texture(0));
 }
 
diff --git a/src/effects/SkMatrixConvolutionImageFilter.cpp b/src/effects/SkMatrixConvolutionImageFilter.cpp
index cda4f28..c4cffea 100644
--- a/src/effects/SkMatrixConvolutionImageFilter.cpp
+++ b/src/effects/SkMatrixConvolutionImageFilter.cpp
@@ -284,8 +284,6 @@
 
     typedef GrGLMatrixConvolutionEffect GLEffect;
 
-
-
     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
 
 private:
@@ -316,18 +314,17 @@
 class GrGLMatrixConvolutionEffect : public GrGLEffect {
 public:
     GrGLMatrixConvolutionEffect(const GrBackendEffectFactory& factory,
-                                const GrEffectRef& effect);
+                                const GrDrawEffect& effect);
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 private:
     typedef GrGLUniformManager::UniformHandle        UniformHandle;
@@ -348,14 +345,15 @@
 };
 
 GrGLMatrixConvolutionEffect::GrGLMatrixConvolutionEffect(const GrBackendEffectFactory& factory,
-                                                         const GrEffectRef& effect)
+                                                         const GrDrawEffect& drawEffect)
     : INHERITED(factory)
     , fKernelUni(GrGLUniformManager::kInvalidUniformHandle)
     , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle)
     , fTargetUni(GrGLUniformManager::kInvalidUniformHandle)
     , fGainUni(GrGLUniformManager::kInvalidUniformHandle)
-    , fBiasUni(GrGLUniformManager::kInvalidUniformHandle) {
-    const GrMatrixConvolutionEffect& m = CastEffect<GrMatrixConvolutionEffect>(effect);
+    , fBiasUni(GrGLUniformManager::kInvalidUniformHandle)
+    , fEffectMatrix(drawEffect.castEffect<GrMatrixConvolutionEffect>().coordsType()) {
+    const GrMatrixConvolutionEffect& m = drawEffect.castEffect<GrMatrixConvolutionEffect>();
     fKernelSize = m.kernelSize();
     fTileMode = m.tileMode();
     fConvolveAlpha = m.convolveAlpha();
@@ -383,14 +381,13 @@
 }
 
 void GrGLMatrixConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
-                                           const GrEffectStage&,
+                                           const GrDrawEffect&,
                                            EffectKey key,
-                                           const char* vertexCoords,
                                            const char* outputColor,
                                            const char* inputColor,
                                            const TextureSamplerArray& samplers) {
     const char* coords;
-    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                              kVec2f_GrSLType, "ImageIncrement");
     fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_ShaderType,
@@ -450,38 +447,40 @@
 
 };
 
-GrGLEffect::EffectKey GrGLMatrixConvolutionEffect::GenKey(const GrEffectStage& s, const GrGLCaps&) {
-    const GrMatrixConvolutionEffect& m = GetEffectFromStage<GrMatrixConvolutionEffect>(s);
+GrGLEffect::EffectKey GrGLMatrixConvolutionEffect::GenKey(const GrDrawEffect& drawEffect,
+                                                          const GrGLCaps&) {
+    const GrMatrixConvolutionEffect& m = drawEffect.castEffect<GrMatrixConvolutionEffect>();
     EffectKey key = encodeXY(m.kernelSize().width(), m.kernelSize().height());
     key |= m.tileMode() << 7;
     key |= m.convolveAlpha() ? 1 << 9 : 0;
     key <<= GrGLEffectMatrix::kKeyBits;
     EffectKey matrixKey = GrGLEffectMatrix::GenKey(m.getMatrix(),
-                                                   s.getCoordChangeMatrix(),
+                                                   drawEffect,
+                                                   m.coordsType(),
                                                    m.texture(0));
     return key | matrixKey;
 }
 
 void GrGLMatrixConvolutionEffect::setData(const GrGLUniformManager& uman,
-                                          const GrEffectStage& stage) {
-    const GrMatrixConvolutionEffect& effect = GetEffectFromStage<GrMatrixConvolutionEffect>(stage);
-    GrTexture& texture = *effect.texture(0);
+                                          const GrDrawEffect& drawEffect) {
+    const GrMatrixConvolutionEffect& conv = drawEffect.castEffect<GrMatrixConvolutionEffect>();
+    GrTexture& texture = *conv.texture(0);
     // the code we generated was for a specific kernel size
-    GrAssert(effect.kernelSize() == fKernelSize);
-    GrAssert(effect.tileMode() == fTileMode);
+    GrAssert(conv.kernelSize() == fKernelSize);
+    GrAssert(conv.tileMode() == fTileMode);
     float imageIncrement[2];
     float ySign = texture.origin() == kTopLeft_GrSurfaceOrigin ? 1.0f : -1.0f;
     imageIncrement[0] = 1.0f / texture.width();
     imageIncrement[1] = ySign / texture.height();
     uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
-    uman.set2fv(fTargetUni, 0, 1, effect.target());
-    uman.set1fv(fKernelUni, 0, fKernelSize.width() * fKernelSize.height(), effect.kernel());
-    uman.set1f(fGainUni, effect.gain());
-    uman.set1f(fBiasUni, effect.bias());
+    uman.set2fv(fTargetUni, 0, 1, conv.target());
+    uman.set1fv(fKernelUni, 0, fKernelSize.width() * fKernelSize.height(), conv.kernel());
+    uman.set1f(fGainUni, conv.gain());
+    uman.set1f(fBiasUni, conv.bias());
     fEffectMatrix.setData(uman,
-                          effect.getMatrix(),
-                          stage.getCoordChangeMatrix(),
-                          effect.texture(0));
+                          conv.getMatrix(),
+                          drawEffect,
+                          conv.texture(0));
 }
 
 GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(GrTexture* texture,
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index bca18e6..f2b37f2 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -278,19 +278,18 @@
 
 class GrGLMorphologyEffect : public GrGLEffect {
 public:
-    GrGLMorphologyEffect (const GrBackendEffectFactory&, const GrEffectRef&);
+    GrGLMorphologyEffect (const GrBackendEffectFactory&, const GrDrawEffect&);
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 private:
     int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); }
@@ -304,23 +303,23 @@
 };
 
 GrGLMorphologyEffect::GrGLMorphologyEffect(const GrBackendEffectFactory& factory,
-                                           const GrEffectRef& effect)
+                                           const GrDrawEffect& drawEffect)
     : INHERITED(factory)
-    , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle) {
-    const GrMorphologyEffect& m = CastEffect<GrMorphologyEffect>(effect);
+    , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle)
+    , fEffectMatrix(drawEffect.castEffect<GrMorphologyEffect>().coordsType()) {
+    const GrMorphologyEffect& m = drawEffect.castEffect<GrMorphologyEffect>();
     fRadius = m.radius();
     fType = m.type();
 }
 
 void GrGLMorphologyEffect::emitCode(GrGLShaderBuilder* builder,
-                                    const GrEffectStage&,
+                                    const GrDrawEffect&,
                                     EffectKey key,
-                                    const char* vertexCoords,
                                     const char* outputColor,
                                     const char* inputColor,
                                     const TextureSamplerArray& samplers) {
     const char* coords;
-    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                              kVec2f_GrSLType, "ImageIncrement");
 
@@ -353,19 +352,22 @@
     builder->fsCodeAppend(modulate.c_str());
 }
 
-GrGLEffect::EffectKey GrGLMorphologyEffect::GenKey(const GrEffectStage& s, const GrGLCaps&) {
-    const GrMorphologyEffect& m = GetEffectFromStage<GrMorphologyEffect>(s);
+GrGLEffect::EffectKey GrGLMorphologyEffect::GenKey(const GrDrawEffect& drawEffect,
+                                                   const GrGLCaps&) {
+    const GrMorphologyEffect& m = drawEffect.castEffect<GrMorphologyEffect>();
     EffectKey key = static_cast<EffectKey>(m.radius());
     key |= (m.type() << 8);
     key <<= GrGLEffectMatrix::kKeyBits;
     EffectKey matrixKey = GrGLEffectMatrix::GenKey(m.getMatrix(),
-                                                   s.getCoordChangeMatrix(),
+                                                   drawEffect,
+                                                   m.coordsType(),
                                                    m.texture(0));
     return key | matrixKey;
 }
 
-void GrGLMorphologyEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    const Gr1DKernelEffect& kern = GetEffectFromStage<Gr1DKernelEffect>(stage);
+void GrGLMorphologyEffect::setData(const GrGLUniformManager& uman,
+                                   const GrDrawEffect& drawEffect) {
+    const Gr1DKernelEffect& kern = drawEffect.castEffect<Gr1DKernelEffect>();
     GrTexture& texture = *kern.texture(0);
     // the code we generated was for a specific kernel radius
     GrAssert(kern.radius() == fRadius);
@@ -381,7 +383,7 @@
             GrCrash("Unknown filter direction.");
     }
     uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
-    fEffectMatrix.setData(uman, kern.getMatrix(), stage.getCoordChangeMatrix(), kern.texture(0));
+    fEffectMatrix.setData(uman, kern.getMatrix(), drawEffect, kern.texture(0));
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index 16f2876..e0c4978 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -256,33 +256,31 @@
 
 class GLColorTableEffect : public GrGLEffect {
 public:
-    GLColorTableEffect(const GrBackendEffectFactory&, const GrEffectRef&);
+    GLColorTableEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE {}
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
 
-    static EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
 private:
 
     typedef GrGLEffect INHERITED;
 };
 
-GLColorTableEffect::GLColorTableEffect(const GrBackendEffectFactory& factory, const GrEffectRef&)
+GLColorTableEffect::GLColorTableEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
     : INHERITED(factory) {
  }
 
 void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder,
-                                  const GrEffectStage&,
+                                  const GrDrawEffect&,
                                   EffectKey,
-                                  const char* vertexCoords,
                                   const char* outputColor,
                                   const char* inputColor,
                                   const TextureSamplerArray& samplers) {
@@ -323,7 +321,7 @@
     builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
 }
 
-GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrEffectStage&, const GrGLCaps&) {
+GrGLEffect::EffectKey GLColorTableEffect::GenKey(const GrDrawEffect&, const GrGLCaps&) {
     return 0;
 }
 
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index 1158dcf..d3b2fd4 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -734,12 +734,14 @@
 #if SK_SUPPORT_GPU
 
 #include "effects/GrTextureStripAtlas.h"
+#include "GrTBackendEffectFactory.h"
 #include "SkGr.h"
 
 GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory)
     : INHERITED(factory)
     , fCachedYCoord(SK_ScalarMax)
-    , fFSYUni(GrGLUniformManager::kInvalidUniformHandle) {
+    , fFSYUni(GrGLUniformManager::kInvalidUniformHandle)
+    , fEffectMatrix(kCoordsType) {
 }
 
 GrGLGradientEffect::~GrGLGradientEffect() { }
@@ -749,10 +751,11 @@
                                   kFloat_GrSLType, "GradientYCoordFS");
 }
 
-void GrGLGradientEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    const GrGradientEffect& e = GetEffectFromStage<GrGradientEffect>(stage);
+void GrGLGradientEffect::setData(const GrGLUniformManager& uman,
+                                 const GrDrawEffect& drawEffect) {
+    const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>();
     const GrTexture* texture = e.texture(0);
-    fEffectMatrix.setData(uman, e.getMatrix(), stage.getCoordChangeMatrix(), texture);
+    fEffectMatrix.setData(uman, e.getMatrix(), drawEffect, texture);
 
     SkScalar yCoord = e.getYCoord();
     if (yCoord != fCachedYCoord) {
@@ -761,21 +764,19 @@
     }
 }
 
-GrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrEffectStage& s) {
-    const GrGradientEffect& e = GetEffectFromStage<GrGradientEffect>(s);
+GrGLEffect::EffectKey GrGLGradientEffect::GenMatrixKey(const GrDrawEffect& drawEffect) {
+    const GrGradientEffect& e = drawEffect.castEffect<GrGradientEffect>();
     const GrTexture* texture = e.texture(0);
-    return GrGLEffectMatrix::GenKey(e.getMatrix(), s.getCoordChangeMatrix(), texture);
+    return GrGLEffectMatrix::GenKey(e.getMatrix(), drawEffect, kCoordsType, texture);
 }
 
 void GrGLGradientEffect::setupMatrix(GrGLShaderBuilder* builder,
                                      EffectKey key,
-                                     const char* vertexCoords,
                                      const char** fsCoordName,
                                      const char** vsVaryingName,
                                      GrSLType* vsVaryingType) {
     fEffectMatrix.emitCodeMakeFSCoords2D(builder,
                                          key & kMatrixKeyMask,
-                                         vertexCoords,
                                          fsCoordName,
                                          vsVaryingName,
                                          vsVaryingType);
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 271a2b6..b9dbf1b 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -274,7 +274,7 @@
     GrGLGradientEffect(const GrBackendEffectFactory& factory);
     virtual ~GrGLGradientEffect();
 
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 protected:
     /**
@@ -290,7 +290,7 @@
      * Subclasses must call this. It will return a value restricted to the lower kMatrixKeyBitCnt
      * bits.
      */
-    static EffectKey GenMatrixKey(const GrEffectStage& s);
+    static EffectKey GenMatrixKey(const GrDrawEffect&);
 
     /**
      * Inserts code to implement the GrGradientEffect's matrix. This should be called before a
@@ -302,7 +302,6 @@
      */
     void setupMatrix(GrGLShaderBuilder* builder,
                      EffectKey key,
-                     const char* vertexCoords,
                      const char** fsCoordName,
                      const char** vsVaryingName = NULL,
                      GrSLType* vsVaryingType = NULL);
@@ -321,6 +320,8 @@
                          const GrGLShaderBuilder::TextureSampler&);
 
 private:
+    static const GrEffect::CoordsType kCoordsType = GrEffect::kLocal_CoordsType;
+
     SkScalar fCachedYCoord;
     GrGLUniformManager::UniformHandle fFSYUni;
     GrGLEffectMatrix fEffectMatrix;
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 3f8d7cc..76168a9 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -453,21 +453,20 @@
 class GrGLLinearGradient : public GrGLGradientEffect {
 public:
 
-    GrGLLinearGradient(const GrBackendEffectFactory& factory, const GrEffectRef&)
+    GrGLLinearGradient(const GrBackendEffectFactory& factory, const GrDrawEffect&)
                        : INHERITED (factory) { }
 
     virtual ~GrGLLinearGradient() { }
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
-        return GenMatrixKey(stage);
+    static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+        return GenMatrixKey(drawEffect);
     }
 
 private:
@@ -533,15 +532,14 @@
 /////////////////////////////////////////////////////////////////////
 
 void GrGLLinearGradient::emitCode(GrGLShaderBuilder* builder,
-                                  const GrEffectStage& stage,
+                                  const GrDrawEffect&,
                                   EffectKey key,
-                                  const char* vertexCoords,
                                   const char* outputColor,
                                   const char* inputColor,
                                   const TextureSamplerArray& samplers) {
     this->emitYCoordUniform(builder);
     const char* coords;
-    this->setupMatrix(builder, key, vertexCoords, &coords);
+    this->setupMatrix(builder, key, &coords);
     SkString t;
     t.append(coords);
     t.append(".x");
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index 3f670ad..a80cb81 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -474,19 +474,18 @@
 public:
 
     GrGLRadialGradient(const GrBackendEffectFactory& factory,
-                       const GrEffectRef&) : INHERITED (factory) { }
+                       const GrDrawEffect&) : INHERITED (factory) { }
     virtual ~GrGLRadialGradient() { }
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
-        return GenMatrixKey(stage);
+    static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+        return GenMatrixKey(drawEffect);
     }
 
 private:
@@ -554,15 +553,14 @@
 /////////////////////////////////////////////////////////////////////
 
 void GrGLRadialGradient::emitCode(GrGLShaderBuilder* builder,
-                                  const GrEffectStage&,
+                                  const GrDrawEffect&,
                                   EffectKey key,
-                                  const char* vertexCoords,
                                   const char* outputColor,
                                   const char* inputColor,
                                   const TextureSamplerArray& samplers) {
     this->emitYCoordUniform(builder);
     const char* coords;
-    this->setupMatrix(builder, key, vertexCoords, &coords);
+    this->setupMatrix(builder, key, &coords);
     SkString t("length(");
     t.append(coords);
     t.append(")");
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 44b03d6..9d24d40 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -391,19 +391,18 @@
 public:
 
     GrGLSweepGradient(const GrBackendEffectFactory& factory,
-                      const GrEffectRef&) : INHERITED (factory) { }
+                      const GrDrawEffect&) : INHERITED (factory) { }
     virtual ~GrGLSweepGradient() { }
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    static EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
-        return GenMatrixKey(stage);
+    static EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+        return GenMatrixKey(drawEffect);
     }
 
 private:
@@ -464,15 +463,14 @@
 /////////////////////////////////////////////////////////////////////
 
 void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder,
-                                 const GrEffectStage&,
+                                 const GrDrawEffect&,
                                  EffectKey key,
-                                 const char* vertexCoords,
                                  const char* outputColor,
                                  const char* inputColor,
                                  const TextureSamplerArray& samplers) {
     this->emitYCoordUniform(builder);
     const char* coords;
-    this->setupMatrix(builder, key, vertexCoords, &coords);
+    this->setupMatrix(builder, key, &coords);
     SkString t;
     t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5", coords, coords);
     this->emitColorLookup(builder, t.c_str(), outputColor, inputColor, samplers[0]);
diff --git a/src/effects/gradients/SkTwoPointConicalGradient.cpp b/src/effects/gradients/SkTwoPointConicalGradient.cpp
index 04cf1eb..0b6e30d 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -343,20 +343,18 @@
 class GrGLConical2Gradient : public GrGLGradientEffect {
 public:
 
-    GrGLConical2Gradient(const GrBackendEffectFactory& factory,
-                         const GrEffectRef&);
+    GrGLConical2Gradient(const GrBackendEffectFactory& factory, const GrDrawEffect&);
     virtual ~GrGLConical2Gradient() { }
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
-    static EffectKey GenKey(const GrEffectStage&, const GrGLCaps& caps);
+    static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps& caps);
 
 protected:
 
@@ -476,7 +474,7 @@
 /////////////////////////////////////////////////////////////////////
 
 GrGLConical2Gradient::GrGLConical2Gradient(const GrBackendEffectFactory& factory,
-                                           const GrEffectRef& baseData)
+                                           const GrDrawEffect& drawEffect)
     : INHERITED(factory)
     , fVSParamUni(kInvalidUniformHandle)
     , fFSParamUni(kInvalidUniformHandle)
@@ -486,21 +484,20 @@
     , fCachedRadius(-SK_ScalarMax)
     , fCachedDiffRadius(-SK_ScalarMax) {
 
-    const GrConical2Gradient& data = CastEffect<GrConical2Gradient>(baseData);
+    const GrConical2Gradient& data = drawEffect.castEffect<GrConical2Gradient>();
     fIsDegenerate = data.isDegenerate();
 }
 
 void GrGLConical2Gradient::emitCode(GrGLShaderBuilder* builder,
-                                    const GrEffectStage&,
+                                    const GrDrawEffect&,
                                     EffectKey key,
-                                    const char* vertexCoords,
                                     const char* outputColor,
                                     const char* inputColor,
                                     const TextureSamplerArray& samplers) {
     const char* fsCoords;
     const char* vsCoordsVarying;
     GrSLType coordsVaryingType;
-    this->setupMatrix(builder, key, vertexCoords, &fsCoords, &vsCoordsVarying, &coordsVaryingType);
+    this->setupMatrix(builder, key, &fsCoords, &vsCoordsVarying, &coordsVaryingType);
 
     this->emitYCoordUniform(builder);
     // 2 copies of uniform array, 1 for each of vertex & fragment shader,
@@ -658,9 +655,10 @@
     }
 }
 
-void GrGLConical2Gradient::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    INHERITED::setData(uman, stage);
-    const GrConical2Gradient& data = GetEffectFromStage<GrConical2Gradient>(stage);
+void GrGLConical2Gradient::setData(const GrGLUniformManager& uman,
+                                   const GrDrawEffect& drawEffect) {
+    INHERITED::setData(uman, drawEffect);
+    const GrConical2Gradient& data = drawEffect.castEffect<GrConical2Gradient>();
     GrAssert(data.isDegenerate() == fIsDegenerate);
     SkScalar centerX1 = data.center();
     SkScalar radius0 = data.radius();
@@ -694,13 +692,14 @@
     }
 }
 
-GrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrEffectStage& s, const GrGLCaps&) {
+GrGLEffect::EffectKey GrGLConical2Gradient::GenKey(const GrDrawEffect& drawEffect,
+                                                   const GrGLCaps&) {
     enum {
         kIsDegenerate = 1 << kMatrixKeyBitCnt,
     };
 
-    EffectKey key = GenMatrixKey(s);
-    if (GetEffectFromStage<GrConical2Gradient>(s).isDegenerate()) {
+    EffectKey key = GenMatrixKey(drawEffect);
+    if (drawEffect.castEffect<GrConical2Gradient>().isDegenerate()) {
         key |= kIsDegenerate;
     }
     return key;
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index 0bf308b..6784818 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -384,19 +384,18 @@
 
 public:
 
-    GrGLRadial2Gradient(const GrBackendEffectFactory& factory, const GrEffectRef&);
+    GrGLRadial2Gradient(const GrBackendEffectFactory& factory, const GrDrawEffect&);
     virtual ~GrGLRadial2Gradient() { }
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
-    static EffectKey GenKey(const GrEffectStage&, const GrGLCaps& caps);
+    static EffectKey GenKey(const GrDrawEffect&, const GrGLCaps& caps);
 
 protected:
 
@@ -516,7 +515,7 @@
 /////////////////////////////////////////////////////////////////////
 
 GrGLRadial2Gradient::GrGLRadial2Gradient(const GrBackendEffectFactory& factory,
-                                         const GrEffectRef& baseData)
+                                         const GrDrawEffect& drawEffect)
     : INHERITED(factory)
     , fVSParamUni(kInvalidUniformHandle)
     , fFSParamUni(kInvalidUniformHandle)
@@ -526,14 +525,13 @@
     , fCachedRadius(-SK_ScalarMax)
     , fCachedPosRoot(0) {
 
-    const GrRadial2Gradient& data = CastEffect<GrRadial2Gradient>(baseData);
+    const GrRadial2Gradient& data = drawEffect.castEffect<GrRadial2Gradient>();
     fIsDegenerate = data.isDegenerate();
 }
 
 void GrGLRadial2Gradient::emitCode(GrGLShaderBuilder* builder,
-                                   const GrEffectStage&,
+                                   const GrDrawEffect& drawEffect,
                                    EffectKey key,
-                                   const char* vertexCoords,
                                    const char* outputColor,
                                    const char* inputColor,
                                    const TextureSamplerArray& samplers) {
@@ -542,7 +540,7 @@
     const char* fsCoords;
     const char* vsCoordsVarying;
     GrSLType coordsVaryingType;
-    this->setupMatrix(builder, key, vertexCoords, &fsCoords, &vsCoordsVarying, &coordsVaryingType);
+    this->setupMatrix(builder, key, &fsCoords, &vsCoordsVarying, &coordsVaryingType);
 
     // 2 copies of uniform array, 1 for each of vertex & fragment shader,
     // to work around Xoom bug. Doesn't seem to cause performance decrease
@@ -639,9 +637,10 @@
     }
 }
 
-void GrGLRadial2Gradient::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    INHERITED::setData(uman, stage);
-    const GrRadial2Gradient& data = GetEffectFromStage<GrRadial2Gradient>(stage);
+void GrGLRadial2Gradient::setData(const GrGLUniformManager& uman,
+                                  const GrDrawEffect& drawEffect) {
+    INHERITED::setData(uman, drawEffect);
+    const GrRadial2Gradient& data = drawEffect.castEffect<GrRadial2Gradient>();
     GrAssert(data.isDegenerate() == fIsDegenerate);
     SkScalar centerX1 = data.center();
     SkScalar radius0 = data.radius();
@@ -673,13 +672,14 @@
     }
 }
 
-GrGLEffect::EffectKey GrGLRadial2Gradient::GenKey(const GrEffectStage& s, const GrGLCaps&) {
+GrGLEffect::EffectKey GrGLRadial2Gradient::GenKey(const GrDrawEffect& drawEffect,
+                                                  const GrGLCaps&) {
     enum {
         kIsDegenerate = 1 << kMatrixKeyBitCnt,
     };
 
-    EffectKey key = GenMatrixKey(s);
-    if (GetEffectFromStage<GrRadial2Gradient>(s).isDegenerate()) {
+    EffectKey key = GenMatrixKey(drawEffect);
+    if (drawEffect.castEffect<GrRadial2Gradient>().isDegenerate()) {
         key |= kIsDegenerate;
     }
     return key;
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index 99068c7..6415859 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -40,6 +40,9 @@
     static const int kMaskStage = GrPaint::kTotalStages+1;
 
     SkMatrix mat;
+    // We want to use device coords to compute the texture coordinates. We set our matrix to be
+    // equal to the view matrix followed by an offset to the devBound, and then a scaling matrix to
+    // normalized coords. We apply this matrix to the vertex positions rather than local coords.
     mat.setIDiv(result->width(), result->height());
     mat.preTranslate(SkIntToScalar(-devBound.fLeft),
                      SkIntToScalar(-devBound.fTop));
@@ -51,7 +54,9 @@
                          GrTextureDomainEffect::Create(result,
                                       mat,
                                       GrTextureDomainEffect::MakeTexelDomain(result, domainTexels),
-                                      GrTextureDomainEffect::kDecal_WrapMode))->unref();
+                                      GrTextureDomainEffect::kDecal_WrapMode,
+                                      false,
+                                      GrEffect::kPosition_CoordsType))->unref();
 }
 
 bool path_needs_SW_renderer(GrContext* context,
@@ -354,7 +359,8 @@
         GrTextureDomainEffect::Create(srcMask,
                                       sampleM,
                                       GrTextureDomainEffect::MakeTexelDomain(srcMask, srcBound),
-                                      GrTextureDomainEffect::kDecal_WrapMode))->unref();
+                                      GrTextureDomainEffect::kDecal_WrapMode,
+                                      false))->unref();
     fGpu->drawSimpleRect(SkRect::MakeFromIRect(dstBound), NULL);
 
     drawState->disableStage(0);
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 4c18574..4798297 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -360,12 +360,12 @@
             {kVec2f_GrVertexAttribType, 0},
             {kVec2f_GrVertexAttribType, sizeof(GrPoint)}
         };
-        static const GrAttribBindings kAttribBindings =
-            GrDrawState::ExplicitTexCoordAttribBindingsBit(0);
+
+        static const GrAttribBindings kAttribBindings = GrDrawState::kLocalCoords_AttribBindingsBit;
         drawState->setAttribBindings(kAttribBindings);
         drawState->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
         drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
-        drawState->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, 1);
+        drawState->setAttribIndex(GrDrawState::kLocalCoords_AttribIndex, 1);
         GrDrawTarget::AutoReleaseGeometry arg(fGpu, 4, 0);
 
         if (arg.succeeded()) {
@@ -852,21 +852,15 @@
 
 void GrContext::drawRectToRect(const GrPaint& paint,
                                const GrRect& dstRect,
-                               const GrRect& srcRect,
+                               const GrRect& localRect,
                                const SkMatrix* dstMatrix,
-                               const SkMatrix* srcMatrix) {
+                               const SkMatrix* localMatrix) {
     SK_TRACE_EVENT0("GrContext::drawRectToRect");
 
-    // srcRect refers to paint's first color stage
-    if (!paint.isColorStageEnabled(0)) {
-        drawRect(paint, dstRect, -1, dstMatrix);
-        return;
-    }
-
     GrDrawTarget* target = this->prepareToDraw(&paint, BUFFERED_DRAW);
+    GrDrawState::AutoStageDisable atr(fDrawState);
 
 #if GR_STATIC_RECT_VB
-    GrDrawState::AutoStageDisable atr(fDrawState);
     GrDrawState* drawState = target->drawState();
 
     SkMatrix m;
@@ -878,19 +872,21 @@
         m.postConcat(*dstMatrix);
     }
 
-    // The first color stage's coords come from srcRect rather than applying a matrix to dstRect.
-    // We explicitly compute a matrix for that stage below, no need to adjust here.
-    static const uint32_t kExplicitCoordMask = 1 << GrPaint::kFirstColorStage;
-    GrDrawState::AutoViewMatrixRestore avmr(drawState, m, kExplicitCoordMask);
+    // This code path plays a little fast and loose with the notion of local coords and coord
+    // change matrices in order to account for localRect and localMatrix. The unit square VB only
+    // has one set of coords. Rather than using AutoViewMatrixRestore we instead directly set concat
+    // with m and then call GrDrawState::localCoordChange() with a matrix that accounts for
+    // localRect and localMatrix. This code path is preventing some encapsulation in GrDrawState.
+    SkMatrix savedViewMatrix = drawState->getViewMatrix();
+    drawState->preConcatViewMatrix(m);
 
-    m.setAll(srcRect.width(), 0,                srcRect.fLeft,
-             0,               srcRect.height(), srcRect.fTop,
-             0,               0,                SkMatrix::I()[8]);
-    if (NULL != srcMatrix) {
-        m.postConcat(*srcMatrix);
+    m.setAll(localRect.width(), 0,                localRect.fLeft,
+             0,               localRect.height(), localRect.fTop,
+             0,               0,                  SkMatrix::I()[8]);
+    if (NULL != localMatrix) {
+        m.postConcat(*localMatrix);
     }
-
-    drawState->preConcatStageMatrices(kExplicitCoordMask, m);
+    drawState->localCoordChange(m);
 
     const GrVertexBuffer* sqVB = fGpu->getUnitSquareVertexBuffer();
     if (NULL == sqVB) {
@@ -900,10 +896,9 @@
     drawState->setDefaultVertexAttribs();
     target->setVertexSourceToBuffer(sqVB);
     target->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4);
+    drawState->setViewMatrix(savedViewMatrix);
 #else
-    GrDrawState::AutoStageDisable atr(fDrawState);
-
-    target->drawRect(dstRect, dstMatrix, &srcRect, srcMatrix, 0);
+    target->drawRect(dstRect, dstMatrix, &localRect, localMatrix);
 #endif
 }
 
@@ -937,8 +932,8 @@
 
     // set up optional texture coordinate attributes
     if (NULL != texCoords) {
-        bindings |= GrDrawState::ExplicitTexCoordAttribBindingsBit(0);
-        drawState->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, attribs.count());
+        bindings |= GrDrawState::kLocalCoords_AttribBindingsBit;
+        drawState->setAttribIndex(GrDrawState::kLocalCoords_AttribIndex, attribs.count());
         currAttrib.set(kVec2f_GrVertexAttribType, currentOffset);
         attribs.push_back(currAttrib);
         texOffset = currentOffset;
diff --git a/src/gpu/GrDrawState.cpp b/src/gpu/GrDrawState.cpp
index cd5fe1c..7982935 100644
--- a/src/gpu/GrDrawState.cpp
+++ b/src/gpu/GrDrawState.cpp
@@ -46,28 +46,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-namespace {
-
-/**
- * This function generates a mask that we like to have known at compile
- * time. When the number of stages is bumped or the way bits are defined in
- * GrDrawState.h changes this function should be rerun to generate the new mask.
- * (We attempted to force the compiler to generate the mask using recursive
- * templates but always wound up with static initializers under gcc, even if
- * they were just a series of immediate->memory moves.)
- *
- */
-void gen_tex_coord_mask(GrAttribBindings* texCoordMask) {
-    *texCoordMask = 0;
-    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-        *texCoordMask |= GrDrawState::ExplicitTexCoordAttribBindingsBit(s);
-    }
-}
-
-const GrAttribBindings kTexCoord_AttribBindingsMask = (1 << GrDrawState::kNumStages)-1;
-
-} //unnamed namespace
-
 const size_t GrDrawState::kVertexAttribSizes[kGrVertexAttribTypeCount] = {
     sizeof(float),          // kFloat_GrVertexAttribType
     2*sizeof(float),        // kVec2_GrVertexAttribType
@@ -106,7 +84,7 @@
     kColor_AttribBindingsBit,
     kCoverage_AttribBindingsBit,
     kEdge_AttribBindingsBit,
-    kTexCoord_AttribBindingsMask
+    kLocalCoords_AttribBindingsBit,
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -210,20 +188,8 @@
     return true;
 }
 
-////////////////////////////////////////////////////////////////////////////////
-
-bool GrDrawState::AttributesBindExplicitTexCoords(GrAttribBindings attribBindings) {
-    return SkToBool(kTexCoord_AttribBindingsMask & attribBindings);
-}
-
-////////////////////////////////////////////////////////////////////////////////
 
 void GrDrawState::VertexAttributesUnitTest() {
-    // Ensure that our tex coord mask is correct
-    GrAttribBindings texCoordMask;
-    gen_tex_coord_mask(&texCoordMask);
-    GrAssert(texCoordMask == kTexCoord_AttribBindingsMask);
-
     // not necessarily exhaustive
     static bool run;
     if (!run) {
@@ -259,27 +225,11 @@
         attribs.push_back(currAttrib);
         GrAssert(4*sizeof(char) + 2*sizeof(float) + 3*sizeof(float) + sizeof(float) + 4*sizeof(float) ==
                  vertex_size(attribs.begin(), attribs.count()));
-
-        GrAttribBindings tcMask = 0;
-        GrAssert(!AttributesBindExplicitTexCoords(0));
-        for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-            tcMask |= ExplicitTexCoordAttribBindingsBit(s);
-            GrAssert(AttributesBindExplicitTexCoords(tcMask));
-            GrAssert(StageBindsExplicitTexCoords(tcMask, s));
-            for (int s2 = s + 1; s2 < GrDrawState::kNumStages; ++s2) {
-                GrAssert(!StageBindsExplicitTexCoords(tcMask, s2));
-            }
-        }
-        GrAssert(kTexCoord_AttribBindingsMask == tcMask);
     }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-bool GrDrawState::StageBindsExplicitTexCoords(GrAttribBindings bindings, int stageIdx) {
-    return SkToBool(bindings & ExplicitTexCoordAttribBindingsBit(stageIdx));
-}
-
 bool GrDrawState::srcAlphaWillBeOne(GrAttribBindings bindings) const {
 
     uint32_t validComponentFlags;
@@ -500,8 +450,7 @@
 }
 
 void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState,
-                                             const SkMatrix& preconcatMatrix,
-                                             uint32_t explicitCoordStageMask) {
+                                             const SkMatrix& preconcatMatrix) {
     this->restore();
 
     fDrawState = drawState;
@@ -513,10 +462,10 @@
     fViewMatrix = drawState->getViewMatrix();
     drawState->preConcatViewMatrix(preconcatMatrix);
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-        if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) {
+        if (drawState->isStageEnabled(s)) {
             fRestoreMask |= (1 << s);
             fDrawState->fStages[s].saveCoordChange(&fSavedCoordChanges[s]);
-            drawState->fStages[s].preConcatCoordChange(preconcatMatrix);
+            drawState->fStages[s].localCoordChange(preconcatMatrix);
         }
     }
 }
@@ -535,8 +484,7 @@
     fDrawState = NULL;
 }
 
-bool GrDrawState::AutoDeviceCoordDraw::set(GrDrawState* drawState,
-                                           uint32_t explicitCoordStageMask) {
+bool GrDrawState::AutoDeviceCoordDraw::set(GrDrawState* drawState) {
     GrAssert(NULL != drawState);
 
     this->restore();
@@ -552,7 +500,7 @@
     bool inverted = false;
 
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-        if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) {
+        if (drawState->isStageEnabled(s)) {
             if (!inverted && !fViewMatrix.invert(&invVM)) {
                 // sad trombone sound
                 fDrawState = NULL;
@@ -563,7 +511,7 @@
             fRestoreMask |= (1 << s);
             GrEffectStage* stage = drawState->fStages + s;
             stage->saveCoordChange(&fSavedCoordChanges[s]);
-            stage->preConcatCoordChange(invVM);
+            stage->localCoordChange(invVM);
         }
     }
     drawState->viewMatrix()->reset();
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 2203e88..ffa7b09 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -257,38 +257,26 @@
     /**
      * The vertex data used by the current program is represented as a bitfield
      * of flags. Programs always use positions and may also use texture
-     * coordinates, per-vertex colors, per-vertex coverage and edge data. Each
-     * stage can use the explicit texture coordinates as its input texture
-     * coordinates or it may use the positions as texture coordinates.
+     * coordinates, per-vertex colors, per-vertex coverage and edge data. The
+     * local coords accessible by effects may either come from positions or
+     * be specified explicitly.
      */
 
     /**
-     * Generates a bit indicating that a texture stage uses texture coordinates
-     *
-     * @param stageIdx    the stage that will use texture coordinates.
-     *
-     * @return the bit to add to a GrAttribBindings bitfield.
-     */
-    static int ExplicitTexCoordAttribBindingsBit(int stageIdx) {
-        GrAssert(stageIdx < kNumStages);
-        return (1 << stageIdx);
-    }
-
-    static bool StageBindsExplicitTexCoords(GrAttribBindings bindings, int stageIdx);
-
-    /**
      * Additional Bits that can be specified in GrAttribBindings.
      */
     enum AttribBindingsBits {
+        /** explicit local coords are provided (instead of using pre-view-matrix positions) */
+        kLocalCoords_AttribBindingsBit        = 0x1,
         /* program uses colors (GrColor) */
-        kColor_AttribBindingsBit              = 1 << (kNumStages + 0),
+        kColor_AttribBindingsBit              = 0x2,
         /* program uses coverage (GrColor)
          */
-        kCoverage_AttribBindingsBit           = 1 << (kNumStages + 1),
+        kCoverage_AttribBindingsBit           = 0x4,
         /* program uses edge data. Distance to the edge is used to
          * compute a coverage. See GrDrawState::setVertexEdgeType().
          */
-        kEdge_AttribBindingsBit               = 1 << (kNumStages + 2),
+        kEdge_AttribBindingsBit               = 0x8,
         // for below assert
         kDummyAttribBindingsBit,
         kHighAttribBindingsBit = kDummyAttribBindingsBit - 1
@@ -313,17 +301,6 @@
     // Helpers for picking apart attribute bindings
 
     /**
-     * Helper function to determine if program uses explicit texture
-     * coordinates.
-     *
-     * @param  bindings  attribute bindings to query
-     *
-     * @return true if program uses texture coordinates,
-     *         false otherwise.
-     */
-    static bool AttributesBindExplicitTexCoords(GrAttribBindings bindings);
-
-    /**
      * Determines whether src alpha is guaranteed to be one for all src pixels
      */
     bool srcAlphaWillBeOne(GrAttribBindings) const;
@@ -356,9 +333,9 @@
         kColor_AttribIndex,
         kCoverage_AttribIndex,
         kEdge_AttribIndex,
-        kTexCoord_AttribIndex,
+        kLocalCoords_AttribIndex,
 
-        kLast_AttribIndex = kTexCoord_AttribIndex
+        kLast_AttribIndex = kLocalCoords_AttribIndex
     };
     static const int kAttribIndexCount = kLast_AttribIndex + 1;
 
@@ -410,7 +387,7 @@
 
     /**
      * Add a color filter that can be represented by a color and a mode. Applied
-     * after color-computing texture stages.
+     * after color-computing effect stages.
      */
     void setColorFilter(GrColor c, SkXfermode::Mode mode) {
         fCommon.fColorFilterColor = c;
@@ -497,7 +474,7 @@
     }
 
     /**
-     * Creates a GrSimpleTextureEffect.
+     * Creates a GrSimpleTextureEffect that uses local coords as texture coordinates.
      */
     void createTextureEffect(int stageIdx, GrTexture* texture, const SkMatrix& matrix) {
         GrAssert(!this->getStage(stageIdx).getEffect());
@@ -556,42 +533,16 @@
     }
 
     /**
-     * Called when the source coord system is changing. preConcat gives the transformation from the
-     * old coord system to the new coord system.
+     * Called when the source coord system is changing. This ensures that effects will see the
+     * correct local coordinates. oldToNew gives the transformation from the old coord system in
+     * which the geometry was specified to the new coordinate system from which it will be rendered.
      */
-    void preConcatStageMatrices(const SkMatrix& preConcat) {
-        this->preConcatStageMatrices(~0U, preConcat);
-    }
-    /**
-     * Version of above that applies the update matrix selectively to stages via a mask.
-     */
-    void preConcatStageMatrices(uint32_t stageMask, const SkMatrix& preConcat) {
-        for (int i = 0; i < kNumStages; ++i) {
-            if (((1 << i) & stageMask) && this->isStageEnabled(i)) {
-                fStages[i].preConcatCoordChange(preConcat);
-            }
-        }
-    }
-
-    /**
-     * Called when the source coord system is changing. preConcatInverse is the inverse of the
-     * transformation from the old coord system to the new coord system. Returns false if the matrix
-     * cannot be inverted.
-     */
-    bool preConcatStageMatricesWithInverse(const SkMatrix& preConcatInverse) {
-        SkMatrix inv;
-        bool computed = false;
+    void localCoordChange(const SkMatrix& oldToNew) {
         for (int i = 0; i < kNumStages; ++i) {
             if (this->isStageEnabled(i)) {
-                if (!computed && !preConcatInverse.invert(&inv)) {
-                    return false;
-                } else {
-                    computed = true;
-                }
-                fStages[i].preConcatCoordChange(preConcatInverse);
+                fStages[i].localCoordChange(oldToNew);
             }
         }
-        return true;
     }
 
     /// @}
@@ -832,11 +783,9 @@
     public:
         AutoViewMatrixRestore() : fDrawState(NULL) {}
 
-        AutoViewMatrixRestore(GrDrawState* ds,
-                              const SkMatrix& preconcatMatrix,
-                              uint32_t explicitCoordStageMask = 0) {
+        AutoViewMatrixRestore(GrDrawState* ds, const SkMatrix& preconcatMatrix) {
             fDrawState = NULL;
-            this->set(ds, preconcatMatrix, explicitCoordStageMask);
+            this->set(ds, preconcatMatrix);
         }
 
         ~AutoViewMatrixRestore() { this->restore(); }
@@ -846,9 +795,7 @@
          */
         void restore();
 
-        void set(GrDrawState* drawState,
-                 const SkMatrix& preconcatMatrix,
-                 uint32_t explicitCoordStageMask = 0);
+        void set(GrDrawState* drawState, const SkMatrix& preconcatMatrix);
 
         bool isSet() const { return NULL != fDrawState; }
 
@@ -875,15 +822,14 @@
          * positions, then we don't want to modify its matrix. The explicitCoordStageMask is used
          * to specify such stages.
          */
-        AutoDeviceCoordDraw(GrDrawState* drawState,
-                            uint32_t explicitCoordStageMask = 0) {
+        AutoDeviceCoordDraw(GrDrawState* drawState) {
             fDrawState = NULL;
-            this->set(drawState, explicitCoordStageMask);
+            this->set(drawState);
         }
 
         ~AutoDeviceCoordDraw() { this->restore(); }
 
-        bool set(GrDrawState* drawState, uint32_t explicitCoordStageMask = 0);
+        bool set(GrDrawState* drawState);
 
         /**
          * Returns true if this object was successfully initialized on to a GrDrawState. It may
@@ -1197,8 +1143,7 @@
             return false;
         }
         for (int i = 0; i < kAttribIndexCount; ++i) {
-            if ((i == kPosition_AttribIndex ||
-                    s.fCommon.fAttribBindings & kAttribIndexMasks[i]) &&
+            if ((i == kPosition_AttribIndex || s.fCommon.fAttribBindings & (1 << i)) &&
                 fAttribIndices[i] != s.fAttribIndices[i]) {
                 return false;
             }
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index 6fdc3a0..cd4d4d2 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -529,11 +529,9 @@
 
 void GrDrawTarget::drawRect(const GrRect& rect,
                             const SkMatrix* matrix,
-                            const GrRect* srcRect,
-                            const SkMatrix* srcMatrix,
-                            int stage) {
+                            const GrRect* localRect,
+                            const SkMatrix* localMatrix) {
     GrAttribBindings bindings = 0;
-    uint32_t explicitCoordMask = 0;
     // position + (optional) texture coord
     static const GrVertexAttrib kAttribs[] = {
         {kVec2f_GrVertexAttribType, 0},
@@ -541,16 +539,15 @@
     };
     int attribCount = 1;
 
-    if (NULL != srcRect) {
-        bindings |= GrDrawState::ExplicitTexCoordAttribBindingsBit(stage);
+    if (NULL != localRect) {
+        bindings |= GrDrawState::kLocalCoords_AttribBindingsBit;
         attribCount = 2;
-        this->drawState()->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, 1);
-        explicitCoordMask = (1 << stage);
+        this->drawState()->setAttribIndex(GrDrawState::kLocalCoords_AttribIndex, 1);
     }
 
     GrDrawState::AutoViewMatrixRestore avmr;
     if (NULL != matrix) {
-        avmr.set(this->drawState(), *matrix, explicitCoordMask);
+        avmr.set(this->drawState(), *matrix);
     }
 
     this->drawState()->setVertexAttribs(kAttribs, attribCount);
@@ -564,15 +561,15 @@
 
     size_t vsize = this->drawState()->getVertexSize();
     geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize);
-    if (NULL != srcRect) {
+    if (NULL != localRect) {
         GrAssert(attribCount == 2);
         GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) +
                                             kAttribs[1].fOffset);
-        coords->setRectFan(srcRect->fLeft, srcRect->fTop,
-                            srcRect->fRight, srcRect->fBottom,
-                            vsize);
-        if (NULL != srcMatrix) {
-            srcMatrix->mapPointsWithStride(coords, vsize, 4);
+        coords->setRectFan(localRect->fLeft, localRect->fTop,
+                           localRect->fRight, localRect->fBottom,
+                           vsize);
+        if (NULL != localMatrix) {
+            localMatrix->mapPointsWithStride(coords, vsize, 4);
         }
     }
 
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index a011aae..de8c5c4 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -388,8 +388,8 @@
     /**
      * Helper function for drawing rects. This does not use the current index
      * and vertex sources. After returning, the vertex and index sources may
-     * have changed. They should be reestablished before the next drawIndexed
-     * or drawNonIndexed. This cannot be called between reserving and releasing
+     * have changed. They should be reestablished before the next draw call.
+     * This cannot be called between reserving and releasing
      * geometry.
      *
      * A subclass may override this to perform more optimal rect rendering. Its
@@ -397,34 +397,29 @@
      * (e.g. drawNonIndexed, drawIndexedInstances, ...). The base class draws a two
      * triangle fan using drawNonIndexed from reserved vertex space.
      *
-     * @param rect      the rect to draw
-     * @param matrix    optional matrix applied to rect (before viewMatrix)
-     * @param srcRects  specifies rect for explicit texture coordinates.
-     *                  if srcRect is non-NULL then that rect will be used
-     *                  as the coordinates for the given stage.
-     * @param srcMatrix   optional matrix applied to srcRect. If
+     * @param rect        the rect to draw
+     * @param matrix      optional matrix applied to rect (before viewMatrix)
+     * @param localRect   optional rect that specifies local coords to map onto
+     *                    rect. If NULL then rect serves as the local coords.
+     * @param localMatrix optional matrix applied to localRect. If
      *                    srcRect is non-NULL and srcMatrix is non-NULL
      *                    then srcRect will be transformed by srcMatrix.
      *                    srcMatrix can be NULL when no srcMatrix is desired.
-     * @param stage     the stage to be given explicit texture coordinates.
-     *                  Ignored if srcRect is NULL.
      */
     virtual void drawRect(const GrRect& rect,
                           const SkMatrix* matrix,
-                          const GrRect* srcRect,
-                          const SkMatrix* srcMatrix,
-                          int stage);
+                          const GrRect* localRect,
+                          const SkMatrix* localMatrix);
 
     /**
-     * Helper for drawRect when the caller doesn't need separate src rects or
-     * matrices.
+     * Helper for drawRect when the caller doesn't need separate local rects or matrices.
      */
     void drawSimpleRect(const GrRect& rect, const SkMatrix* matrix = NULL) {
-        drawRect(rect, matrix, NULL, NULL, 0);
+        drawRect(rect, matrix, NULL, NULL);
     }
     void drawSimpleRect(const GrIRect& irect, const SkMatrix* matrix = NULL) {
         SkRect rect = SkRect::MakeFromIRect(irect);
-        this->drawRect(rect, matrix, NULL, NULL, 0);
+        this->drawRect(rect, matrix, NULL, NULL);
     }
 
     /**
diff --git a/src/gpu/GrInOrderDrawBuffer.cpp b/src/gpu/GrInOrderDrawBuffer.cpp
index 31b1a57..6966858 100644
--- a/src/gpu/GrInOrderDrawBuffer.cpp
+++ b/src/gpu/GrInOrderDrawBuffer.cpp
@@ -74,9 +74,8 @@
 
 void GrInOrderDrawBuffer::drawRect(const GrRect& rect,
                                    const SkMatrix* matrix,
-                                   const GrRect* srcRect,
-                                   const SkMatrix* srcMatrix,
-                                   int stage) {
+                                   const GrRect* localRect,
+                                   const SkMatrix* localMatrix) {
 
     GrAttribBindings bindings = GrDrawState::kDefault_AttribBindings;
     GrDrawState::AutoColorRestore acr;
@@ -86,7 +85,7 @@
     GrColor color = drawState->getColor();
     GrVertexAttribArray<3> attribs;
     size_t currentOffset = 0;
-    int colorOffset = -1, texOffset = -1;
+    int colorOffset = -1, localOffset = -1;
 
     // set position attrib
     drawState->setAttribIndex(GrDrawState::kPosition_AttribIndex, attribs.count());
@@ -115,15 +114,13 @@
         acr.set(drawState, 0xFFFFFFFF);
     }
 
-    uint32_t explicitCoordMask = 0;
-    if (NULL != srcRect) {
-        bindings |= GrDrawState::ExplicitTexCoordAttribBindingsBit(stage);
-        drawState->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, attribs.count());
+    if (NULL != localRect) {
+        bindings |= GrDrawState::kLocalCoords_AttribBindingsBit;
+        drawState->setAttribIndex(GrDrawState::kLocalCoords_AttribIndex, attribs.count());
         currAttrib.set(kVec2f_GrVertexAttribType, currentOffset);
         attribs.push_back(currAttrib);
-        texOffset = currentOffset;
+        localOffset = currentOffset;
         currentOffset += sizeof(GrPoint);
-        explicitCoordMask = (1 << stage);
     }
 
     drawState->setVertexAttribs(attribs.begin(), attribs.count());
@@ -145,7 +142,7 @@
     // When the caller has provided an explicit source rect for a stage then we don't want to
     // modify that stage's matrix. Otherwise if the effect is generating its source rect from
     // the vertex positions then we have to account for the view matrix change.
-    GrDrawState::AutoDeviceCoordDraw adcd(drawState, explicitCoordMask);
+    GrDrawState::AutoDeviceCoordDraw adcd(drawState);
     if (!adcd.succeeded()) {
         return;
     }
@@ -161,15 +158,13 @@
     // unnecessary clipping in our onDraw().
     get_vertex_bounds(geo.vertices(), vsize, 4, &devBounds);
 
-    if (texOffset >= 0) {
-        GrAssert(explicitCoordMask != 0);
-        GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) +
-                                            texOffset);
-        coords->setRectFan(srcRect->fLeft, srcRect->fTop,
-                            srcRect->fRight, srcRect->fBottom,
+    if (localOffset >= 0) {
+        GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) + localOffset);
+        coords->setRectFan(localRect->fLeft, localRect->fTop,
+                           localRect->fRight, localRect->fBottom,
                             vsize);
-        if (NULL != srcMatrix) {
-            srcMatrix->mapPointsWithStride(coords, vsize, 4);
+        if (NULL != localMatrix) {
+            localMatrix->mapPointsWithStride(coords, vsize, 4);
         }
     }
 
diff --git a/src/gpu/GrInOrderDrawBuffer.h b/src/gpu/GrInOrderDrawBuffer.h
index f04bb84..cb51bc4 100644
--- a/src/gpu/GrInOrderDrawBuffer.h
+++ b/src/gpu/GrInOrderDrawBuffer.h
@@ -78,9 +78,8 @@
                        GrRenderTarget* renderTarget = NULL) SK_OVERRIDE;
     virtual void drawRect(const GrRect& rect,
                           const SkMatrix* matrix,
-                          const GrRect* srcRect,
-                          const SkMatrix* srcMatrix,
-                          int stage) SK_OVERRIDE;
+                          const GrRect* localRect,
+                          const SkMatrix* localMatrix) SK_OVERRIDE;
 
 protected:
     virtual void clipWillBeSet(const GrClipData* newClip) SK_OVERRIDE;
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index fe9fd82..2cf56d6 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -197,18 +197,29 @@
         // && edge rendering (kEdgeEffectStage in GrContext)
         kPathMaskStage = GrPaint::kTotalStages,
     };
-    GrAssert(!drawState->isStageEnabled(kPathMaskStage));
-    drawState->createTextureEffect(kPathMaskStage, texture, SkMatrix::I());
-    SkScalar w = SkIntToScalar(rect.width());
-    SkScalar h = SkIntToScalar(rect.height());
-    GrRect maskRect = GrRect::MakeWH(w / texture->width(),
-                                     h / texture->height());
 
     GrRect dstRect = GrRect::MakeLTRB(
                             SK_Scalar1 * rect.fLeft,
                             SK_Scalar1 * rect.fTop,
                             SK_Scalar1 * rect.fRight,
                             SK_Scalar1 * rect.fBottom);
-    target->drawRect(dstRect, NULL, &maskRect, NULL, kPathMaskStage);
+
+    // We want to use device coords to compute the texture coordinates. We set our matrix to be
+    // equal to the view matrix followed by a translation so that the top-left of the device bounds
+    // maps to 0,0, and then a scaling matrix to normalized coords. We apply this matrix to the
+    // vertex positions rather than local coords.
+    SkMatrix maskMatrix;
+    maskMatrix.setIDiv(texture->width(), texture->height());
+    maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop));
+    maskMatrix.preConcat(drawState->getViewMatrix());
+
+    GrAssert(!drawState->isStageEnabled(kPathMaskStage));
+    drawState->setEffect(kPathMaskStage,
+                         GrSimpleTextureEffect::Create(texture,
+                                                       maskMatrix,
+                                                       false,
+                                                       GrEffect::kPosition_CoordsType))->unref();
+
+    target->drawSimpleRect(dstRect);
     drawState->disableStage(kPathMaskStage);
 }
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index 5ff13b0..ab2bc42 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -18,12 +18,10 @@
 #include "SkPath.h"
 #include "SkStrokeRec.h"
 
-enum {
-    // glyph rendering shares this stage with edge rendering
-    // (kEdgeEffectStage in GrContext) && SW path rendering
-    // (kPathMaskStage in GrSWMaskHelper)
-    kGlyphMaskStage = GrPaint::kTotalStages,
-};
+// glyph rendering shares this stage with edge rendering (kEdgeEffectStage in GrContext) && SW path
+// rendering (kPathMaskStage in GrSWMaskHelper)
+static const int kGlyphMaskStage = GrPaint::kTotalStages;
+static const int kGlyphCoordsAttributeIndex = 1;
 
 void GrTextContext::flushGlyphs() {
     if (NULL == fDrawTarget) {
@@ -35,7 +33,11 @@
         GrAssert(GrIsALIGN4(fCurrVertex));
         GrAssert(fCurrTexture);
         GrTextureParams params(SkShader::kRepeat_TileMode, false);
-        drawState->createTextureEffect(kGlyphMaskStage, fCurrTexture, SkMatrix::I(), params);
+
+        // This effect could be stored with one of the cache objects (atlas?)
+        drawState->setEffect(kGlyphMaskStage,
+                             GrSimpleTextureEffect::CreateWithCustomCoords(fCurrTexture, params),
+                             kGlyphCoordsAttributeIndex)->unref();
 
         if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
             if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
@@ -195,7 +197,7 @@
             {kVec2f_GrVertexAttribType, 0},
             {kVec2f_GrVertexAttribType, sizeof(GrPoint)}
         };
-        static const GrAttribBindings kAttribBindings = GrDrawState::ExplicitTexCoordAttribBindingsBit(kGlyphMaskStage);
+        static const GrAttribBindings kAttribBindings = 0;
 
        // If we need to reserve vertices allow the draw target to suggest
         // a number of verts to reserve and whether to perform a flush.
@@ -214,7 +216,6 @@
             fDrawTarget->drawState()->setVertexAttribs(kVertexAttribs, SK_ARRAY_COUNT(kVertexAttribs));
         }
         fDrawTarget->drawState()->setAttribIndex(GrDrawState::kPosition_AttribIndex, 0);
-        fDrawTarget->drawState()->setAttribIndex(GrDrawState::kTexCoord_AttribIndex, 1);
         fDrawTarget->drawState()->setAttribBindings(kAttribBindings);
         fMaxVertices = kDefaultRequestedVerts;
         // ignore return, no point in flushing again.
diff --git a/src/gpu/effects/GrCircleEdgeEffect.cpp b/src/gpu/effects/GrCircleEdgeEffect.cpp
index ba73502..4ecdedb 100644
--- a/src/gpu/effects/GrCircleEdgeEffect.cpp
+++ b/src/gpu/effects/GrCircleEdgeEffect.cpp
@@ -17,29 +17,27 @@
 
 class GrGLCircleEdgeEffect : public GrGLEffect {
 public:
-    GrGLCircleEdgeEffect(const GrBackendEffectFactory& factory, const GrEffectRef&)
+    GrGLCircleEdgeEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
     : INHERITED (factory) {}
 
     virtual void emitCode(GrGLShaderBuilder* builder,
-                          const GrEffectStage& stage,
+                          const GrDrawEffect& drawEffect,
                           EffectKey key,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        const GrCircleEdgeEffect& effect = GetEffectFromStage<GrCircleEdgeEffect>(stage);
-
+        const GrCircleEdgeEffect& circleEffect = drawEffect.castEffect<GrCircleEdgeEffect>();
         const char *vsName, *fsName;
         builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
 
         const SkString* attrName =
-            builder->getEffectAttributeName(stage.getVertexAttribIndices()[0]);
+            builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
         builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
 
         builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n",
                                builder->fragmentPosition(), fsName);
         builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
-        if (effect.isStroked()) {
+        if (circleEffect.isStroked()) {
             builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName);
             builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
         }
@@ -48,13 +46,13 @@
         builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
     }
 
-    static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
-        const GrCircleEdgeEffect& effect = GetEffectFromStage<GrCircleEdgeEffect>(stage);
+    static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+        const GrCircleEdgeEffect& circleEffect = drawEffect.castEffect<GrCircleEdgeEffect>();
 
-        return effect.isStroked() ? 0x1 : 0x0;
+        return circleEffect.isStroked() ? 0x1 : 0x0;
     }
 
-    virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE {
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {
     }
 
 private:
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index 5cc05e2..df8ab8d 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -16,21 +16,22 @@
 class GrGLConfigConversionEffect : public GrGLEffect {
 public:
     GrGLConfigConversionEffect(const GrBackendEffectFactory& factory,
-                               const GrEffectRef& s) : INHERITED (factory) {
-        const GrConfigConversionEffect& effect = CastEffect<GrConfigConversionEffect>(s);
+                               const GrDrawEffect& drawEffect)
+    : INHERITED (factory)
+    , fEffectMatrix(drawEffect.castEffect<GrConfigConversionEffect>().coordsType()) {
+        const GrConfigConversionEffect& effect = drawEffect.castEffect<GrConfigConversionEffect>();
         fSwapRedAndBlue = effect.swapsRedAndBlue();
         fPMConversion = effect.pmConversion();
     }
 
     virtual void emitCode(GrGLShaderBuilder* builder,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey key,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
         const char* coords;
-        GrSLType coordsType = fEffectMatrix.emitCode(builder, key, vertexCoords, &coords);
+        GrSLType coordsType = fEffectMatrix.emitCode(builder, key, &coords);
         builder->fsCodeAppendf("\t\t%s = ", outputColor);
         builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
                                      samplers[0],
@@ -71,23 +72,19 @@
         builder->fsCodeAppend(modulate.c_str());
     }
 
-    void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-        const GrConfigConversionEffect& effect =
-            GetEffectFromStage<GrConfigConversionEffect>(stage);
-        fEffectMatrix.setData(uman,
-                              effect.getMatrix(),
-                              stage.getCoordChangeMatrix(),
-                              effect.texture(0));
+    void setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) {
+        const GrConfigConversionEffect& conv = drawEffect.castEffect<GrConfigConversionEffect>();
+        fEffectMatrix.setData(uman, conv.getMatrix(), drawEffect, conv.texture(0));
     }
 
-    static inline EffectKey GenKey(const GrEffectStage& s, const GrGLCaps&) {
-        const GrConfigConversionEffect& effect = GetEffectFromStage<GrConfigConversionEffect>(s);
-        EffectKey key = static_cast<EffectKey>(effect.swapsRedAndBlue()) |
-                        (effect.pmConversion() << 1);
+    static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+        const GrConfigConversionEffect& conv = drawEffect.castEffect<GrConfigConversionEffect>();
+        EffectKey key = static_cast<EffectKey>(conv.swapsRedAndBlue()) | (conv.pmConversion() << 1);
         key <<= GrGLEffectMatrix::kKeyBits;
-        EffectKey matrixKey =  GrGLEffectMatrix::GenKey(effect.getMatrix(),
-                                                        s.getCoordChangeMatrix(),
-                                                        effect.texture(0));
+        EffectKey matrixKey =  GrGLEffectMatrix::GenKey(conv.getMatrix(),
+                                                        drawEffect,
+                                                        conv.coordsType(),
+                                                        conv.texture(0));
         GrAssert(!(matrixKey & key));
         return matrixKey | key;
     }
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index 794a936..924b03c 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -18,19 +18,18 @@
 
 class GrGLConvolutionEffect : public GrGLEffect {
 public:
-    GrGLConvolutionEffect(const GrBackendEffectFactory&, const GrEffectRef&);
+    GrGLConvolutionEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    virtual void setData(const GrGLUniformManager& uman, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE;
 
-    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
 private:
     int width() const { return Gr1DKernelEffect::WidthFromRadius(fRadius); }
@@ -44,23 +43,23 @@
 };
 
 GrGLConvolutionEffect::GrGLConvolutionEffect(const GrBackendEffectFactory& factory,
-                                             const GrEffectRef& effect)
+                                             const GrDrawEffect& drawEffect)
     : INHERITED(factory)
     , fKernelUni(kInvalidUniformHandle)
-    , fImageIncrementUni(kInvalidUniformHandle) {
-    const GrConvolutionEffect& c = CastEffect<GrConvolutionEffect>(effect);
+    , fImageIncrementUni(kInvalidUniformHandle)
+    , fEffectMatrix(drawEffect.castEffect<GrConvolutionEffect>().coordsType()) {
+    const GrConvolutionEffect& c = drawEffect.castEffect<GrConvolutionEffect>();
     fRadius = c.radius();
 }
 
 void GrGLConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
-                                     const GrEffectStage&,
+                                     const GrDrawEffect&,
                                      EffectKey key,
-                                     const char* vertexCoords,
                                      const char* outputColor,
                                      const char* inputColor,
                                      const TextureSamplerArray& samplers) {
     const char* coords;
-    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
     fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                              kVec2f_GrSLType, "ImageIncrement");
     fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_ShaderType,
@@ -90,8 +89,9 @@
     builder->fsCodeAppend(modulate.c_str());
 }
 
-void GrGLConvolutionEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    const GrConvolutionEffect& conv = GetEffectFromStage<GrConvolutionEffect>(stage);
+void GrGLConvolutionEffect::setData(const GrGLUniformManager& uman,
+                                    const GrDrawEffect& drawEffect) {
+    const GrConvolutionEffect& conv = drawEffect.castEffect<GrConvolutionEffect>();
     GrTexture& texture = *conv.texture(0);
     // the code we generated was for a specific kernel radius
     GrAssert(conv.radius() == fRadius);
@@ -108,15 +108,17 @@
     }
     uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
     uman.set1fv(fKernelUni, 0, this->width(), conv.kernel());
-    fEffectMatrix.setData(uman, conv.getMatrix(), stage.getCoordChangeMatrix(), conv.texture(0));
+    fEffectMatrix.setData(uman, conv.getMatrix(), drawEffect, conv.texture(0));
 }
 
-GrGLEffect::EffectKey GrGLConvolutionEffect::GenKey(const GrEffectStage& s, const GrGLCaps&) {
-    const GrConvolutionEffect& conv = GetEffectFromStage<GrConvolutionEffect>(s);
+GrGLEffect::EffectKey GrGLConvolutionEffect::GenKey(const GrDrawEffect& drawEffect,
+                                                    const GrGLCaps&) {
+    const GrConvolutionEffect& conv = drawEffect.castEffect<GrConvolutionEffect>();
     EffectKey key = conv.radius();
     key <<= GrGLEffectMatrix::kKeyBits;
     EffectKey matrixKey = GrGLEffectMatrix::GenKey(conv.getMatrix(),
-                                                   s.getCoordChangeMatrix(),
+                                                   drawEffect,
+                                                   conv.coordsType(),
                                                    conv.texture(0));
     return key | matrixKey;
 }
diff --git a/src/gpu/effects/GrEllipseEdgeEffect.cpp b/src/gpu/effects/GrEllipseEdgeEffect.cpp
index 37432f0..12f3197 100644
--- a/src/gpu/effects/GrEllipseEdgeEffect.cpp
+++ b/src/gpu/effects/GrEllipseEdgeEffect.cpp
@@ -15,29 +15,28 @@
 
 class GrGLEllipseEdgeEffect : public GrGLEffect {
 public:
-    GrGLEllipseEdgeEffect(const GrBackendEffectFactory& factory, const GrEffectRef&)
+    GrGLEllipseEdgeEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
     : INHERITED (factory) {}
 
     virtual void emitCode(GrGLShaderBuilder* builder,
-                          const GrEffectStage& stage,
+                          const GrDrawEffect& drawEffect,
                           EffectKey key,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        const GrEllipseEdgeEffect& effect = GetEffectFromStage<GrEllipseEdgeEffect>(stage);
+        const GrEllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<GrEllipseEdgeEffect>();
 
         const char *vsCenterName, *fsCenterName;
         const char *vsEdgeName, *fsEdgeName;
 
         builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName, &fsCenterName);
         const SkString* attr0Name =
-            builder->getEffectAttributeName(stage.getVertexAttribIndices()[0]);
+            builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
         builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_str());
 
         builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fsEdgeName);
         const SkString* attr1Name =
-            builder->getEffectAttributeName(stage.getVertexAttribIndices()[1]);
+            builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
         builder->vsCodeAppendf("\t%s = %s;\n", vsEdgeName, attr1Name->c_str());
 
         // translate to origin
@@ -50,7 +49,7 @@
         // compare outer lengths against xOuterRadius
         builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n", fsEdgeName);
 
-        if (effect.isStroked()) {
+        if (ellipseEffect.isStroked()) {
             builder->fsCodeAppendf("\tinnerOffset.y *= %s.w;\n", fsEdgeName);
             builder->fsCodeAppend("\tfloat dInner = length(innerOffset);\n");
 
@@ -64,13 +63,13 @@
         builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
     }
 
-    static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
-        const GrEllipseEdgeEffect& effect = GetEffectFromStage<GrEllipseEdgeEffect>(stage);
+    static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+        const GrEllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<GrEllipseEdgeEffect>();
 
-        return effect.isStroked() ? 0x1 : 0x0;
+        return ellipseEffect.isStroked() ? 0x1 : 0x0;
     }
 
-    virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE {
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {
     }
 
 private:
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index 37e6eb4..80627aa 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -15,41 +15,69 @@
 
 class GrGLSimpleTextureEffect : public GrGLEffect {
 public:
-    GrGLSimpleTextureEffect(const GrBackendEffectFactory& factory, const GrEffectRef&)
-    : INHERITED (factory) {}
+    GrGLSimpleTextureEffect(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect)
+    : INHERITED (factory) {
+        GrEffect::CoordsType coordsType =
+            drawEffect.castEffect<GrSimpleTextureEffect>().coordsType();
+        if (GrEffect::kCustom_CoordsType != coordsType) {
+            SkNEW_IN_TLAZY(&fEffectMatrix, GrGLEffectMatrix, (coordsType));
+        }
+    }
 
     virtual void emitCode(GrGLShaderBuilder* builder,
-                          const GrEffectStage&,
+                          const GrDrawEffect& drawEffect,
                           EffectKey key,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        const char* coordName;
-        GrSLType coordType = fEffectMatrix.emitCode(builder, key, vertexCoords, &coordName);
+        const GrSimpleTextureEffect& ste = drawEffect.castEffect<GrSimpleTextureEffect>();
+        const char* fsCoordName;
+        GrSLType fsCoordSLType;
+        if (GrEffect::kCustom_CoordsType == ste.coordsType()) {
+            GrAssert(ste.getMatrix().isIdentity());
+            GrAssert(1 == ste.numVertexAttribs());
+            fsCoordSLType = kVec2f_GrSLType;
+            const char* vsVaryingName;
+            builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsVaryingName, &fsCoordName);
+            const char* attrName =
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str();
+            builder->vsCodeAppendf("\t%s = %s;", vsVaryingName, attrName);
+        } else {
+            fsCoordSLType = fEffectMatrix.get()->emitCode(builder, key, &fsCoordName);
+        }
         builder->fsCodeAppendf("\t%s = ", outputColor);
         builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
                                                 inputColor,
                                                 samplers[0],
-                                                coordName,
-                                                coordType);
+                                                fsCoordName,
+                                                fsCoordSLType);
         builder->fsCodeAppend(";\n");
     }
 
-    static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
-        const GrSimpleTextureEffect& ste = GetEffectFromStage<GrSimpleTextureEffect>(stage);
-        return GrGLEffectMatrix::GenKey(ste.getMatrix(),
-                                        stage.getCoordChangeMatrix(),
-                                        ste.texture(0));
+    static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
+        const GrSimpleTextureEffect& ste = drawEffect.castEffect<GrSimpleTextureEffect>();
+        if (GrEffect::kCustom_CoordsType == ste.coordsType()) {
+            return 1 << GrGLEffectMatrix::kKeyBits;
+        } else {
+            return GrGLEffectMatrix::GenKey(ste.getMatrix(),
+                                            drawEffect,
+                                            ste.coordsType(),
+                                            ste.texture(0));
+        }
     }
 
-    virtual void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) SK_OVERRIDE {
-        const GrSimpleTextureEffect& ste = GetEffectFromStage<GrSimpleTextureEffect>(stage);
-        fEffectMatrix.setData(uman, ste.getMatrix(), stage.getCoordChangeMatrix(), ste.texture(0));
+    virtual void setData(const GrGLUniformManager& uman,
+                         const GrDrawEffect& drawEffect) SK_OVERRIDE {
+        const GrSimpleTextureEffect& ste = drawEffect.castEffect<GrSimpleTextureEffect>();
+        if (GrEffect::kCustom_CoordsType == ste.coordsType()) {
+            GrAssert(ste.getMatrix().isIdentity());
+        } else {
+            fEffectMatrix.get()->setData(uman, ste.getMatrix(), drawEffect, ste.texture(0));
+        }
     }
 
 private:
-    GrGLEffectMatrix fEffectMatrix;
+    SkTLazy<GrGLEffectMatrix> fEffectMatrix;
     typedef GrGLEffect INHERITED;
 };
 
@@ -72,6 +100,28 @@
                                                GrTexture* textures[]) {
     int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
                                       GrEffectUnitTest::kAlphaTextureIdx;
-    const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random);
-    return GrSimpleTextureEffect::Create(textures[texIdx], matrix);
+    static const SkShader::TileMode kTileModes[] = {
+        SkShader::kClamp_TileMode,
+        SkShader::kRepeat_TileMode,
+        SkShader::kMirror_TileMode,
+    };
+    SkShader::TileMode tileModes[] = {
+        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
+        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
+    };
+    GrTextureParams params(tileModes, random->nextBool());
+
+    static const CoordsType kCoordsTypes[] = {
+        kLocal_CoordsType,
+        kPosition_CoordsType,
+        kCustom_CoordsType
+    };
+    CoordsType coordsType = kCoordsTypes[random->nextULessThan(GR_ARRAY_COUNT(kCoordsTypes))];
+
+    if (kCustom_CoordsType == coordsType) {
+        return GrSimpleTextureEffect::CreateWithCustomCoords(textures[texIdx], params);
+    } else {
+        const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random);
+        return GrSimpleTextureEffect::Create(textures[texIdx], matrix);
+    }
 }
diff --git a/src/gpu/effects/GrSimpleTextureEffect.h b/src/gpu/effects/GrSimpleTextureEffect.h
index ffc05e5..661f40f 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.h
+++ b/src/gpu/effects/GrSimpleTextureEffect.h
@@ -14,25 +14,50 @@
 
 /**
  * The output color of this effect is a modulation of the input color and a sample from a texture.
- * The coord to sample the texture is determine by a matrix. It allows explicit specification of
- * the filtering and wrap modes (GrTextureParams).
+ * It allows explicit specification of the filtering and wrap modes (GrTextureParams). It can use
+ * local coords, positions, or a custom vertex attribute as input texture coords. The input coords
+ * can have a matrix applied in the VS in both the local and position cases but not with a custom
+ * attribute coords at this time. It will add a varying to input interpolate texture coords to the
+ * FS.
  */
 class GrSimpleTextureEffect : public GrSingleTextureEffect {
 public:
     /* unfiltered, clamp mode */
-    static GrEffectRef* Create(GrTexture* tex, const SkMatrix& matrix) {
-        AutoEffectUnref effect(SkNEW_ARGS(GrSimpleTextureEffect, (tex, matrix)));
+    static GrEffectRef* Create(GrTexture* tex,
+                               const SkMatrix& matrix,
+                               CoordsType coordsType = kLocal_CoordsType) {
+        GrAssert(kLocal_CoordsType == coordsType || kPosition_CoordsType == coordsType);
+        AutoEffectUnref effect(SkNEW_ARGS(GrSimpleTextureEffect, (tex, matrix, false, coordsType)));
         return CreateEffectRef(effect);
     }
 
     /* clamp mode */
-    static GrEffectRef* Create(GrTexture* tex, const SkMatrix& matrix, bool bilerp) {
-        AutoEffectUnref effect(SkNEW_ARGS(GrSimpleTextureEffect, (tex, matrix, bilerp)));
+    static GrEffectRef* Create(GrTexture* tex,
+                               const SkMatrix& matrix,
+                               bool bilerp,
+                               CoordsType coordsType = kLocal_CoordsType) {
+        GrAssert(kLocal_CoordsType == coordsType || kPosition_CoordsType == coordsType);
+        AutoEffectUnref effect(
+            SkNEW_ARGS(GrSimpleTextureEffect, (tex, matrix, bilerp, coordsType)));
         return CreateEffectRef(effect);
     }
 
-    static GrEffectRef* Create(GrTexture* tex, const SkMatrix& matrix, const GrTextureParams& p) {
-        AutoEffectUnref effect(SkNEW_ARGS(GrSimpleTextureEffect, (tex, matrix, p)));
+    static GrEffectRef* Create(GrTexture* tex,
+                               const SkMatrix& matrix,
+                               const GrTextureParams& p,
+                               CoordsType coordsType = kLocal_CoordsType) {
+        GrAssert(kLocal_CoordsType == coordsType || kPosition_CoordsType == coordsType);
+        AutoEffectUnref effect(SkNEW_ARGS(GrSimpleTextureEffect, (tex, matrix, p, coordsType)));
+        return CreateEffectRef(effect);
+    }
+
+    /** Variant that requires the client to install a custom kVec2 vertex attribute that will be
+        the source of the coords. No matrix is allowed in this mode. */
+    static GrEffectRef* CreateWithCustomCoords(GrTexture* tex, const GrTextureParams& p) {
+        AutoEffectUnref effect(SkNEW_ARGS(GrSimpleTextureEffect, (tex,
+                                                                  SkMatrix::I(),
+                                                                  p,
+                                                                  kCustom_CoordsType)));
         return CreateEffectRef(effect);
     }
 
@@ -47,16 +72,28 @@
     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
 
 private:
-    GrSimpleTextureEffect(GrTexture* texture, const SkMatrix& matrix)
-        : GrSingleTextureEffect(texture, matrix) {}
-    GrSimpleTextureEffect(GrTexture* texture, const SkMatrix& matrix, bool bilerp)
-        : GrSingleTextureEffect(texture, matrix, bilerp) {}
-    GrSimpleTextureEffect(GrTexture* texture, const SkMatrix& matrix, const GrTextureParams& params)
-        : GrSingleTextureEffect(texture, matrix, params) {}
+    GrSimpleTextureEffect(GrTexture* texture,
+                          const SkMatrix& matrix,
+                          bool bilerp,
+                          CoordsType coordsType)
+        : GrSingleTextureEffect(texture, matrix, bilerp, coordsType) {
+        GrAssert(kLocal_CoordsType == coordsType || kPosition_CoordsType == coordsType);
+    }
+
+    GrSimpleTextureEffect(GrTexture* texture,
+                          const SkMatrix& matrix,
+                          const GrTextureParams& params,
+                          CoordsType coordsType)
+        : GrSingleTextureEffect(texture, matrix, params, coordsType) {
+        if (kCustom_CoordsType == coordsType) {
+            GrAssert(matrix.isIdentity());
+            this->addVertexAttrib(kVec2f_GrSLType);
+        }
+    }
 
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
         const GrSimpleTextureEffect& ste = CastEffect<GrSimpleTextureEffect>(other);
-        return this->hasSameTextureParamsAndMatrix(ste);
+        return this->hasSameTextureParamsMatrixAndCoordsType(ste);
     }
 
     GR_DECLARE_EFFECT_TEST;
diff --git a/src/gpu/effects/GrSingleTextureEffect.cpp b/src/gpu/effects/GrSingleTextureEffect.cpp
index 7183ba3..0c671f1 100644
--- a/src/gpu/effects/GrSingleTextureEffect.cpp
+++ b/src/gpu/effects/GrSingleTextureEffect.cpp
@@ -7,23 +7,32 @@
 
 #include "effects/GrSingleTextureEffect.h"
 
-GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, const SkMatrix& m)
+GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture,
+                                             const SkMatrix& m,
+                                             CoordsType coordsType)
     : fTextureAccess(texture)
-    , fMatrix(m) {
-    this->addTextureAccess(&fTextureAccess);
-}
-
-GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture, const SkMatrix& m, bool bilerp)
-    : fTextureAccess(texture, bilerp)
-    , fMatrix(m) {
+    , fMatrix(m)
+    , fCoordsType(coordsType) {
     this->addTextureAccess(&fTextureAccess);
 }
 
 GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture,
                                              const SkMatrix& m,
-                                             const GrTextureParams& params)
+                                             bool bilerp,
+                                             CoordsType coordsType)
+    : fTextureAccess(texture, bilerp)
+    , fMatrix(m)
+    , fCoordsType(coordsType) {
+    this->addTextureAccess(&fTextureAccess);
+}
+
+GrSingleTextureEffect::GrSingleTextureEffect(GrTexture* texture,
+                                             const SkMatrix& m,
+                                             const GrTextureParams& params,
+                                             CoordsType coordsType)
     : fTextureAccess(texture, params)
-    , fMatrix(m) {
+    , fMatrix(m)
+    , fCoordsType(coordsType) {
     this->addTextureAccess(&fTextureAccess);
 }
 
diff --git a/src/gpu/effects/GrSingleTextureEffect.h b/src/gpu/effects/GrSingleTextureEffect.h
index 4f25ddb..82037cf 100644
--- a/src/gpu/effects/GrSingleTextureEffect.h
+++ b/src/gpu/effects/GrSingleTextureEffect.h
@@ -14,7 +14,8 @@
 class GrTexture;
 
 /**
- * A base class for effects that draw a single texture with a texture matrix.
+ * A base class for effects that draw a single texture with a texture matrix. This effect has no
+ * backend implementations. One must be provided by the subclass.
  */
 class GrSingleTextureEffect : public GrEffect {
 public:
@@ -22,20 +23,29 @@
 
     const SkMatrix& getMatrix() const { return fMatrix; }
 
+    /** Indicates whether the matrix operates on local coords or positions */
+    CoordsType coordsType() const { return fCoordsType; }
+
 protected:
-    GrSingleTextureEffect(GrTexture*, const SkMatrix&); /* unfiltered, clamp mode */
-    GrSingleTextureEffect(GrTexture*, const SkMatrix&, bool bilerp); /* clamp mode */
-    GrSingleTextureEffect(GrTexture*, const SkMatrix&, const GrTextureParams&);
+    /** unfiltered, clamp mode */
+    GrSingleTextureEffect(GrTexture*, const SkMatrix&, CoordsType = kLocal_CoordsType);
+    /** clamp mode */
+    GrSingleTextureEffect(GrTexture*, const SkMatrix&, bool bilerp, CoordsType = kLocal_CoordsType);
+    GrSingleTextureEffect(GrTexture*,
+                          const SkMatrix&,
+                          const GrTextureParams&,
+                          CoordsType = kLocal_CoordsType);
 
     /**
      * Helper for subclass onIsEqual() functions.
      */
-    bool hasSameTextureParamsAndMatrix(const GrSingleTextureEffect& other) const {
+    bool hasSameTextureParamsMatrixAndCoordsType(const GrSingleTextureEffect& other) const {
         const GrTextureAccess& otherAccess = other.fTextureAccess;
         // We don't have to check the accesses' swizzles because they are inferred from the texture.
         return fTextureAccess.getTexture() == otherAccess.getTexture() &&
                fTextureAccess.getParams() == otherAccess.getParams() &&
-               this->getMatrix().cheapEqualTo(other.getMatrix());
+               this->getMatrix().cheapEqualTo(other.getMatrix()) &&
+               fCoordsType == other.fCoordsType;
     }
 
     /**
@@ -55,6 +65,7 @@
 private:
     GrTextureAccess fTextureAccess;
     SkMatrix        fMatrix;
+    CoordsType      fCoordsType;
 
     typedef GrEffect INHERITED;
 };
diff --git a/src/gpu/effects/GrTextureDomainEffect.cpp b/src/gpu/effects/GrTextureDomainEffect.cpp
index e54af25..b1fd3ed 100644
--- a/src/gpu/effects/GrTextureDomainEffect.cpp
+++ b/src/gpu/effects/GrTextureDomainEffect.cpp
@@ -14,19 +14,18 @@
 
 class GrGLTextureDomainEffect : public GrGLEffect {
 public:
-    GrGLTextureDomainEffect(const GrBackendEffectFactory&, const GrEffectRef&);
+    GrGLTextureDomainEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
     virtual void emitCode(GrGLShaderBuilder*,
-                          const GrEffectStage&,
+                          const GrDrawEffect&,
                           EffectKey,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray&) SK_OVERRIDE;
 
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
 
-    static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&);
+    static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&);
 
 private:
     GrGLUniformManager::UniformHandle fNameUni;
@@ -37,27 +36,27 @@
 };
 
 GrGLTextureDomainEffect::GrGLTextureDomainEffect(const GrBackendEffectFactory& factory,
-                                                 const GrEffectRef&)
+                                                 const GrDrawEffect& drawEffect)
     : INHERITED(factory)
-    , fNameUni(GrGLUniformManager::kInvalidUniformHandle) {
+    , fNameUni(GrGLUniformManager::kInvalidUniformHandle)
+    , fEffectMatrix(drawEffect.castEffect<GrTextureDomainEffect>().coordsType()) {
     fPrevDomain[0] = SK_FloatNaN;
 }
 
 void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder,
-                                       const GrEffectStage& stage,
+                                       const GrDrawEffect& drawEffect,
                                        EffectKey key,
-                                       const char* vertexCoords,
                                        const char* outputColor,
                                        const char* inputColor,
                                        const TextureSamplerArray& samplers) {
-    const GrTextureDomainEffect& effect = GetEffectFromStage<GrTextureDomainEffect>(stage);
+    const GrTextureDomainEffect& texDom = drawEffect.castEffect<GrTextureDomainEffect>();
 
     const char* coords;
-    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, vertexCoords, &coords);
+    fEffectMatrix.emitCodeMakeFSCoords2D(builder, key, &coords);
     const char* domain;
     fNameUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                     kVec4f_GrSLType, "TexDom", &domain);
-    if (GrTextureDomainEffect::kClamp_WrapMode == effect.wrapMode()) {
+    if (GrTextureDomainEffect::kClamp_WrapMode == texDom.wrapMode()) {
 
         builder->fsCodeAppendf("\tvec2 clampCoord = clamp(%s, %s.xy, %s.zw);\n",
                                 coords, domain, domain);
@@ -69,7 +68,7 @@
                                                 "clampCoord");
         builder->fsCodeAppend(";\n");
     } else {
-        GrAssert(GrTextureDomainEffect::kDecal_WrapMode == effect.wrapMode());
+        GrAssert(GrTextureDomainEffect::kDecal_WrapMode == texDom.wrapMode());
 
         if (kImagination_GrGLVendor == builder->ctxInfo().vendor()) {
             // On the NexusS and GalaxyNexus, the other path (with the 'any'
@@ -106,9 +105,10 @@
     }
 }
 
-void GrGLTextureDomainEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
-    const GrTextureDomainEffect& effect = GetEffectFromStage<GrTextureDomainEffect>(stage);
-    const GrRect& domain = effect.domain();
+void GrGLTextureDomainEffect::setData(const GrGLUniformManager& uman,
+                                      const GrDrawEffect& drawEffect) {
+    const GrTextureDomainEffect& texDom = drawEffect.castEffect<GrTextureDomainEffect>();
+    const GrRect& domain = texDom.domain();
 
     float values[4] = {
         SkScalarToFloat(domain.left()),
@@ -117,7 +117,7 @@
         SkScalarToFloat(domain.bottom())
     };
     // vertical flip if necessary
-    if (kBottomLeft_GrSurfaceOrigin == effect.texture(0)->origin()) {
+    if (kBottomLeft_GrSurfaceOrigin == texDom.texture(0)->origin()) {
         values[1] = 1.0f - values[1];
         values[3] = 1.0f - values[3];
         // The top and bottom were just flipped, so correct the ordering
@@ -128,18 +128,20 @@
         uman.set4fv(fNameUni, 0, 1, values);
     }
     fEffectMatrix.setData(uman,
-                          effect.getMatrix(),
-                          stage.getCoordChangeMatrix(),
-                          effect.texture(0));
+                          texDom.getMatrix(),
+                          drawEffect,
+                          texDom.texture(0));
 }
 
-GrGLEffect::EffectKey GrGLTextureDomainEffect::GenKey(const GrEffectStage& stage, const GrGLCaps&) {
-    const GrTextureDomainEffect& effect = GetEffectFromStage<GrTextureDomainEffect>(stage);
-    EffectKey key = effect.wrapMode();
+GrGLEffect::EffectKey GrGLTextureDomainEffect::GenKey(const GrDrawEffect& drawEffect,
+                                                      const GrGLCaps&) {
+    const GrTextureDomainEffect& texDom = drawEffect.castEffect<GrTextureDomainEffect>();
+    EffectKey key = texDom.wrapMode();
     key <<= GrGLEffectMatrix::kKeyBits;
-    EffectKey matrixKey = GrGLEffectMatrix::GenKey(effect.getMatrix(),
-                                                   stage.getCoordChangeMatrix(),
-                                                   effect.texture(0));
+    EffectKey matrixKey = GrGLEffectMatrix::GenKey(texDom.getMatrix(),
+                                                   drawEffect,
+                                                   texDom.coordsType(),
+                                                   texDom.texture(0));
     return key | matrixKey;
 }
 
@@ -150,7 +152,8 @@
                                            const SkMatrix& matrix,
                                            const GrRect& domain,
                                            WrapMode wrapMode,
-                                           bool bilerp) {
+                                           bool bilerp,
+                                           CoordsType coordsType) {
     static const SkRect kFullRect = {0, 0, SK_Scalar1, SK_Scalar1};
     if (kClamp_WrapMode == wrapMode && domain.contains(kFullRect)) {
         return GrSimpleTextureEffect::Create(texture, matrix, bilerp);
@@ -172,7 +175,8 @@
                                                                   matrix,
                                                                   clippedDomain,
                                                                   wrapMode,
-                                                                  bilerp)));
+                                                                  bilerp,
+                                                                  coordsType)));
         return CreateEffectRef(effect);
 
     }
@@ -182,8 +186,9 @@
                                              const SkMatrix& matrix,
                                              const GrRect& domain,
                                              WrapMode wrapMode,
-                                             bool bilerp)
-    : GrSingleTextureEffect(texture, matrix, bilerp)
+                                             bool bilerp,
+                                             CoordsType coordsType)
+    : GrSingleTextureEffect(texture, matrix, bilerp, coordsType)
     , fWrapMode(wrapMode)
     , fTextureDomain(domain) {
 }
@@ -198,7 +203,8 @@
 
 bool GrTextureDomainEffect::onIsEqual(const GrEffect& sBase) const {
     const GrTextureDomainEffect& s = CastEffect<GrTextureDomainEffect>(sBase);
-    return this->hasSameTextureParamsAndMatrix(s) && this->fTextureDomain == s.fTextureDomain;
+    return this->hasSameTextureParamsMatrixAndCoordsType(s) &&
+           this->fTextureDomain == s.fTextureDomain;
 }
 
 void GrTextureDomainEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const {
@@ -225,5 +231,12 @@
     domain.fBottom = random->nextRangeScalar(domain.fTop, SK_Scalar1);
     WrapMode wrapMode = random->nextBool() ? kClamp_WrapMode : kDecal_WrapMode;
     const SkMatrix& matrix = GrEffectUnitTest::TestMatrix(random);
-    return GrTextureDomainEffect::Create(textures[texIdx], matrix, domain, wrapMode);
+    bool bilerp = random->nextBool();
+    CoordsType coords = random->nextBool() ? kLocal_CoordsType : kPosition_CoordsType;
+    return GrTextureDomainEffect::Create(textures[texIdx],
+                                         matrix,
+                                         domain,
+                                         wrapMode,
+                                         bilerp,
+                                         coords);
 }
diff --git a/src/gpu/effects/GrTextureDomainEffect.h b/src/gpu/effects/GrTextureDomainEffect.h
index b7f665c..8b1f2b6 100644
--- a/src/gpu/effects/GrTextureDomainEffect.h
+++ b/src/gpu/effects/GrTextureDomainEffect.h
@@ -38,7 +38,8 @@
                                const SkMatrix&,
                                const SkRect& domain,
                                WrapMode,
-                               bool bilerp = false);
+                               bool bilerp,
+                               CoordsType = kLocal_CoordsType);
 
     virtual ~GrTextureDomainEffect();
 
@@ -75,7 +76,8 @@
                           const SkMatrix&,
                           const GrRect& domain,
                           WrapMode,
-                          bool bilerp);
+                          bool bilerp,
+                          CoordsType type);
 
     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE;
 
diff --git a/src/gpu/gl/GrGLEffect.cpp b/src/gpu/gl/GrGLEffect.cpp
index 478d03d..e21ab1d 100644
--- a/src/gpu/gl/GrGLEffect.cpp
+++ b/src/gpu/gl/GrGLEffect.cpp
@@ -7,6 +7,7 @@
 
 #include "GrGLSL.h"
 #include "GrGLEffect.h"
+#include "GrDrawEffect.h"
 
 GrGLEffect::GrGLEffect(const GrBackendEffectFactory& factory)
     : fFactory(factory) {
@@ -17,14 +18,15 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrGLEffect::setData(const GrGLUniformManager&, const GrEffectStage&) {
+void GrGLEffect::setData(const GrGLUniformManager&, const GrDrawEffect&) {
 }
 
-GrGLEffect::EffectKey GrGLEffect::GenTextureKey(const GrEffectRef* effect,
+GrGLEffect::EffectKey GrGLEffect::GenTextureKey(const GrDrawEffect& drawEffect,
                                                 const GrGLCaps& caps) {
     EffectKey key = 0;
-    for (int index = 0; index < (*effect)->numTextures(); ++index) {
-        const GrTextureAccess& access = (*effect)->textureAccess(index);
+    int numTextures = (*drawEffect.effect())->numTextures();
+    for (int index = 0; index < numTextures; ++index) {
+        const GrTextureAccess& access = (*drawEffect.effect())->textureAccess(index);
         EffectKey value = GrGLShaderBuilder::KeyForTextureAccess(access, caps) << index;
         GrAssert(0 == (value & key)); // keys for each access ought not to overlap
         key |= value;
@@ -32,12 +34,12 @@
     return key;
 }
 
-GrGLEffect::EffectKey GrGLEffect::GenAttribKey(const GrEffectStage& stage) {
+GrGLEffect::EffectKey GrGLEffect::GenAttribKey(const GrDrawEffect& drawEffect) {
     EffectKey key = 0;
 
-    int numAttributes = stage.getVertexAttribIndexCount();
+    int numAttributes = drawEffect.getVertexAttribIndexCount();
     GrAssert(numAttributes <= 2);
-    const int* attributeIndices = stage.getVertexAttribIndices();
+    const int* attributeIndices = drawEffect.getVertexAttribIndices();
     for (int index = 0; index < numAttributes; ++index) {
         EffectKey value = attributeIndices[index] << 3*index;
         GrAssert(0 == (value & key)); // keys for each attribute ought not to overlap
diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h
index 869fbda..5df2281 100644
--- a/src/gpu/gl/GrGLEffect.h
+++ b/src/gpu/gl/GrGLEffect.h
@@ -12,7 +12,6 @@
 #include "GrGLShaderBuilder.h"
 #include "GrGLShaderVar.h"
 #include "GrGLSL.h"
-#include "GrEffectStage.h"
 
 class GrGLTexture;
 
@@ -21,13 +20,20 @@
     include/gpu/GrEffect.h. Objects of type GrGLEffect are responsible for emitting the
     GLSL code that implements a GrEffect and for uploading uniforms at draw time. They also
     must have a function:
-        static inline EffectKey GenKey(const GrEffectStage&, const GrGLCaps&)
+        static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&)
     that is used to implement a program cache. When two GrEffects produce the same key this means
     that their GrGLEffects would emit the same GLSL code.
 
+    The GrGLEffect subclass must also have a constructor of the form:
+        EffectSubclass::EffectSubclass(const GrBackendEffectFactory&, const GrDrawEffect&)
+    The effect held by the GrDrawEffect is guaranteed to be of the type that generated the
+    GrGLEffect subclass instance.
+
     These objects are created by the factory object returned by the GrEffect::getFactory().
 */
 
+class GrDrawEffect;
+
 class GrGLEffect {
 
 public:
@@ -50,14 +56,10 @@
         stages.
 
         @param builder      Interface used to emit code in the shaders.
-        @param stage        The effect stage that generated this program stage.
+        @param drawEffect   A wrapper on the effect that generated this program stage.
         @param key          The key that was computed by GenKey() from the generating GrEffect.
                             Only the bits indicated by GrBackendEffectFactory::kEffectKeyBits are
                             guaranteed to match the value produced by GenKey();
-        @param vertexCoords A vec2 in the VS that holds the position in local coords. This is either
-                            the pre-view-matrix vertex position or if explicit per-vertex texture
-                            coords are used with a stage then it is those coordinates. See
-                            GrVertexLayout.
         @param outputColor  A predefined vec4 in the FS in which the stage should place its output
                             color (or coverage).
         @param inputColor   A vec4 that holds the input color to the stage in the FS. This may be
@@ -70,9 +72,8 @@
                             reads in the generated code.
         */
     virtual void emitCode(GrGLShaderBuilder* builder,
-                          const GrEffectStage& stage,
+                          const GrDrawEffect& drawEffect,
                           EffectKey key,
-                          const char* vertexCoords,
                           const char* outputColor,
                           const char* inputColor,
                           const TextureSamplerArray& samplers) = 0;
@@ -81,34 +82,15 @@
         key; this function reads data from a stage and uploads any uniform variables required
         by the shaders created in emitCode(). The GrEffect installed in the GrEffectStage is
         guaranteed to be of the same type that created this GrGLEffect and to have an identical
-        EffectKey as the one that created this GrGLEffect. */
-    virtual void setData(const GrGLUniformManager&, const GrEffectStage&);
+        EffectKey as the one that created this GrGLEffect. Effects that use local coords have
+        to consider whether the GrEffectStage's coord change matrix should be used. When explicit
+        local coordinates are used it can be ignored. */
+    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&);
 
     const char* name() const { return fFactory.name(); }
 
-    static EffectKey GenTextureKey(const GrEffectRef*, const GrGLCaps&);
-    static EffectKey GenAttribKey(const GrEffectStage& stage);
-
-   /**
-    * GrGLEffect subclasses get passed a GrEffectStage in their emitCode and setData functions.
-    * The GrGLEffect usually needs to cast the stage's effect to the GrEffect subclass that
-    * generated the GrGLEffect. This helper does just that.
-    */
-    template <typename T>
-    static const T& GetEffectFromStage(const GrEffectStage& effectStage) {
-        GrAssert(NULL != effectStage.getEffect());
-        return CastEffect<T>(*effectStage.getEffect());
-    }
-
-   /**
-    * Extracts the GrEffect from a GrEffectRef and down-casts to a GrEffect subclass. Usually used
-    * in a GrGLEffect subclass's constructor (which takes const GrEffectRef&).
-    */
-    template <typename T>
-    static const T& CastEffect(const GrEffectRef& effectRef) {
-        GrAssert(NULL != effectRef.get());
-        return *static_cast<const T*>(effectRef.get());
-    }
+    static EffectKey GenTextureKey(const GrDrawEffect&, const GrGLCaps&);
+    static EffectKey GenAttribKey(const GrDrawEffect& stage);
 
 protected:
     const GrBackendEffectFactory& fFactory;
diff --git a/src/gpu/gl/GrGLEffectMatrix.cpp b/src/gpu/gl/GrGLEffectMatrix.cpp
index c37098e..e2e8807 100644
--- a/src/gpu/gl/GrGLEffectMatrix.cpp
+++ b/src/gpu/gl/GrGLEffectMatrix.cpp
@@ -6,58 +6,67 @@
  */
 
 #include "GrGLEffectMatrix.h"
+#include "GrDrawEffect.h"
 #include "GrTexture.h"
 
 GrGLEffect::EffectKey GrGLEffectMatrix::GenKey(const SkMatrix& effectMatrix,
-                                               const SkMatrix& coordChangeMatrix,
+                                               const GrDrawEffect& drawEffect,
+                                               CoordsType coordsType,
                                                const GrTexture* texture) {
+    EffectKey key = 0;
     SkMatrix::TypeMask type0 = effectMatrix.getType();
-    SkMatrix::TypeMask type1 = coordChangeMatrix.getType();
+    SkMatrix::TypeMask type1;
+    if (GrEffect::kLocal_CoordsType == coordsType) {
+        type1 = drawEffect.getCoordChangeMatrix().getType();
+    } else {
+        if (drawEffect.programHasExplicitLocalCoords()) {
+            // We only make the key indicate that device coords are referenced when the local coords
+            // are not actually determined by positions.
+            key |= kPositionCoords_Flag;
+        }
+        type1 = SkMatrix::kIdentity_Mask;
+    }
 
-    static const int kNonTransMask = SkMatrix::kAffine_Mask |
-                                     SkMatrix::kScale_Mask  |
-                                     SkMatrix::kPerspective_Mask;
     int combinedTypes = type0 | type1;
 
     bool reverseY = (NULL != texture) && kBottomLeft_GrSurfaceOrigin == texture->origin();
 
     if (SkMatrix::kPerspective_Mask & combinedTypes) {
-        return kGeneral_Key;
-    } else if ((kNonTransMask & combinedTypes) || reverseY) {
-        return kNoPersp_Key;
-    } else if (kTrans_Key & combinedTypes) {
-        return kTrans_Key;
+        key |= kGeneral_MatrixType;
+    } else if (((SkMatrix::kAffine_Mask | SkMatrix::kScale_Mask) & combinedTypes) || reverseY) {
+        key |= kNoPersp_MatrixType;
+    } else if (SkMatrix::kTranslate_Mask & combinedTypes) {
+        key |= kTrans_MatrixType;
     } else {
-        GrAssert(effectMatrix.isIdentity() && coordChangeMatrix.isIdentity());
-        return kIdentity_Key;
+        key |= kIdentity_MatrixType;
     }
+    return key;
 }
 
 GrSLType GrGLEffectMatrix::emitCode(GrGLShaderBuilder* builder,
                                     EffectKey key,
-                                    const char* vertexCoords,
                                     const char** fsCoordName,
                                     const char** vsCoordName,
                                     const char* suffix) {
     GrSLType varyingType;
     const char* uniName;
     key &= kKeyMask;
-    switch (key) {
-        case kIdentity_Key:
+    switch (key & kMatrixTypeKeyMask) {
+        case kIdentity_MatrixType:
             fUniType = kVoid_GrSLType;
             varyingType = kVec2f_GrSLType;
             break;
-        case kTrans_Key:
+        case kTrans_MatrixType:
             fUniType = kVec2f_GrSLType;
             uniName = "StageTranslate";
             varyingType = kVec2f_GrSLType;
             break;
-        case kNoPersp_Key:
+        case kNoPersp_MatrixType:
             fUniType = kMat33f_GrSLType;
             uniName = "StageMatrix";
             varyingType = kVec2f_GrSLType;
             break;
-        case kGeneral_Key:
+        case kGeneral_MatrixType:
             fUniType = kMat33f_GrSLType;
             uniName = "StageMatrix";
             varyingType = kVec3f_GrSLType;
@@ -89,24 +98,39 @@
     const char* fsVaryingName;
     builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
 
-    // varying = matrix * vertex-coords (logically)
+    const GrGLShaderVar* coords;
+    switch (fCoordsType) {
+        case GrEffect::kLocal_CoordsType:
+            GrAssert(!(kPositionCoords_Flag & key));
+            coords = &builder->localCoordsAttribute();
+            break;
+        case GrEffect::kPosition_CoordsType:
+            GrAssert((kPositionCoords_Flag & key) || !builder->hasExplicitLocalCoords());
+            coords = &builder->positionAttribute();
+            break;
+        default:
+            coords = NULL; // prevents warning
+            GrCrash("Unexpected coords type.");
+    }
+    // varying = matrix * coords (logically)
     switch (fUniType) {
         case kVoid_GrSLType:
             GrAssert(kVec2f_GrSLType == varyingType);
-            builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, vertexCoords);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, coords->c_str());
             break;
         case kVec2f_GrSLType:
             GrAssert(kVec2f_GrSLType == varyingType);
-            builder->vsCodeAppendf("\t%s = %s + %s;\n", vsVaryingName, uniName, vertexCoords);
+            builder->vsCodeAppendf("\t%s = %s + %s;\n",
+                                   vsVaryingName, uniName, coords->c_str());
             break;
         case kMat33f_GrSLType: {
             GrAssert(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
             if (kVec2f_GrSLType == varyingType) {
                 builder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
-                                       vsVaryingName, uniName, vertexCoords);
+                                       vsVaryingName, uniName, coords->c_str());
             } else {
                 builder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n",
-                                       vsVaryingName, uniName, vertexCoords);
+                                       vsVaryingName, uniName, coords->c_str());
             }
             break;
         }
@@ -128,7 +152,6 @@
     */
 void GrGLEffectMatrix::emitCodeMakeFSCoords2D(GrGLShaderBuilder* builder,
                                               EffectKey key,
-                                              const char* vertexCoords,
                                               const char** fsCoordName,
                                               const char** vsVaryingName,
                                               GrSLType* vsVaryingType,
@@ -137,7 +160,6 @@
 
     GrSLType varyingType = this->emitCode(builder,
                                           key,
-                                          vertexCoords,
                                           &fsVaryingName,
                                           vsVaryingName,
                                           suffix);
@@ -164,11 +186,14 @@
 }
 
 void GrGLEffectMatrix::setData(const GrGLUniformManager& uniformManager,
-                              const SkMatrix& matrix,
-                              const SkMatrix& coordChangeMatrix,
-                              const GrTexture* texture) {
+                               const SkMatrix& matrix,
+                               const GrDrawEffect& drawEffect,
+                               const GrTexture* texture) {
     GrAssert((GrGLUniformManager::kInvalidUniformHandle == fUni) ==
-                (kVoid_GrSLType == fUniType));
+             (kVoid_GrSLType == fUniType));
+    const SkMatrix& coordChangeMatrix = GrEffect::kLocal_CoordsType == fCoordsType ?
+                                            drawEffect.getCoordChangeMatrix() :
+                                            SkMatrix::I();
     switch (fUniType) {
         case kVoid_GrSLType:
             GrAssert(matrix.isIdentity());
@@ -178,8 +203,8 @@
         case kVec2f_GrSLType: {
             GrAssert(SkMatrix::kTranslate_Mask == (matrix.getType() | coordChangeMatrix.getType()));
             GrAssert(NULL == texture || kTopLeft_GrSurfaceOrigin == texture->origin());
-            SkScalar tx = matrix[SkMatrix::kMTransX] + coordChangeMatrix[SkMatrix::kMTransX];
-            SkScalar ty = matrix[SkMatrix::kMTransY] + coordChangeMatrix[SkMatrix::kMTransY];
+            SkScalar tx = matrix[SkMatrix::kMTransX] + (coordChangeMatrix)[SkMatrix::kMTransX];
+            SkScalar ty = matrix[SkMatrix::kMTransY] + (coordChangeMatrix)[SkMatrix::kMTransY];
             if (fPrevMatrix.get(SkMatrix::kMTransX) != tx ||
                 fPrevMatrix.get(SkMatrix::kMTransY) != ty) {
                 uniformManager.set2f(fUni, tx, ty);
diff --git a/src/gpu/gl/GrGLEffectMatrix.h b/src/gpu/gl/GrGLEffectMatrix.h
index 1a11656..fc4b783 100644
--- a/src/gpu/gl/GrGLEffectMatrix.h
+++ b/src/gpu/gl/GrGLEffectMatrix.h
@@ -14,34 +14,68 @@
 class GrTexture;
 
 /**
- * This is a helper to implement a texture matrix in a GrGLEffect.
+ * This is a helper to implement a matrix in a GrGLEffect that operates on incoming coords in the
+ * vertex shader and writes them to an attribute to be used in the fragment shader. When the input
+ * coords in the vertex shader are local coordinates this class accounts for the coord change matrix
+ * communicated via GrDrawEffect. The input coords may also be positions and in this case the coord
+ * change matrix is ignored. The GrGLEffectMatrix will emit different code based on the type of
+ * matrix and thus must contribute to the effect's key.
+ *
+ * This class cannot be used to apply a matrix to coordinates that come in the form of custom vertex
+ * attributes.
  */
 class GrGLEffectMatrix {
+private:
+    // We specialize the generated code for each of these matrix types.
+    enum MatrixTypes {
+        kIdentity_MatrixType    = 0,
+        kTrans_MatrixType       = 1,
+        kNoPersp_MatrixType     = 2,
+        kGeneral_MatrixType     = 3,
+    };
+    // The key for is made up of a matrix type and a bit that indicates the source of the input
+    // coords.
+    enum {
+        kMatrixTypeKeyBits      = 2,
+        kMatrixTypeKeyMask      = (1 << kMatrixTypeKeyBits) - 1,
+        kPositionCoords_Flag    = (1 << kMatrixTypeKeyBits),
+        kKeyBitsPrivate         = kMatrixTypeKeyBits + 1,
+    };
+
 public:
+
+    typedef GrEffect::CoordsType CoordsType;
+
     typedef GrGLEffect::EffectKey EffectKey;
+
     /**
      * The matrix uses kKeyBits of the effect's EffectKey. A GrGLEffect may place these bits at an
      * arbitrary shift in its final key. However, when GrGLEffectMatrix::emitCode*() code is called
      * the relevant bits must be in the lower kKeyBits of the key parameter.
      */
     enum {
-        kKeyBits = 2,
+        kKeyBits = kKeyBitsPrivate,
         kKeyMask = (1 << kKeyBits) - 1,
     };
 
-    GrGLEffectMatrix() : fUni(GrGLUniformManager::kInvalidUniformHandle) {
+    GrGLEffectMatrix(CoordsType coordsType)
+        : fUni(GrGLUniformManager::kInvalidUniformHandle)
+        , fCoordsType(coordsType) {
+        GrAssert(GrEffect::kLocal_CoordsType == coordsType ||
+                 GrEffect::kPosition_CoordsType == coordsType);
         fPrevMatrix = SkMatrix::InvalidMatrix();
     }
 
     /**
      * Generates the key for the portion of the code emitted by this class's emitCode() function.
      * Pass a texture to make GrGLEffectMatrix automatically adjust for the texture's origin. Pass
-     * NULL when not using the EffectMatrix for a texture lookups, or if the GrGLEffect subclass
-     * wants to handle origin adjustments in some other manner. coordChangeMatrix is the matrix
-     * from GrEffectStage.
+     * NULL when not using the EffectMatrix for a texture lookup, or if the GrGLEffect subclass
+     * wants to handle origin adjustments in some other manner. The coords type param must match the
+     * param that would be used to initialize GrGLEffectMatrix for the generating GrEffect.
      */
     static EffectKey GenKey(const SkMatrix& effectMatrix,
-                            const SkMatrix& coordChangeMatrix,
+                            const GrDrawEffect&,
+                            CoordsType,
                             const GrTexture*);
 
     /**
@@ -55,7 +89,6 @@
      */
     GrSLType emitCode(GrGLShaderBuilder*,
                       EffectKey,
-                      const char* vertexCoords,
                       const char** fsCoordName, /* optional */
                       const char** vsCoordName = NULL,
                       const char* suffix = NULL);
@@ -66,31 +99,23 @@
      */
     void emitCodeMakeFSCoords2D(GrGLShaderBuilder*,
                                 EffectKey,
-                                const char* vertexCoords,
                                 const char** fsCoordName, /* optional */
                                 const char** vsVaryingName = NULL,
                                 GrSLType* vsVaryingType = NULL,
                                 const char* suffix = NULL);
     /**
-     * Call from a GrGLEffect's subclass to update the texture matrix. The matrix,
-     * coordChangeMatrix, and texture params should match those used with GenKey.
+     * Call from a GrGLEffect's subclass to update the texture matrix. The effectMatrix and texture
+     * params should match those used with GenKey.
      */
     void setData(const GrGLUniformManager& uniformManager,
                  const SkMatrix& effectMatrix,
-                 const SkMatrix& coordChangeMatrix,
+                 const GrDrawEffect& drawEffect,
                  const GrTexture*);
 
-private:
-    enum {
-        kIdentity_Key   = 0,
-        kTrans_Key      = 1,
-        kNoPersp_Key    = 2,
-        kGeneral_Key    = 3,
-    };
-
     GrGLUniformManager::UniformHandle fUni;
     GrSLType                          fUniType;
     SkMatrix                          fPrevMatrix;
+    CoordsType                        fCoordsType;
 };
 
 #endif
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 7d6420e..21729cd 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -9,6 +9,7 @@
 
 #include "GrAllocator.h"
 #include "GrEffect.h"
+#include "GrDrawEffect.h"
 #include "GrGLEffect.h"
 #include "GrGpuGL.h"
 #include "GrGLShaderVar.h"
@@ -26,7 +27,6 @@
 SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false,
                 "Print the source code for all shaders generated.");
 
-#define TEX_ATTR_NAME "aTexCoord"
 #define COL_ATTR_NAME "aColor"
 #define COV_ATTR_NAME "aCoverage"
 #define EDGE_ATTR_NAME "aEdge"
@@ -134,7 +134,10 @@
             lastEnabledStage = s;
             const GrEffectRef& effect = *drawState.getStage(s).getEffect();
             const GrBackendEffectFactory& factory = effect->getFactory();
-            desc->fEffectKeys[s] = factory.glEffectKey(drawState.getStage(s), gpu->glCaps());
+            bool explicitLocalCoords = (drawState.getAttribBindings() &
+                                        GrDrawState::kLocalCoords_AttribBindingsBit);
+            GrDrawEffect drawEffect(drawState.getStage(s), explicitLocalCoords);
+            desc->fEffectKeys[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
         } else {
             desc->fEffectKeys[s] = 0;
         }
@@ -207,8 +210,8 @@
     if (desc->fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
         desc->fEdgeAttributeIndex = drawState.getAttribIndex(GrDrawState::kEdge_AttribIndex);
     }
-    if (GrDrawState::AttributesBindExplicitTexCoords(desc->fAttribBindings)) {
-        desc->fTexCoordAttributeIndex = drawState.getAttribIndex(GrDrawState::kTexCoord_AttribIndex);
+    if (desc->fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
+        desc->fLocalCoordsAttributeIndex = drawState.getAttribIndex(GrDrawState::kLocalCoords_AttribIndex);
     }
 
 #if GR_DEBUG
@@ -227,10 +230,10 @@
     if (desc->fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
         GrAssert(desc->fEdgeAttributeIndex < GrDrawState::kVertexAttribCnt);
         GrAssert(kAttribLayouts[vertexAttribs[desc->fEdgeAttributeIndex].fType].fCount == 4);
-     }
-    if (GrDrawState::AttributesBindExplicitTexCoords(desc->fAttribBindings)) {
-        GrAssert(desc->fTexCoordAttributeIndex < GrDrawState::kVertexAttribCnt);
-        GrAssert(kAttribLayouts[vertexAttribs[desc->fTexCoordAttributeIndex].fType].fCount == 2);
+    }
+    if (desc->fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
+        GrAssert(desc->fLocalCoordsAttributeIndex < GrDrawState::kVertexAttribCnt);
+        GrAssert(kAttribLayouts[vertexAttribs[desc->fLocalCoordsAttributeIndex].fType].fCount == 2);
     }
 #endif
 }
@@ -679,8 +682,10 @@
 bool GrGLProgram::genProgram(const GrEffectStage* stages[]) {
     GrAssert(0 == fProgramID);
 
-    GrGLShaderBuilder builder(fContext.info(), fUniformManager);
     const GrAttribBindings& attribBindings = fDesc.fAttribBindings;
+    bool hasExplicitLocalCoords =
+        SkToBool(attribBindings & GrDrawState::kLocalCoords_AttribBindingsBit);
+    GrGLShaderBuilder builder(fContext.info(), fUniformManager, hasExplicitLocalCoords);
 
 #if GR_GL_EXPERIMENTAL_GS
     builder.fUsesGS = fDesc.fExperimentalGS;
@@ -760,11 +765,6 @@
         builder.vsCodeAppend("\tgl_PointSize = 1.0;\n");
     }
 
-    // add texture coordinates that are used to the list of vertex attr decls
-    if (GrDrawState::AttributesBindExplicitTexCoords(attribBindings)) {
-        builder.addAttribute(kVec2f_GrSLType, TEX_ATTR_NAME);
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // compute the final color
 
@@ -779,21 +779,11 @@
                 outColor.appendS32(s);
                 builder.fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
 
-                const char* inCoords;
-                // figure out what our input coords are
-                if (!GrDrawState::StageBindsExplicitTexCoords(attribBindings, s)) {
-                    inCoords = builder.positionAttribute().c_str();
-                } else {
-                    // must have input tex coordinates if stage is enabled.
-                    inCoords = TEX_ATTR_NAME;
-                }
-
                 builder.setCurrentStage(s);
                 fEffects[s] = builder.createAndEmitGLEffect(*stages[s],
                                                             fDesc.fEffectKeys[s],
                                                             inColor.size() ? inColor.c_str() : NULL,
                                                             outColor.c_str(),
-                                                            inCoords,
                                                             &fUniformHandles.fSamplerUnis[s]);
                 builder.setNonStage();
                 inColor = outColor;
@@ -871,16 +861,6 @@
                     outCoverage.appendS32(s);
                     builder.fsCodeAppendf("\tvec4 %s;\n", outCoverage.c_str());
 
-                    const char* inCoords;
-                    // figure out what our input coords are
-                    if (!GrDrawState::StageBindsExplicitTexCoords(attribBindings, s)) {
-                        inCoords = builder.positionAttribute().c_str();
-                    } else {
-                        // must have input tex coordinates if stage is
-                        // enabled.
-                        inCoords = TEX_ATTR_NAME;
-                    }
-
                     // stages don't know how to deal with a scalar input. (Maybe they should. We
                     // could pass a GrGLShaderVar)
                     if (inCoverageIsScalar) {
@@ -894,7 +874,6 @@
                                                     fDesc.fEffectKeys[s],
                                                     inCoverage.size() ? inCoverage.c_str() : NULL,
                                                     outCoverage.c_str(),
-                                                    inCoords,
                                                     &fUniformHandles.fSamplerUnis[s]);
                     builder.setNonStage();
                     inCoverage = outCoverage;
@@ -1008,8 +987,10 @@
     if (fDesc.fAttribBindings & GrDrawState::kEdge_AttribBindingsBit) {
         GL_CALL(BindAttribLocation(fProgramID, fDesc.fEdgeAttributeIndex, EDGE_ATTR_NAME));
     }
-    if (GrDrawState::AttributesBindExplicitTexCoords(fDesc.fAttribBindings)) {
-        GL_CALL(BindAttribLocation(fProgramID, fDesc.fTexCoordAttributeIndex, TEX_ATTR_NAME));
+    if (fDesc.fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
+        GL_CALL(BindAttribLocation(fProgramID,
+                                   fDesc.fLocalCoordsAttributeIndex,
+                                   builder.localCoordsAttribute().c_str()));
     }
 
     const GrGLShaderBuilder::AttributePair* attribEnd = builder.getEffectAttributes().end();
@@ -1088,7 +1069,11 @@
         if (NULL != fEffects[s]) {
             const GrEffectStage& stage = drawState.getStage(s);
             GrAssert(NULL != stage.getEffect());
-            fEffects[s]->setData(fUniformManager, stage);
+
+            bool explicitLocalCoords =
+                (fDesc.fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit);
+            GrDrawEffect drawEffect(stage, explicitLocalCoords);
+            fEffects[s]->setData(fUniformManager, drawEffect);
             int numSamplers = fUniformHandles.fSamplerUnis[s].count();
             for (int u = 0; u < numSamplers; ++u) {
                 UniformHandle handle = fUniformHandles.fSamplerUnis[s][u];
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index cde918b..9fd01fd 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -192,7 +192,7 @@
         int8_t                      fColorAttributeIndex;
         int8_t                      fCoverageAttributeIndex;
         int8_t                      fEdgeAttributeIndex;
-        int8_t                      fTexCoordAttributeIndex;
+        int8_t                      fLocalCoordsAttributeIndex;
 
         friend class GrGLProgram;
     };
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index b3b09cc..1179626 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -8,6 +8,7 @@
 #include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLProgram.h"
 #include "gl/GrGLUniformHandle.h"
+#include "GrDrawEffect.h"
 #include "GrTexture.h"
 
 // number of each input/output type in a single allocation block
@@ -82,7 +83,8 @@
 //const int GrGLShaderBuilder::fCoordDims = 2;
 
 GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctxInfo,
-                                     GrGLUniformManager& uniformManager)
+                                     GrGLUniformManager& uniformManager,
+                                     bool explicitLocalCoords)
     : fUniforms(kVarsPerBlock)
     , fVSAttrs(kVarsPerBlock)
     , fVSOutputs(kVarsPerBlock)
@@ -99,6 +101,14 @@
 
     fPositionVar = &fVSAttrs.push_back();
     fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
+    if (explicitLocalCoords) {
+        fLocalCoordsVar = &fVSAttrs.push_back();
+        fLocalCoordsVar->set(kVec2f_GrSLType,
+                             GrGLShaderVar::kAttribute_TypeModifier,
+                             "aLocalCoords");
+    } else {
+        fLocalCoordsVar = fPositionVar;
+    }
 }
 
 void GrGLShaderBuilder::codeAppendf(ShaderType type, const char format[], va_list args) {
@@ -494,7 +504,6 @@
                                 GrGLEffect::EffectKey key,
                                 const char* fsInColor,
                                 const char* fsOutColor,
-                                const char* vsInCoord,
                                 SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles) {
     GrAssert(NULL != stage.getEffect());
 
@@ -506,6 +515,7 @@
         textureSamplers[i].init(this, &effect->textureAccess(i), i);
         samplerHandles->push_back(textureSamplers[i].fSamplerUniform);
     }
+    GrDrawEffect drawEffect(stage, this->hasExplicitLocalCoords());
 
     int numAttributes = stage.getVertexAttribIndexCount();
     const int* attributeIndices = stage.getVertexAttribIndices();
@@ -519,15 +529,15 @@
         }
     }
 
-    GrGLEffect* glEffect = effect->getFactory().createGLInstance(effect);
+    GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
 
     // Enclose custom code in a block to avoid namespace conflicts
     this->fVSCode.appendf("\t{ // %s\n", glEffect->name());
     this->fFSCode.appendf("\t{ // %s \n", glEffect->name());
+
     glEffect->emitCode(this,
-                       stage,
+                       drawEffect,
                        key,
-                       vsInCoord,
                        fsOutColor,
                        fsInColor,
                        textureSamplers);
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 524a885..9d64143 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -17,6 +17,7 @@
 #include <stdarg.h>
 
 class GrGLContextInfo;
+class GrEffectStage;
 
 /**
   Contains all the incremental state of a shader as it is being built,as well as helpers to
@@ -80,7 +81,7 @@
         kFragment_ShaderType = 0x4,
     };
 
-    GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&);
+    GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&, bool explicitLocalCoords);
 
     /**
      * Called by GrGLEffects to add code to one of the shaders.
@@ -205,6 +206,16 @@
       */
     const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
 
+    /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
+        as positionAttribute() or it may not be. It depends upon whether the rendering code
+        specified explicit local coords or not in the GrDrawState. */
+    const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
+
+    /**
+     * Are explicit local coordinates provided as input to the vertex shader.
+     */
+    bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
+
     /**
      * Interfaces used by GrGLProgram.
      * TODO: Hide these from the GrEffects using friend or splitting this into two related classes.
@@ -223,7 +234,6 @@
                                 GrBackendEffectFactory::EffectKey key,
                                 const char* fsInColor, // NULL means no incoming color
                                 const char* fsOutColor,
-                                const char* vsInCoord,
                                 SkTArray<GrGLUniformManager::UniformHandle, true>* samplerHandles);
     GrGLUniformManager::UniformHandle getRTHeightUniform() const { return fRTHeightUniform; }
 
@@ -290,6 +300,8 @@
     SkSTArray<10, AttributePair, true>  fEffectAttributes;
 
     GrGLShaderVar*                      fPositionVar;
+    GrGLShaderVar*                      fLocalCoordsVar;
+
 };
 
 #endif
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index d12aeb5..aeb7ecc 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -15,6 +15,7 @@
 #include "gl/GrGpuGL.h"
 #include "GrBackendEffectFactory.h"
 #include "GrContextFactory.h"
+#include "GrDrawEffect.h"
 #include "effects/GrConfigConversionEffect.h"
 
 #include "SkRandom.h"
@@ -57,16 +58,18 @@
         fDualSrcOutput = kNone_DualSrcOutput;
     }
 
-    bool useOnce = false;
+    // use separate tex coords?
+    if (random->nextBool()) {
+        fAttribBindings |= GrDrawState::kLocalCoords_AttribBindingsBit;
+    }
+
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
         if (NULL != stages[s].getEffect()) {
             const GrBackendEffectFactory& factory = (*stages[s].getEffect())->getFactory();
-            fEffectKeys[s] = factory.glEffectKey(stages[s], gpu->glCaps());
-            // use separate tex coords?
-            if (!useOnce && random->nextBool()) {
-                fAttribBindings |= GrDrawState::ExplicitTexCoordAttribBindingsBit(s);
-                useOnce = true;
-            }
+            bool explicitLocalCoords = (fAttribBindings &
+                                        GrDrawState::kLocalCoords_AttribBindingsBit);
+            GrDrawEffect drawEffect(stages[s], explicitLocalCoords);
+            fEffectKeys[s] = factory.glEffectKey(drawEffect, gpu->glCaps());
         }
     }
 
@@ -85,8 +88,8 @@
         fEdgeAttributeIndex = attributeIndex;
         ++attributeIndex;
     }
-    if (GrDrawState::AttributesBindExplicitTexCoords(fAttribBindings)) {
-        fTexCoordAttributeIndex = attributeIndex;
+    if (fAttribBindings & GrDrawState::kLocalCoords_AttribBindingsBit) {
+        fLocalCoordsAttributeIndex = attributeIndex;
         ++attributeIndex;
     }
 }