BUG=skia:
R=bsalomon@google.com, egdaniel@google.com, jvanverth@google.com, robertphillips@google.com

Author: joshualitt@chromium.org

Review URL: https://codereview.chromium.org/543623004
diff --git a/gm/beziereffects.cpp b/gm/beziereffects.cpp
index f2e09b0..924f2a5 100644
--- a/gm/beziereffects.cpp
+++ b/gm/beziereffects.cpp
@@ -170,7 +170,7 @@
                     GrDrawState* drawState = tt.target()->drawState();
                     drawState->setVertexAttribs<kAttribs>(2, sizeof(Vertex));
 
-                    drawState->setGeometryProcessor(effect, 1);
+                    drawState->setGeometryProcessor(effect);
                     drawState->setRenderTarget(rt);
                     drawState->setColor(0xff000000);
 
@@ -325,7 +325,7 @@
                     GrDrawState* drawState = tt.target()->drawState();
                     drawState->setVertexAttribs<kAttribs>(2, sizeof(Vertex));
 
-                    drawState->setGeometryProcessor(effect, 1);
+                    drawState->setGeometryProcessor(effect);
                     drawState->setRenderTarget(rt);
                     drawState->setColor(0xff000000);
 
@@ -509,7 +509,7 @@
                     GrDrawState* drawState = tt.target()->drawState();
                     drawState->setVertexAttribs<kAttribs>(2, sizeof(Vertex));
 
-                    drawState->setGeometryProcessor(effect, 1);
+                    drawState->setGeometryProcessor(effect);
                     drawState->setRenderTarget(rt);
                     drawState->setColor(0xff000000);
 
diff --git a/gm/convexpolyeffect.cpp b/gm/convexpolyeffect.cpp
index 8d73da5..0938e58 100644
--- a/gm/convexpolyeffect.cpp
+++ b/gm/convexpolyeffect.cpp
@@ -127,7 +127,6 @@
                     return;
                 }
                 GrDrawState* drawState = tt.target()->drawState();
-                drawState->setVertexAttribs<kAttribs>(SK_ARRAY_COUNT(kAttribs), sizeof(SkPoint));
 
                 SkMatrix m;
                 SkPath p;
@@ -139,7 +138,7 @@
                 if (!effect) {
                     continue;
                 }
-                drawState->addCoverageEffect(effect, 1);
+                drawState->addCoverageEffect(effect);
                 drawState->setIdentityViewMatrix();
                 drawState->setRenderTarget(rt);
                 drawState->setColor(0xff000000);
@@ -193,8 +192,7 @@
                 }
 
                 GrDrawState* drawState = tt.target()->drawState();
-                drawState->setVertexAttribs<kAttribs>(SK_ARRAY_COUNT(kAttribs), sizeof(SkPoint));
-                drawState->addCoverageEffect(effect, 1);
+                drawState->addCoverageEffect(effect);
                 drawState->setIdentityViewMatrix();
                 drawState->setRenderTarget(rt);
                 drawState->setColor(0xff000000);
diff --git a/gm/texturedomaineffect.cpp b/gm/texturedomaineffect.cpp
index 6cc9799..b310253 100644
--- a/gm/texturedomaineffect.cpp
+++ b/gm/texturedomaineffect.cpp
@@ -136,7 +136,7 @@
                     drawState->reset(viewMatrix);
                     drawState->setRenderTarget(rt);
                     drawState->setColor(0xffffffff);
-                    drawState->addColorEffect(effect, 1);
+                    drawState->addColorEffect(effect);
 
                     tt.target()->drawSimpleRect(renderRect);
                     x += renderRect.width() + kTestPad;
diff --git a/gm/yuvtorgbeffect.cpp b/gm/yuvtorgbeffect.cpp
index acb6f22..d0b511f 100644
--- a/gm/yuvtorgbeffect.cpp
+++ b/gm/yuvtorgbeffect.cpp
@@ -118,7 +118,7 @@
                   drawState->reset(viewMatrix);
                   drawState->setRenderTarget(rt);
                   drawState->setColor(0xffffffff);
-                  drawState->addColorEffect(effect, 1);
+                  drawState->addColorEffect(effect);
                   tt.target()->drawSimpleRect(renderRect);
               }
               x += renderRect.width() + kTestPad;
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index eb02ce6..693d1f3 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -31,6 +31,7 @@
       '<(skia_include_path)/gpu/GrRenderTarget.h',
       '<(skia_include_path)/gpu/GrResourceKey.h',
       '<(skia_include_path)/gpu/GrSurface.h',
+      '<(skia_include_path)/gpu/GrShaderVar.h',
       '<(skia_include_path)/gpu/GrTBackendEffectFactory.h',
       '<(skia_include_path)/gpu/GrTexture.h',
       '<(skia_include_path)/gpu/GrTextureAccess.h',
@@ -207,7 +208,7 @@
       '<(skia_src_path)/gpu/gl/GrGLDefaultInterface_none.cpp',
       '<(skia_src_path)/gpu/gl/GrGLDefines.h',
       '<(skia_src_path)/gpu/gl/GrGLEffect.h',
-      '<(skia_src_path)/gpu/gl/GrGLVertexEffect.h',
+      '<(skia_src_path)/gpu/gl/GrGLGeometryProcessor.h',
       '<(skia_src_path)/gpu/gl/GrGLExtensions.cpp',
       '<(skia_src_path)/gpu/gl/GrGLIndexBuffer.cpp',
       '<(skia_src_path)/gpu/gl/GrGLIndexBuffer.h',
diff --git a/include/gpu/GrDrawEffect.h b/include/gpu/GrDrawEffect.h
index 2bf17d8..710b000 100644
--- a/include/gpu/GrDrawEffect.h
+++ b/include/gpu/GrDrawEffect.h
@@ -39,9 +39,6 @@
 
     bool programHasExplicitLocalCoords() const { return fExplicitLocalCoords; }
 
-    const int* getVertexAttribIndices() const { return fEffectStage->getVertexAttribIndices(); }
-    int getVertexAttribIndexCount() const { return fEffectStage->getVertexAttribIndexCount(); }
-
 private:
     const GrEffectStage*    fEffectStage;
     bool                    fExplicitLocalCoords;
diff --git a/include/gpu/GrEffect.h b/include/gpu/GrEffect.h
index b7a6d17..102b9d4 100644
--- a/include/gpu/GrEffect.h
+++ b/include/gpu/GrEffect.h
@@ -11,14 +11,15 @@
 #include "GrColor.h"
 #include "GrEffectUnitTest.h"
 #include "GrProgramElement.h"
+#include "GrShaderVar.h"
 #include "GrTextureAccess.h"
 #include "GrTypesPriv.h"
+#include "SkString.h"
 
 class GrBackendEffectFactory;
 class GrContext;
 class GrCoordTransform;
 
-
 /** Provides custom vertex shader, fragment shader, uniform data for a particular stage of the
     Ganesh shading pipeline.
     Subclasses must have a function that produces a human-readable name:
@@ -114,14 +115,10 @@
         (To set this value the effect must inherit from GrEffect.) */
     bool requiresVertexShader() const { return fRequiresVertexShader; }
 
-    int numVertexAttribs() const {
-        SkASSERT(0 == fVertexAttribTypes.count() || fRequiresVertexShader);
-        return fVertexAttribTypes.count();
-    }
-
-    GrSLType vertexAttribType(int index) const { return fVertexAttribTypes[index]; }
-
     static const int kMaxVertexAttribs = 2;
+    typedef SkSTArray<kMaxVertexAttribs, GrShaderVar, true> VertexAttribArray;
+
+    const VertexAttribArray& getVertexAttribs() const { return fVertexAttribs; }
 
     void* operator new(size_t size);
     void operator delete(void* target);
@@ -193,11 +190,11 @@
         getFactory()).*/
     virtual bool onIsEqual(const GrEffect& other) const = 0;
 
-    friend class GrVertexEffect; // to set fRequiresVertexShader and build fVertexAttribTypes.
+    friend class GrGeometryProcessor; // to set fRequiresVertexShader and build fVertexAttribTypes.
 
     SkSTArray<4, const GrCoordTransform*, true>  fCoordTransforms;
     SkSTArray<4, const GrTextureAccess*, true>   fTextureAccesses;
-    SkSTArray<kMaxVertexAttribs, GrSLType, true> fVertexAttribTypes;
+    VertexAttribArray                            fVertexAttribs;
     bool                                         fWillReadDstColor;
     bool                                         fWillReadFragmentPosition;
     bool                                         fWillUseInputColor;
diff --git a/include/gpu/GrEffectStage.h b/include/gpu/GrEffectStage.h
index 4499790..6df7f90 100644
--- a/include/gpu/GrEffectStage.h
+++ b/include/gpu/GrEffectStage.h
@@ -24,11 +24,9 @@
 // when draws are enqueued in the GrInOrderDrawBuffer.
 class GrEffectStage {
 public:
-    explicit GrEffectStage(const GrEffect* effect, int attrIndex0 = -1, int attrIndex1 = -1)
+    explicit GrEffectStage(const GrEffect* effect)
     : fEffect(SkRef(effect)) {
         fCoordChangeMatrixSet = false;
-        fVertexAttribIndices[0] = attrIndex0;
-        fVertexAttribIndices[1] = attrIndex1;
     }
 
     GrEffectStage(const GrEffectStage& other) {
@@ -37,7 +35,6 @@
             fCoordChangeMatrix = other.fCoordChangeMatrix;
         }
         fEffect.initAndRef(other.fEffect);
-        memcpy(fVertexAttribIndices, other.fVertexAttribIndices, sizeof(fVertexAttribIndices));
     }
     
     static bool AreCompatible(const GrEffectStage& a, const GrEffectStage& b,
@@ -133,16 +130,12 @@
 
     const GrEffect* getEffect() const { return fEffect.get(); }
 
-    const int* getVertexAttribIndices() const { return fVertexAttribIndices; }
-    int getVertexAttribIndexCount() const { return fEffect->numVertexAttribs(); }
-
     void convertToPendingExec() { fEffect.convertToPendingExec(); }
 
 private:
     bool                                fCoordChangeMatrixSet;
     SkMatrix                            fCoordChangeMatrix;
     GrProgramElementRef<const GrEffect> fEffect;
-    int                                 fVertexAttribIndices[2];
 };
 
 #endif
diff --git a/include/gpu/GrPaint.h b/include/gpu/GrPaint.h
index 900ab4c..07b526f 100644
--- a/include/gpu/GrPaint.h
+++ b/include/gpu/GrPaint.h
@@ -87,24 +87,26 @@
     /**
      * Appends an additional color effect to the color computation.
      */
-    const GrEffect* addColorEffect(const GrEffect* effect, int attr0 = -1, int attr1 = -1) {
+    const GrEffect* addColorEffect(const GrEffect* effect) {
         SkASSERT(effect);
+        SkASSERT(!effect->requiresVertexShader());
         if (!effect->willUseInputColor()) {
             fColorStages.reset();
         }
-        SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect, attr0, attr1));
+        SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect));
         return effect;
     }
 
     /**
      * Appends an additional coverage effect to the coverage computation.
      */
-    const GrEffect* addCoverageEffect(const GrEffect* effect, int attr0 = -1, int attr1 = -1) {
+    const GrEffect* addCoverageEffect(const GrEffect* effect) {
         SkASSERT(effect);
+        SkASSERT(!effect->requiresVertexShader());
         if (!effect->willUseInputColor()) {
             fCoverageStages.reset();
         }
-        SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect, attr0, attr1));
+        SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect));
         return effect;
     }
 
diff --git a/include/gpu/GrShaderVar.h b/include/gpu/GrShaderVar.h
new file mode 100644
index 0000000..a13cb8c
--- /dev/null
+++ b/include/gpu/GrShaderVar.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrShaderVar_DEFINED
+#define GrShaderVar_DEFINED
+
+#include "GrTypesPriv.h"
+#include "SkString.h"
+
+class GrShaderVar {
+public:
+    /**
+     * Early versions of GLSL have Varying and Attribute; those are later
+     * deprecated, but we still need to know whether a Varying variable
+     * should be treated as In or Out.
+     *
+     * TODO This really shouldn't live here, but until we have c++11, there is really no good way
+     * to write extensible enums.  In reality, only none, out, in, inout, and uniform really
+     * make sense on this base class
+     */
+    enum TypeModifier {
+        kNone_TypeModifier,
+        kOut_TypeModifier,
+        kIn_TypeModifier,
+        kInOut_TypeModifier,
+        kUniform_TypeModifier,
+        // GL Specific types below
+        kAttribute_TypeModifier,
+        kVaryingIn_TypeModifier,
+        kVaryingOut_TypeModifier
+    };
+
+    enum Precision {
+        kLow_Precision,         // lowp
+        kMedium_Precision,      // mediump
+        kHigh_Precision,        // highp
+        kDefault_Precision,     // Default for the current context. We make
+                                // fragment shaders default to mediump on ES2
+                                // because highp support is not guaranteed (and
+                                // we haven't been motivated to test for it).
+                                // Otherwise, highp.
+    };
+
+    /**
+     * Defaults to a float with no precision specifier
+     */
+    GrShaderVar()
+        : fType(kFloat_GrSLType)
+        , fTypeModifier(kNone_TypeModifier)
+        , fCount(kNonArray)
+        , fPrecision(kDefault_Precision) {
+    }
+
+    GrShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray,
+                  Precision precision = kDefault_Precision)
+        : fType(type)
+        , fTypeModifier(kNone_TypeModifier)
+        , fName(name)
+        , fCount(arrayCount)
+        , fPrecision(precision) {
+        SkASSERT(kVoid_GrSLType != type);
+    }
+
+    GrShaderVar(const char* name, GrSLType type, TypeModifier typeModifier,
+                  int arrayCount = kNonArray, Precision precision = kDefault_Precision)
+        : fType(type)
+        , fTypeModifier(typeModifier)
+        , fName(name)
+        , fCount(arrayCount)
+        , fPrecision(precision) {
+        SkASSERT(kVoid_GrSLType != type);
+    }
+
+    /**
+     * Values for array count that have special meaning. We allow 1-sized arrays.
+     */
+    enum {
+        kNonArray     =  0, // not an array
+        kUnsizedArray = -1, // an unsized array (declared with [])
+    };
+
+    /**
+     * Sets as a non-array.
+     */
+    void set(GrSLType type,
+             TypeModifier typeModifier,
+             const SkString& name,
+             Precision precision = kDefault_Precision) {
+        SkASSERT(kVoid_GrSLType != type);
+        fType = type;
+        fTypeModifier = typeModifier;
+        fName = name;
+        fCount = kNonArray;
+        fPrecision = precision;
+    }
+
+    /**
+     * Sets as a non-array.
+     */
+    void set(GrSLType type,
+             TypeModifier typeModifier,
+             const char* name,
+             Precision precision = kDefault_Precision) {
+        SkASSERT(kVoid_GrSLType != type);
+        fType = type;
+        fTypeModifier = typeModifier;
+        fName = name;
+        fCount = kNonArray;
+        fPrecision = precision;
+    }
+
+    /**
+     * Set all var options
+     */
+    void set(GrSLType type,
+             TypeModifier typeModifier,
+             const SkString& name,
+             int count,
+             Precision precision = kDefault_Precision) {
+        SkASSERT(kVoid_GrSLType != type);
+        fType = type;
+        fTypeModifier = typeModifier;
+        fName = name;
+        fCount = count;
+        fPrecision = precision;
+    }
+
+    /**
+     * Set all var options
+     */
+    void set(GrSLType type,
+             TypeModifier typeModifier,
+             const char* name,
+             int count,
+             Precision precision = kDefault_Precision) {
+        SkASSERT(kVoid_GrSLType != type);
+        fType = type;
+        fTypeModifier = typeModifier;
+        fName = name;
+        fCount = count;
+        fPrecision = precision;
+    }
+
+    /**
+     * Is the var an array.
+     */
+    bool isArray() const { return kNonArray != fCount; }
+    /**
+     * Is this an unsized array, (i.e. declared with []).
+     */
+    bool isUnsizedArray() const { return kUnsizedArray == fCount; }
+    /**
+     * Get the array length of the var.
+     */
+    int getArrayCount() const { return fCount; }
+    /**
+     * Set the array length of the var
+     */
+    void setArrayCount(int count) { fCount = count; }
+    /**
+     * Set to be a non-array.
+     */
+    void setNonArray() { fCount = kNonArray; }
+    /**
+     * Set to be an unsized array.
+     */
+    void setUnsizedArray() { fCount = kUnsizedArray; }
+
+    /**
+     * Access the var name as a writable string
+     */
+    SkString* accessName() { return &fName; }
+    /**
+     * Set the var name
+     */
+    void setName(const SkString& n) { fName = n; }
+    void setName(const char* n) { fName = n; }
+
+    /**
+     * Get the var name.
+     */
+    const SkString& getName() const { return fName; }
+
+    /**
+     * Shortcut for this->getName().c_str();
+     */
+    const char* c_str() const { return this->getName().c_str(); }
+
+    /**
+     * Get the type of the var
+     */
+    GrSLType getType() const { return fType; }
+    /**
+     * Set the type of the var
+     */
+    void setType(GrSLType type) { fType = type; }
+
+    TypeModifier getTypeModifier() const { return fTypeModifier; }
+    void setTypeModifier(TypeModifier type) { fTypeModifier = type; }
+
+    /**
+     * Get the precision of the var
+     */
+    Precision getPrecision() const { return fPrecision; }
+
+    /**
+     * Set the precision of the var
+     */
+    void setPrecision(Precision p) { fPrecision = p; }
+
+protected:
+    GrSLType        fType;
+    TypeModifier    fTypeModifier;
+    SkString        fName;
+    int             fCount;
+    Precision       fPrecision;
+};
+
+#endif
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index e4fc6ec..c6da45e 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -21,9 +21,9 @@
 
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
-#include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLGeometryProcessor.h"
 
-#include "effects/GrVertexEffect.h"
+#include "effects/GrGeometryProcessor.h"
 
 GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
 }
@@ -504,7 +504,7 @@
  * Requires shader derivative instruction support.
  */
 
-class QuadEdgeEffect : public GrVertexEffect {
+class QuadEdgeEffect : public GrGeometryProcessor {
 public:
 
     static GrEffect* Create() {
@@ -522,11 +522,13 @@
         *validFlags = 0;
     }
 
+    const GrShaderVar& inQuadEdge() const { return fInQuadEdge; }
+
     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
         return GrTBackendEffectFactory<QuadEdgeEffect>::getInstance();
     }
 
-    class GLEffect : public GrGLVertexEffect {
+    class GLEffect : public GrGLGeometryProcessor {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
             : INHERITED (factory) {}
@@ -567,10 +569,9 @@
             fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
 
+            const GrShaderVar& inQuadEdge = drawEffect.castEffect<QuadEdgeEffect>().inQuadEdge();
             GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-            const SkString* attr0Name =
-                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsName, inQuadEdge.c_str());
         }
 
         static inline void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
@@ -578,18 +579,22 @@
         virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE {}
 
     private:
-        typedef GrGLVertexEffect INHERITED;
+        typedef GrGLGeometryProcessor INHERITED;
     };
 
 private:
-    QuadEdgeEffect() {
-        this->addVertexAttrib(kVec4f_GrSLType);
+    QuadEdgeEffect()
+        : fInQuadEdge(this->addVertexAttrib(GrShaderVar("inQuadEdge",
+                                                        kVec4f_GrSLType,
+                                                        GrShaderVar::kAttribute_TypeModifier))) {
     }
 
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
         return true;
     }
 
+    const GrShaderVar& fInQuadEdge;
+
     GR_DECLARE_EFFECT_TEST;
 
     typedef GrEffect INHERITED;
@@ -676,9 +681,8 @@
 
     drawState->setVertexAttribs<gPathAttribs>(SK_ARRAY_COUNT(gPathAttribs), sizeof(QuadVertex));
 
-    static const int kEdgeAttrIndex = 1;
     GrEffect* quadEffect = QuadEdgeEffect::Create();
-    drawState->setGeometryProcessor(quadEffect, kEdgeAttrIndex)->unref();
+    drawState->setGeometryProcessor(quadEffect)->unref();
 
     GrDrawTarget::AutoReleaseGeometry arg(target, vCount, iCount);
     if (!arg.succeeded()) {
diff --git a/src/gpu/GrAAHairLinePathRenderer.cpp b/src/gpu/GrAAHairLinePathRenderer.cpp
index 0b3b878..2b4689e 100644
--- a/src/gpu/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/GrAAHairLinePathRenderer.cpp
@@ -990,8 +990,6 @@
         }
         GrDrawState* drawState = target->drawState();
 
-        static const int kEdgeAttrIndex = 1;
-
         // Check devBounds
         SkASSERT(check_bounds<BezierVertex>(drawState, devBounds, arg.vertices(),
                                             kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt));
@@ -1002,7 +1000,7 @@
             SkASSERT(hairQuadEffect);
             GrDrawState::AutoRestoreEffects are(drawState);
             target->setIndexSourceToBuffer(fQuadsIndexBuffer);
-            drawState->setGeometryProcessor(hairQuadEffect, kEdgeAttrIndex)->unref();
+            drawState->setGeometryProcessor(hairQuadEffect)->unref();
             int quads = 0;
             while (quads < quadCnt) {
                 int n = SkTMin(quadCnt - quads, kNumQuadsInIdxBuffer);
@@ -1021,7 +1019,7 @@
             GrEffect* hairConicEffect = GrConicEffect::Create(kHairlineAA_GrEffectEdgeType,
                                                               *target->caps());
             SkASSERT(hairConicEffect);
-            drawState->setGeometryProcessor(hairConicEffect, 1, 2)->unref();
+            drawState->setGeometryProcessor(hairConicEffect)->unref();
             int conics = 0;
             while (conics < conicCnt) {
                 int n = SkTMin(conicCnt - conics, kNumQuadsInIdxBuffer);
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index d19e26d..954a6f2 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -9,16 +9,16 @@
 #include "GrAARectRenderer.h"
 #include "GrGpu.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLGeometryProcessor.h"
 #include "GrTBackendEffectFactory.h"
 #include "SkColorPriv.h"
-#include "effects/GrVertexEffect.h"
+#include "effects/GrGeometryProcessor.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 class GrGLAlignedRectEffect;
 
 // Axis Aligned special case
-class GrAlignedRectEffect : public GrVertexEffect {
+class GrAlignedRectEffect : public GrGeometryProcessor {
 public:
     static GrEffect* Create() {
         GR_CREATE_STATIC_EFFECT(gAlignedRectEffect, GrAlignedRectEffect, ());
@@ -35,11 +35,13 @@
         *validFlags = 0;
     }
 
+    const GrShaderVar& inRect() const { return fInRect; }
+
     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
         return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
     }
 
-    class GLEffect : public GrGLVertexEffect {
+    class GLEffect : public GrGLGeometryProcessor {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
@@ -57,10 +59,9 @@
             const char *vsRectName, *fsRectName;
             builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
 
+            const GrShaderVar& inRect = drawEffect.castEffect<GrAlignedRectEffect>().inRect();
             GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-            const SkString* attr0Name =
-                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsRectName, inRect.c_str());
 
             GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
             // TODO: compute all these offsets, spans, and scales in the VS
@@ -96,20 +97,24 @@
         virtual void setData(const GrGLProgramDataManager& pdman, const GrDrawEffect&) SK_OVERRIDE {}
 
     private:
-        typedef GrGLVertexEffect INHERITED;
+        typedef GrGLGeometryProcessor INHERITED;
     };
 
 
 private:
-    GrAlignedRectEffect() : GrVertexEffect() {
-        this->addVertexAttrib(kVec4f_GrSLType);
+    GrAlignedRectEffect()
+        : fInRect(this->addVertexAttrib(GrShaderVar("inRect",
+                                                    kVec4f_GrSLType,
+                                                    GrShaderVar::kAttribute_TypeModifier))) {
     }
 
+    const GrShaderVar& fInRect;
+
     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 
@@ -137,7 +142,8 @@
  * The munged width and height are stored in a vec2 varying ("WidthHeight")
  * with the width in x and the height in y.
  */
-class GrRectEffect : public GrVertexEffect {
+
+class GrRectEffect : public GrGeometryProcessor {
 public:
     static GrEffect* Create() {
         GR_CREATE_STATIC_EFFECT(gRectEffect, GrRectEffect, ());
@@ -154,11 +160,14 @@
         *validFlags = 0;
     }
 
+    const GrShaderVar& inRectEdge() const { return fInRectEdge; }
+    const GrShaderVar& inWidthHeight() const { return fInWidthHeight; }
+
     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
         return GrTBackendEffectFactory<GrRectEffect>::getInstance();
     }
 
-    class GLEffect : public GrGLVertexEffect {
+    class GLEffect : public GrGLGeometryProcessor {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
@@ -176,18 +185,17 @@
             builder->addVarying(kVec4f_GrSLType, "RectEdge",
                                 &vsRectEdgeName, &fsRectEdgeName);
 
+            const GrRectEffect& rectEffect = drawEffect.castEffect<GrRectEffect>();
             GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-            const SkString* attr0Name =
-                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
+            vsBuilder->codeAppendf("%s = %s;", vsRectEdgeName, rectEffect.inRectEdge().c_str());
 
             // setup the varying for width/2+.5 and height/2+.5
             const char *vsWidthHeightName, *fsWidthHeightName;
             builder->addVarying(kVec2f_GrSLType, "WidthHeight",
                                 &vsWidthHeightName, &fsWidthHeightName);
-            const SkString* attr1Name =
-                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
+            vsBuilder->codeAppendf("%s = %s;",
+                                   vsWidthHeightName,
+                                   rectEffect.inWidthHeight().c_str());
 
             GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
             // TODO: compute all these offsets, spans, and scales in the VS
@@ -230,22 +238,31 @@
         virtual void setData(const GrGLProgramDataManager& pdman, const GrDrawEffect&) SK_OVERRIDE {}
 
     private:
-        typedef GrGLVertexEffect INHERITED;
+        typedef GrGLGeometryProcessor INHERITED;
     };
 
 
+
 private:
-    GrRectEffect() : GrVertexEffect() {
-        this->addVertexAttrib(kVec4f_GrSLType);
-        this->addVertexAttrib(kVec2f_GrSLType);
+    GrRectEffect()
+        : fInRectEdge(this->addVertexAttrib(GrShaderVar("inRectEdge",
+                                                        kVec4f_GrSLType,
+                                                        GrShaderVar::kAttribute_TypeModifier)))
+        , fInWidthHeight(this->addVertexAttrib(
+                GrShaderVar("inWidthHeight",
+                            kVec2f_GrSLType,
+                            GrShaderVar::kAttribute_TypeModifier))) {
         this->setWillReadFragmentPosition();
     }
 
     virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE { return true; }
 
+    const GrShaderVar& fInRectEdge;
+    const GrShaderVar& fInWidthHeight;
+
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 
@@ -646,9 +663,7 @@
     RectVertex* verts = reinterpret_cast<RectVertex*>(geo.vertices());
 
     GrEffect* effect = GrRectEffect::Create();
-    static const int kRectAttrIndex = 1;
-    static const int kWidthIndex = 2;
-    drawState->setGeometryProcessor(effect, kRectAttrIndex, kWidthIndex)->unref();
+    drawState->setGeometryProcessor(effect)->unref();
 
     for (int i = 0; i < 4; ++i) {
         verts[i].fCenter = center;
@@ -696,8 +711,7 @@
     AARectVertex* verts = reinterpret_cast<AARectVertex*>(geo.vertices());
 
     GrEffect* effect = GrAlignedRectEffect::Create();
-    static const int kOffsetIndex = 1;
-    drawState->setGeometryProcessor(effect, kOffsetIndex)->unref();
+    drawState->setGeometryProcessor(effect)->unref();
 
     SkRect devRect;
     combinedMatrix.mapRect(&devRect, rect);
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
index 70785a6..9ef8da2 100755
--- a/src/gpu/GrBitmapTextContext.cpp
+++ b/src/gpu/GrBitmapTextContext.cpp
@@ -30,9 +30,6 @@
 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
                 "Dump the contents of the font cache before every purge.");
 
-static const int kGlyphCoordsNoColorAttributeIndex = 1;
-static const int kGlyphCoordsWithColorAttributeIndex = 2;
-
 namespace {
 // position + texture coord
 extern const GrVertexAttrib gTextVertexAttribs[] = {
@@ -106,9 +103,7 @@
         }
 
         // This effect could be stored with one of the cache objects (atlas?)
-        int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
-                                                               kGlyphCoordsNoColorAttributeIndex;
-        drawState->setGeometryProcessor(fCachedEffect.get(), coordsIdx);
+        drawState->setGeometryProcessor(fCachedEffect.get());
         SkASSERT(fStrike);
         switch (fStrike->getMaskFormat()) {
             // Color bitmap text
diff --git a/src/gpu/GrDistanceFieldTextContext.cpp b/src/gpu/GrDistanceFieldTextContext.cpp
index 0aafc54..d32dcb9 100755
--- a/src/gpu/GrDistanceFieldTextContext.cpp
+++ b/src/gpu/GrDistanceFieldTextContext.cpp
@@ -28,9 +28,6 @@
 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
                 "Dump the contents of the font cache before every purge.");
 
-static const int kGlyphCoordsNoColorAttributeIndex = 1;
-static const int kGlyphCoordsWithColorAttributeIndex = 2;
-
 static const int kSmallDFFontSize = 32;
 static const int kSmallDFFontLimit = 32;
 static const int kMediumDFFontSize = 64;
@@ -196,9 +193,7 @@
         this->setupCoverageEffect(filteredColor);
        
         // Effects could be stored with one of the cache objects (atlas?)
-        int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
-                                                               kGlyphCoordsNoColorAttributeIndex;
-        drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx);
+        drawState->setGeometryProcessor(fCachedEffect.get());
         
         // Set draw state
         if (fUseLCDText) {
diff --git a/src/gpu/GrDrawState.h b/src/gpu/GrDrawState.h
index 4850fc9..6a1e380 100644
--- a/src/gpu/GrDrawState.h
+++ b/src/gpu/GrDrawState.h
@@ -180,10 +180,11 @@
      * but is never put in the color processing pipeline.
      */
 
-    const GrEffect* setGeometryProcessor(const GrEffect* effect, int attr0 = -1, int attr1 = -1) {
+    const GrEffect* setGeometryProcessor(const GrEffect* effect) {
         SkASSERT(effect);
+        SkASSERT(effect->requiresVertexShader());
         SkASSERT(!this->hasGeometryProcessor());
-        fGeometryProcessor.reset(new GrEffectStage(effect, attr0, attr1));
+        fGeometryProcessor.reset(new GrEffectStage(effect));
         this->invalidateOptState();
         return effect;
     }
@@ -208,16 +209,18 @@
     /// the color / coverage distinction.
     ////
 
-    const GrEffect* addColorEffect(const GrEffect* effect, int attr0 = -1, int attr1 = -1) {
+    const GrEffect* addColorEffect(const GrEffect* effect) {
         SkASSERT(effect);
-        SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect, attr0, attr1));
+        SkASSERT(!effect->requiresVertexShader());
+        SkNEW_APPEND_TO_TARRAY(&fColorStages, GrEffectStage, (effect));
         this->invalidateOptState();
         return effect;
     }
 
-    const GrEffect* addCoverageEffect(const GrEffect* effect, int attr0 = -1, int attr1 = -1) {
+    const GrEffect* addCoverageEffect(const GrEffect* effect) {
         SkASSERT(effect);
-        SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect, attr0, attr1));
+        SkASSERT(!effect->requiresVertexShader());
+        SkNEW_APPEND_TO_TARRAY(&fCoverageStages, GrEffectStage, (effect));
         this->invalidateOptState();
         return effect;
     }
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index f694678..46ba72d 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -11,7 +11,7 @@
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
-#include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLGeometryProcessor.h"
 #include "GrTBackendEffectFactory.h"
 
 #include "GrDrawState.h"
@@ -22,7 +22,7 @@
 #include "SkStrokeRec.h"
 #include "SkTLazy.h"
 
-#include "effects/GrVertexEffect.h"
+#include "effects/GrGeometryProcessor.h"
 #include "effects/GrRRectEffect.h"
 
 namespace {
@@ -60,7 +60,7 @@
  * specified as offset_x, offset_y (both from center point), outer radius and inner radius.
  */
 
-class CircleEdgeEffect : public GrVertexEffect {
+class CircleEdgeEffect : public GrGeometryProcessor {
 public:
     static GrEffect* Create(bool stroke) {
         GR_CREATE_STATIC_EFFECT(gCircleStrokeEdge, CircleEdgeEffect, (true));
@@ -80,6 +80,8 @@
         *validFlags = 0;
     }
 
+    const GrShaderVar& inCircleEdge() const { return fInCircleEdge; }
+
     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
         return GrTBackendEffectFactory<CircleEdgeEffect>::getInstance();
     }
@@ -90,7 +92,7 @@
 
     inline bool isStroked() const { return fStroke; }
 
-    class GLEffect : public GrGLVertexEffect {
+    class GLEffect : public GrGLGeometryProcessor {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
@@ -106,10 +108,8 @@
             const char *vsName, *fsName;
             builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
 
-            GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-            const SkString* attr0Name =
-                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
+            GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();;
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsName, circleEffect.inCircleEdge().c_str());
 
             GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
             fsBuilder->codeAppendf("\tfloat d = length(%s.xy);\n", fsName);
@@ -132,13 +132,16 @@
         virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE {}
 
     private:
-        typedef GrGLVertexEffect INHERITED;
+        typedef GrGLGeometryProcessor INHERITED;
     };
 
 
 private:
-    CircleEdgeEffect(bool stroke) : GrVertexEffect() {
-        this->addVertexAttrib(kVec4f_GrSLType);
+    CircleEdgeEffect(bool stroke)
+        : fInCircleEdge(this->addVertexAttrib(
+                GrShaderVar("inCircleEdge",
+                            kVec4f_GrSLType,
+                            GrShaderVar::kAttribute_TypeModifier))) {
         fStroke = stroke;
     }
 
@@ -147,11 +150,12 @@
         return cee.fStroke == fStroke;
     }
 
+    const GrShaderVar& fInCircleEdge;
     bool fStroke;
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 GR_DEFINE_EFFECT_TEST(CircleEdgeEffect);
@@ -173,7 +177,7 @@
  * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0.
  */
 
-class EllipseEdgeEffect : public GrVertexEffect {
+class EllipseEdgeEffect : public GrGeometryProcessor {
 public:
     static GrEffect* Create(bool stroke) {
         GR_CREATE_STATIC_EFFECT(gEllipseStrokeEdge, EllipseEdgeEffect, (true));
@@ -201,9 +205,12 @@
 
     static const char* Name() { return "EllipseEdge"; }
 
+    const GrShaderVar& inEllipseOffset() const { return fInEllipseOffset; }
+    const GrShaderVar& inEllipseRadii() const { return fInEllipseRadii; }
+
     inline bool isStroked() const { return fStroke; }
 
-    class GLEffect : public GrGLVertexEffect {
+    class GLEffect : public GrGLGeometryProcessor {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
@@ -223,14 +230,11 @@
             builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName, &fsOffsetName);
 
             GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-            const SkString* attr0Name =
-                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_str());
+            vsBuilder->codeAppendf("%s = %s;", vsOffsetName,
+                                   ellipseEffect.inEllipseOffset().c_str());
 
             builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName);
-            const SkString* attr1Name =
-                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str());
+            vsBuilder->codeAppendf("%s = %s;", vsRadiiName, ellipseEffect.inEllipseRadii().c_str());
 
             // for outer curve
             GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
@@ -266,13 +270,19 @@
         }
 
     private:
-        typedef GrGLVertexEffect INHERITED;
+        typedef GrGLGeometryProcessor INHERITED;
     };
 
 private:
-    EllipseEdgeEffect(bool stroke) : GrVertexEffect() {
-        this->addVertexAttrib(kVec2f_GrSLType);
-        this->addVertexAttrib(kVec4f_GrSLType);
+    EllipseEdgeEffect(bool stroke)
+        : fInEllipseOffset(this->addVertexAttrib(
+                GrShaderVar("inEllipseOffset",
+                            kVec2f_GrSLType,
+                            GrShaderVar::kAttribute_TypeModifier)))
+        , fInEllipseRadii(this->addVertexAttrib(
+                GrShaderVar("inEllipseRadii",
+                            kVec4f_GrSLType,
+                            GrShaderVar::kAttribute_TypeModifier))) {
         fStroke = stroke;
     }
 
@@ -281,11 +291,13 @@
         return eee.fStroke == fStroke;
     }
 
+    const GrShaderVar& fInEllipseOffset;
+    const GrShaderVar& fInEllipseRadii;
     bool fStroke;
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 GR_DEFINE_EFFECT_TEST(EllipseEdgeEffect);
@@ -308,7 +320,7 @@
  * The result is device-independent and can be used with any affine matrix.
  */
 
-class DIEllipseEdgeEffect : public GrVertexEffect {
+class DIEllipseEdgeEffect : public GrGeometryProcessor {
 public:
     enum Mode { kStroke = 0, kHairline, kFill };
 
@@ -342,9 +354,12 @@
 
     static const char* Name() { return "DIEllipseEdge"; }
 
+    const GrShaderVar& inEllipseOffsets0() const { return fInEllipseOffsets0; }
+    const GrShaderVar& inEllipseOffsets1() const { return fInEllipseOffsets1; }
+
     inline Mode getMode() const { return fMode; }
 
-    class GLEffect : public GrGLVertexEffect {
+    class GLEffect : public GrGLGeometryProcessor {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
@@ -363,15 +378,13 @@
                                       &vsOffsetName0, &fsOffsetName0);
 
             GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-            const SkString* attr0Name =
-                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName0, attr0Name->c_str());
+            vsBuilder->codeAppendf("%s = %s;", vsOffsetName0,
+                                   ellipseEffect.inEllipseOffsets0().c_str());
             const char *vsOffsetName1, *fsOffsetName1;
             builder->addVarying(kVec2f_GrSLType, "EllipseOffsets1",
                                       &vsOffsetName1, &fsOffsetName1);
-            const SkString* attr1Name =
-                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName1, attr1Name->c_str());
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName1,
+                                   ellipseEffect.inEllipseOffsets1().c_str());
 
             GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
             SkAssertResult(fsBuilder->enableFeature(
@@ -426,13 +439,19 @@
         }
 
     private:
-        typedef GrGLVertexEffect INHERITED;
+        typedef GrGLGeometryProcessor INHERITED;
     };
 
 private:
-    DIEllipseEdgeEffect(Mode mode) : GrVertexEffect() {
-        this->addVertexAttrib(kVec2f_GrSLType);
-        this->addVertexAttrib(kVec2f_GrSLType);
+    DIEllipseEdgeEffect(Mode mode)
+        : fInEllipseOffsets0(this->addVertexAttrib(
+                GrShaderVar("inEllipseOffsets0",
+                            kVec2f_GrSLType,
+                            GrShaderVar::kAttribute_TypeModifier)))
+        , fInEllipseOffsets1(this->addVertexAttrib(
+                GrShaderVar("inEllipseOffsets1",
+                            kVec2f_GrSLType,
+                            GrShaderVar::kAttribute_TypeModifier))) {
         fMode = mode;
     }
 
@@ -441,11 +460,13 @@
         return eee.fMode == fMode;
     }
 
+    const GrShaderVar& fInEllipseOffsets0;
+    const GrShaderVar& fInEllipseOffsets1;
     Mode fMode;
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 GR_DEFINE_EFFECT_TEST(DIEllipseEdgeEffect);
@@ -552,8 +573,7 @@
     }
 
     GrEffect* effect = CircleEdgeEffect::Create(isStrokeOnly && innerRadius > 0);
-    static const int kCircleEdgeAttrIndex = 1;
-    drawState->setGeometryProcessor(effect, kCircleEdgeAttrIndex)->unref();
+    drawState->setGeometryProcessor(effect)->unref();
 
     // The radii are outset for two reasons. First, it allows the shader to simply perform
     // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
@@ -694,9 +714,7 @@
     GrEffect* effect = EllipseEdgeEffect::Create(isStrokeOnly &&
                                                  innerXRadius > 0 && innerYRadius > 0);
 
-    static const int kEllipseCenterAttrIndex = 1;
-    static const int kEllipseEdgeAttrIndex = 2;
-    drawState->setGeometryProcessor(effect, kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref();
+    drawState->setGeometryProcessor(effect)->unref();
 
     // Compute the reciprocals of the radii here to save time in the shader
     SkScalar xRadRecip = SkScalarInvert(xRadius);
@@ -812,10 +830,7 @@
 
     GrEffect* effect = DIEllipseEdgeEffect::Create(mode);
 
-    static const int kEllipseOuterOffsetAttrIndex = 1;
-    static const int kEllipseInnerOffsetAttrIndex = 2;
-    drawState->setGeometryProcessor(effect, kEllipseOuterOffsetAttrIndex,
-                                    kEllipseInnerOffsetAttrIndex)->unref();
+    drawState->setGeometryProcessor(effect)->unref();
 
     // This expands the outer rect so that after CTM we end up with a half-pixel border
     SkScalar a = vm[SkMatrix::kMScaleX];
@@ -1062,8 +1077,7 @@
         isStrokeOnly = (isStrokeOnly && innerRadius >= 0);
 
         GrEffect* effect = CircleEdgeEffect::Create(isStrokeOnly);
-        static const int kCircleEdgeAttrIndex = 1;
-        drawState->setGeometryProcessor(effect, kCircleEdgeAttrIndex)->unref();
+        drawState->setGeometryProcessor(effect)->unref();
 
         // The radii are outset for two reasons. First, it allows the shader to simply perform
         // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the
@@ -1166,11 +1180,7 @@
         EllipseVertex* verts = reinterpret_cast<EllipseVertex*>(geo.vertices());
 
         GrEffect* effect = EllipseEdgeEffect::Create(isStrokeOnly);
-        static const int kEllipseOffsetAttrIndex = 1;
-        static const int kEllipseRadiiAttrIndex = 2;
-        drawState->setGeometryProcessor(effect,
-                                        kEllipseOffsetAttrIndex,
-                                        kEllipseRadiiAttrIndex)->unref();
+        drawState->setGeometryProcessor(effect)->unref();
 
         // Compute the reciprocals of the radii here to save time in the shader
         SkScalar xRadRecip = SkScalarInvert(xRadius);
diff --git a/src/gpu/GrRODrawState.cpp b/src/gpu/GrRODrawState.cpp
index b79e8fc..f7e486f 100644
--- a/src/gpu/GrRODrawState.cpp
+++ b/src/gpu/GrRODrawState.cpp
@@ -93,26 +93,28 @@
         // make sure that any attribute indices have the correct binding type, that the attrib
         // type and effect's shader lang type are compatible, and that attributes shared by
         // multiple effects use the same shader lang type.
-        const int* attributeIndices = stage.getVertexAttribIndices();
-        int numAttributes = stage.getVertexAttribIndexCount();
-        for (int i = 0; i < numAttributes; ++i) {
-            int attribIndex = attributeIndices[i];
-            if (attribIndex >= fVACount ||
-                kEffect_GrVertexAttribBinding != fVAPtr[attribIndex].fBinding) {
-                return false;
-            }
+        const GrEffect::VertexAttribArray& s = effect->getVertexAttribs();
 
-            GrSLType effectSLType = effect->vertexAttribType(i);
-            GrVertexAttribType attribType = fVAPtr[attribIndex].fType;
+        int effectIndex = 0;
+        for (int index = 0; index < fVACount; index++) {
+            if (kEffect_GrVertexAttribBinding != fVAPtr[index].fBinding) {
+                // we only care about effect bindings
+                continue;
+            }
+            SkASSERT(effectIndex < s.count());
+            GrSLType effectSLType = s[effectIndex].getType();
+            GrVertexAttribType attribType = fVAPtr[index].fType;
             int slVecCount = GrSLTypeVectorCount(effectSLType);
             int attribVecCount = GrVertexAttribTypeVectorCount(attribType);
             if (slVecCount != attribVecCount ||
-                (static_cast<GrSLType>(-1) != slTypes[attribIndex] &&
-                    slTypes[attribIndex] != effectSLType)) {
+                (static_cast<GrSLType>(-1) != slTypes[index] && slTypes[index] != effectSLType)) {
                 return false;
             }
-            slTypes[attribIndex] = effectSLType;
+            slTypes[index] = effectSLType;
+            effectIndex++;
         }
+        // Make sure all attributes are consumed and we were able to find everything
+        SkASSERT(s.count() == effectIndex);
     }
 
     return true;
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 488af15..8c85809 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -10,10 +10,10 @@
 
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
-#include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLGeometryProcessor.h"
 #include "GrTBackendEffectFactory.h"
 
-class GrGLConicEffect : public GrGLVertexEffect {
+class GrGLConicEffect : public GrGLGeometryProcessor {
 public:
     GrGLConicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
@@ -32,7 +32,7 @@
 private:
     GrEffectEdgeType fEdgeType;
 
-    typedef GrGLVertexEffect INHERITED;
+    typedef GrGLGeometryProcessor INHERITED;
 };
 
 GrGLConicEffect::GrGLConicEffect(const GrBackendEffectFactory& factory,
@@ -54,10 +54,9 @@
     builder->addVarying(kVec4f_GrSLType, "ConicCoeffs",
                               &vsName, &fsName);
 
+    const GrShaderVar& inConicCoeffs = drawEffect.castEffect<GrConicEffect>().inConicCoeffs();
     GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-    const SkString* attr0Name =
-        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    vsBuilder->codeAppendf("%s = %s;", vsName, attr0Name->c_str());
+    vsBuilder->codeAppendf("%s = %s;", vsName, inConicCoeffs.c_str());
 
     GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     fsBuilder->codeAppend("float edgeAlpha;");
@@ -135,9 +134,11 @@
     return GrTBackendEffectFactory<GrConicEffect>::getInstance();
 }
 
-GrConicEffect::GrConicEffect(GrEffectEdgeType edgeType) : GrVertexEffect() {
-    this->addVertexAttrib(kVec4f_GrSLType);
-    fEdgeType = edgeType;
+GrConicEffect::GrConicEffect(GrEffectEdgeType edgeType)
+    : fEdgeType(edgeType)
+    , fInConicCoeffs(this->addVertexAttrib(GrShaderVar("inConicCoeffs",
+                                                       kVec4f_GrSLType,
+                                                       GrShaderVar::kAttribute_TypeModifier))) {
 }
 
 bool GrConicEffect::onIsEqual(const GrEffect& other) const {
@@ -166,7 +167,7 @@
 // Quad
 //////////////////////////////////////////////////////////////////////////////
 
-class GrGLQuadEffect : public GrGLVertexEffect {
+class GrGLQuadEffect : public GrGLGeometryProcessor {
 public:
     GrGLQuadEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
@@ -185,7 +186,7 @@
 private:
     GrEffectEdgeType fEdgeType;
 
-    typedef GrGLVertexEffect INHERITED;
+    typedef GrGLGeometryProcessor INHERITED;
 };
 
 GrGLQuadEffect::GrGLQuadEffect(const GrBackendEffectFactory& factory,
@@ -206,9 +207,8 @@
     builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName);
 
     GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-    const SkString* attrName =
-        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    vsBuilder->codeAppendf("%s = %s;", vsName, attrName->c_str());
+    const GrShaderVar& inHairQuadEdge = drawEffect.castEffect<GrQuadEffect>().inHairQuadEdge();
+    vsBuilder->codeAppendf("%s = %s;", vsName, inHairQuadEdge.c_str());
 
     GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     fsBuilder->codeAppendf("float edgeAlpha;");
@@ -272,9 +272,11 @@
     return GrTBackendEffectFactory<GrQuadEffect>::getInstance();
 }
 
-GrQuadEffect::GrQuadEffect(GrEffectEdgeType edgeType) : GrVertexEffect() {
-    this->addVertexAttrib(kVec4f_GrSLType);
-    fEdgeType = edgeType;
+GrQuadEffect::GrQuadEffect(GrEffectEdgeType edgeType)
+    : fEdgeType(edgeType)
+    , fInHairQuadEdge(this->addVertexAttrib(GrShaderVar("inCubicCoeffs",
+                                                        kVec4f_GrSLType,
+                                                        GrShaderVar::kAttribute_TypeModifier))) {
 }
 
 bool GrQuadEffect::onIsEqual(const GrEffect& other) const {
@@ -303,7 +305,7 @@
 // Cubic
 //////////////////////////////////////////////////////////////////////////////
 
-class GrGLCubicEffect : public GrGLVertexEffect {
+class GrGLCubicEffect : public GrGLGeometryProcessor {
 public:
     GrGLCubicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
@@ -322,7 +324,7 @@
 private:
     GrEffectEdgeType fEdgeType;
 
-    typedef GrGLVertexEffect INHERITED;
+    typedef GrGLGeometryProcessor INHERITED;
 };
 
 GrGLCubicEffect::GrGLCubicEffect(const GrBackendEffectFactory& factory,
@@ -345,9 +347,8 @@
                               &vsName, &fsName, GrGLShaderVar::kHigh_Precision);
 
     GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-    const SkString* attr0Name =
-        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    vsBuilder->codeAppendf("%s = %s;", vsName, attr0Name->c_str());
+    const GrShaderVar& inCubicCoeffs = drawEffect.castEffect<GrCubicEffect>().inCubicCoeffs();
+    vsBuilder->codeAppendf("%s = %s;", vsName, inCubicCoeffs.c_str());
 
     GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
 
@@ -451,9 +452,11 @@
     return GrTBackendEffectFactory<GrCubicEffect>::getInstance();
 }
 
-GrCubicEffect::GrCubicEffect(GrEffectEdgeType edgeType) : GrVertexEffect() {
-    this->addVertexAttrib(kVec4f_GrSLType);
-    fEdgeType = edgeType;
+GrCubicEffect::GrCubicEffect(GrEffectEdgeType edgeType)
+    : fEdgeType(edgeType)
+    , fInCubicCoeffs(this->addVertexAttrib(GrShaderVar("inCubicCoeffs",
+                                                       kVec4f_GrSLType,
+                                                       GrShaderVar::kAttribute_TypeModifier))) {
 }
 
 bool GrCubicEffect::onIsEqual(const GrEffect& other) const {
diff --git a/src/gpu/effects/GrBezierEffect.h b/src/gpu/effects/GrBezierEffect.h
index b8d8f7b..4da16fe 100644
--- a/src/gpu/effects/GrBezierEffect.h
+++ b/src/gpu/effects/GrBezierEffect.h
@@ -10,7 +10,7 @@
 
 #include "GrDrawTargetCaps.h"
 #include "GrEffect.h"
-#include "GrVertexEffect.h"
+#include "GrGeometryProcessor.h"
 #include "GrTypesPriv.h"
 
 /**
@@ -55,7 +55,7 @@
  */
 class GrGLConicEffect;
 
-class GrConicEffect : public GrVertexEffect {
+class GrConicEffect : public GrGeometryProcessor {
 public:
     static GrEffect* Create(const GrEffectEdgeType edgeType, const GrDrawTargetCaps& caps) {
         GR_CREATE_STATIC_EFFECT(gConicFillAA, GrConicEffect, (kFillAA_GrEffectEdgeType));
@@ -86,6 +86,7 @@
 
     static const char* Name() { return "Conic"; }
 
+    inline const GrShaderVar& inConicCoeffs() const { return fInConicCoeffs; }
     inline bool isAntiAliased() const { return GrEffectEdgeTypeIsAA(fEdgeType); }
     inline bool isFilled() const { return GrEffectEdgeTypeIsFill(fEdgeType); }
     inline GrEffectEdgeType getEdgeType() const { return fEdgeType; }
@@ -104,11 +105,12 @@
 
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
 
-    GrEffectEdgeType fEdgeType;
+    GrEffectEdgeType   fEdgeType;
+    const GrShaderVar& fInConicCoeffs;
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -122,7 +124,7 @@
  */
 class GrGLQuadEffect;
 
-class GrQuadEffect : public GrVertexEffect {
+class GrQuadEffect : public GrGeometryProcessor {
 public:
     static GrEffect* Create(const GrEffectEdgeType edgeType, const GrDrawTargetCaps& caps) {
         GR_CREATE_STATIC_EFFECT(gQuadFillAA, GrQuadEffect, (kFillAA_GrEffectEdgeType));
@@ -153,6 +155,7 @@
 
     static const char* Name() { return "Quad"; }
 
+    inline const GrShaderVar& inHairQuadEdge() const { return fInHairQuadEdge; }
     inline bool isAntiAliased() const { return GrEffectEdgeTypeIsAA(fEdgeType); }
     inline bool isFilled() const { return GrEffectEdgeTypeIsFill(fEdgeType); }
     inline GrEffectEdgeType getEdgeType() const { return fEdgeType; }
@@ -171,11 +174,12 @@
 
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
 
-    GrEffectEdgeType fEdgeType;
+    GrEffectEdgeType   fEdgeType;
+    const GrShaderVar& fInHairQuadEdge;
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 //////////////////////////////////////////////////////////////////////////////
@@ -191,7 +195,7 @@
  */
 class GrGLCubicEffect;
 
-class GrCubicEffect : public GrVertexEffect {
+class GrCubicEffect : public GrGeometryProcessor {
 public:
     static GrEffect* Create(const GrEffectEdgeType edgeType, const GrDrawTargetCaps& caps) {
         GR_CREATE_STATIC_EFFECT(gCubicFillAA, GrCubicEffect, (kFillAA_GrEffectEdgeType));
@@ -222,6 +226,7 @@
 
     static const char* Name() { return "Cubic"; }
 
+    inline const GrShaderVar& inCubicCoeffs() const { return fInCubicCoeffs; }
     inline bool isAntiAliased() const { return GrEffectEdgeTypeIsAA(fEdgeType); }
     inline bool isFilled() const { return GrEffectEdgeTypeIsFill(fEdgeType); }
     inline GrEffectEdgeType getEdgeType() const { return fEdgeType; }
@@ -240,11 +245,12 @@
 
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
 
-    GrEffectEdgeType fEdgeType;
+    GrEffectEdgeType   fEdgeType;
+    const GrShaderVar& fInCubicCoeffs;
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 #endif
diff --git a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
index 0401c6c..206c524 100644
--- a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
+++ b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
@@ -10,11 +10,11 @@
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
-#include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLGeometryProcessor.h"
 #include "GrTBackendEffectFactory.h"
 #include "GrTexture.h"
 
-class GrGLCustomCoordsTextureEffect : public GrGLVertexEffect {
+class GrGLCustomCoordsTextureEffect : public GrGLGeometryProcessor {
 public:
     GrGLCustomCoordsTextureEffect(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect)
         : INHERITED (factory) {}
@@ -26,7 +26,9 @@
                           const char* inputColor,
                           const TransformedCoordsArray&,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        SkASSERT(1 == drawEffect.castEffect<GrCustomCoordsTextureEffect>().numVertexAttribs());
+        const GrCustomCoordsTextureEffect& customCoordsTextureEffect =
+                drawEffect.castEffect<GrCustomCoordsTextureEffect>();
+        SkASSERT(1 == customCoordsTextureEffect.getVertexAttribs().count());
 
         SkString fsCoordName;
         const char* vsVaryingName;
@@ -35,9 +37,8 @@
         fsCoordName = fsVaryingNamePtr;
 
         GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-        const SkString* attr0Name =
-            vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-        vsBuilder->codeAppendf("\t%s = %s;\n", vsVaryingName, attr0Name->c_str());
+        const GrShaderVar& inTextureCoords = customCoordsTextureEffect.inTextureCoords();
+        vsBuilder->codeAppendf("\t%s = %s;\n", vsVaryingName, inTextureCoords.c_str());
 
         GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
         fsBuilder->codeAppendf("\t%s = ", outputColor);
@@ -52,16 +53,18 @@
                          const GrDrawEffect& drawEffect) SK_OVERRIDE {}
 
 private:
-    typedef GrGLVertexEffect INHERITED;
+    typedef GrGLGeometryProcessor INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
 GrCustomCoordsTextureEffect::GrCustomCoordsTextureEffect(GrTexture* texture,
                                                          const GrTextureParams& params)
-    : fTextureAccess(texture, params) {
+    : fTextureAccess(texture, params)
+    , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
+                                                         kVec2f_GrSLType,
+                                                         GrShaderVar::kAttribute_TypeModifier))) {
     this->addTextureAccess(&fTextureAccess);
-    this->addVertexAttrib(kVec2f_GrSLType);
 }
 
 bool GrCustomCoordsTextureEffect::onIsEqual(const GrEffect& other) const {
diff --git a/src/gpu/effects/GrCustomCoordsTextureEffect.h b/src/gpu/effects/GrCustomCoordsTextureEffect.h
index 95e0fbb..02e7c44 100644
--- a/src/gpu/effects/GrCustomCoordsTextureEffect.h
+++ b/src/gpu/effects/GrCustomCoordsTextureEffect.h
@@ -9,7 +9,7 @@
 #define GrCustomCoordsTextureEffect_DEFINED
 
 #include "GrEffect.h"
-#include "GrVertexEffect.h"
+#include "GrGeometryProcessor.h"
 
 class GrGLCustomCoordsTextureEffect;
 
@@ -18,7 +18,7 @@
  * It allows explicit specification of the filtering and wrap modes (GrTextureParams). The input
  * coords are a custom attribute.
  */
-class GrCustomCoordsTextureEffect : public GrVertexEffect {
+class GrCustomCoordsTextureEffect : public GrGeometryProcessor {
 public:
     static GrEffect* Create(GrTexture* tex, const GrTextureParams& p) {
         return SkNEW_ARGS(GrCustomCoordsTextureEffect, (tex, p));
@@ -30,6 +30,8 @@
 
     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
 
+    const GrShaderVar& inTextureCoords() const { return fInTextureCoords; }
+
     typedef GrGLCustomCoordsTextureEffect GLEffect;
 
     virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE;
@@ -39,11 +41,12 @@
 
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
 
-    GrTextureAccess fTextureAccess;
+    GrTextureAccess    fTextureAccess;
+    const GrShaderVar& fInTextureCoords;
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 #endif
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index f4298eb..398b0dd 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -10,9 +10,9 @@
 
 #include "../GrAARectRenderer.h"
 
-#include "effects/GrVertexEffect.h"
+#include "effects/GrGeometryProcessor.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLGeometryProcessor.h"
 #include "gl/GrGLSL.h"
 #include "GrContext.h"
 #include "GrCoordTransform.h"
@@ -69,6 +69,10 @@
     SkPoint fDashPos;
 };
 
+extern const GrVertexAttrib gDashLineNoAAVertexAttribs[] = {
+    { kVec2f_GrVertexAttribType, 0,                 kPosition_GrVertexAttribBinding }
+};
+
 extern const GrVertexAttrib gDashLineVertexAttribs[] = {
     { kVec2f_GrVertexAttribType, 0,                 kPosition_GrVertexAttribBinding },
     { kVec2f_GrVertexAttribType, sizeof(SkPoint),   kEffect_GrVertexAttribBinding },
@@ -346,12 +350,16 @@
         GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap :
                                                         GrDashingEffect::kNonRound_DashCap;
         drawState->setGeometryProcessor(
-            GrDashingEffect::Create(edgeType, devInfo, strokeWidth, capType), 1)->unref();
-    }
+            GrDashingEffect::Create(edgeType, devInfo, strokeWidth, capType))->unref();
 
-    // Set up the vertex data for the line and start/end dashes
-    drawState->setVertexAttribs<gDashLineVertexAttribs>(SK_ARRAY_COUNT(gDashLineVertexAttribs),
-                                                        sizeof(DashLineVertex));
+        // Set up the vertex data for the line and start/end dashes
+        drawState->setVertexAttribs<gDashLineVertexAttribs>(SK_ARRAY_COUNT(gDashLineVertexAttribs),
+                                                            sizeof(DashLineVertex));
+    } else {
+        // Set up the vertex data for the line and start/end dashes
+        drawState->setVertexAttribs<gDashLineNoAAVertexAttribs>(
+                SK_ARRAY_COUNT(gDashLineNoAAVertexAttribs), sizeof(DashLineVertex));
+    }
 
     int totalRectCnt = 0;
 
@@ -424,7 +432,7 @@
  * transform the line to be horizontal, with the start of line at the origin then shifted to the
  * right by half the off interval. The line then goes in the positive x direction.
  */
-class DashingCircleEffect : public GrVertexEffect {
+class DashingCircleEffect : public GrGeometryProcessor {
 public:
     typedef SkPathEffect::DashInfo DashInfo;
 
@@ -434,6 +442,8 @@
 
     static const char* Name() { return "DashingCircleEffect"; }
 
+    const GrShaderVar& inCoord() const { return fInCoord; }
+
     GrEffectEdgeType getEdgeType() const { return fEdgeType; }
 
     SkScalar getRadius() const { return fRadius; }
@@ -454,18 +464,19 @@
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
 
     GrEffectEdgeType    fEdgeType;
+    const GrShaderVar&  fInCoord;
     SkScalar            fIntervalLength;
     SkScalar            fRadius;
     SkScalar            fCenterX;
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 //////////////////////////////////////////////////////////////////////////////
 
-class GLDashingCircleEffect : public GrGLVertexEffect {
+class GLDashingCircleEffect : public GrGLGeometryProcessor {
 public:
     GLDashingCircleEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
@@ -486,7 +497,7 @@
     SkScalar                              fPrevRadius;
     SkScalar                              fPrevCenterX;
     SkScalar                              fPrevIntervalLength;
-    typedef GrGLVertexEffect INHERITED;
+    typedef GrGLGeometryProcessor INHERITED;
 };
 
 GLDashingCircleEffect::GLDashingCircleEffect(const GrBackendEffectFactory& factory,
@@ -517,9 +528,7 @@
     builder->addVarying(kVec2f_GrSLType, "Coord", &vsCoordName, &fsCoordName);
 
     GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-    const SkString* attr0Name =
-        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
+    vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dce.inCoord().c_str());
 
     // transforms all points so that we can compare them to our test circle
     GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
@@ -582,14 +591,15 @@
 
 DashingCircleEffect::DashingCircleEffect(GrEffectEdgeType edgeType, const DashInfo& info,
                                          SkScalar radius)
-    : fEdgeType(edgeType) {
+    : fEdgeType(edgeType)
+    , fInCoord(this->addVertexAttrib(GrShaderVar("inCoord",
+                                                 kVec2f_GrSLType,
+                                                 GrShaderVar::kAttribute_TypeModifier))) {
     SkScalar onLen = info.fIntervals[0];
     SkScalar offLen = info.fIntervals[1];
     fIntervalLength = onLen + offLen;
     fRadius = radius;
     fCenterX = SkScalarHalf(offLen);
-
-    this->addVertexAttrib(kVec2f_GrSLType);
 }
 
 bool DashingCircleEffect::onIsEqual(const GrEffect& other) const {
@@ -635,7 +645,7 @@
  * line at the origin then shifted to the right by half the off interval. The line then goes in the
  * positive x direction.
  */
-class DashingLineEffect : public GrVertexEffect {
+class DashingLineEffect : public GrGeometryProcessor {
 public:
     typedef SkPathEffect::DashInfo DashInfo;
 
@@ -645,6 +655,8 @@
 
     static const char* Name() { return "DashingEffect"; }
 
+    const GrShaderVar& inCoord() const { return fInCoord; }
+
     GrEffectEdgeType getEdgeType() const { return fEdgeType; }
 
     const SkRect& getRect() const { return fRect; }
@@ -663,17 +675,18 @@
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
 
     GrEffectEdgeType    fEdgeType;
+    const GrShaderVar&  fInCoord;
     SkRect              fRect;
     SkScalar            fIntervalLength;
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrGeometryProcessor INHERITED;
 };
 
 //////////////////////////////////////////////////////////////////////////////
 
-class GLDashingLineEffect : public GrGLVertexEffect {
+class GLDashingLineEffect : public GrGLGeometryProcessor {
 public:
     GLDashingLineEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
@@ -694,7 +707,7 @@
     GrGLProgramDataManager::UniformHandle fIntervalUniform;
     SkRect                                fPrevRect;
     SkScalar                              fPrevIntervalLength;
-    typedef GrGLVertexEffect INHERITED;
+    typedef GrGLGeometryProcessor INHERITED;
 };
 
 GLDashingLineEffect::GLDashingLineEffect(const GrBackendEffectFactory& factory,
@@ -729,9 +742,7 @@
     const char *vsCoordName, *fsCoordName;
     builder->addVarying(kVec2f_GrSLType, "Coord", &vsCoordName, &fsCoordName);
     GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-    const SkString* attr0Name =
-        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
+    vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, de.inCoord().c_str());
 
     // transforms all points so that we can compare them to our test rect
     GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
@@ -801,15 +812,16 @@
 
 DashingLineEffect::DashingLineEffect(GrEffectEdgeType edgeType, const DashInfo& info,
                                      SkScalar strokeWidth)
-    : fEdgeType(edgeType) {
+    : fEdgeType(edgeType)
+    , fInCoord(this->addVertexAttrib(GrShaderVar("inCoord",
+                                                 kVec2f_GrSLType,
+                                                 GrShaderVar::kAttribute_TypeModifier))) {
     SkScalar onLen = info.fIntervals[0];
     SkScalar offLen = info.fIntervals[1];
     SkScalar halfOffLen = SkScalarHalf(offLen);
     SkScalar halfStroke = SkScalarHalf(strokeWidth);
     fIntervalLength = onLen + offLen;
     fRect.set(halfOffLen, -halfStroke, halfOffLen + onLen, halfStroke);
-
-    this->addVertexAttrib(kVec2f_GrSLType);
 }
 
 bool DashingLineEffect::onIsEqual(const GrEffect& other) const {
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
index eaaefeb..ee7dd61 100755
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
@@ -10,7 +10,7 @@
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
-#include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLGeometryProcessor.h"
 #include "GrTBackendEffectFactory.h"
 #include "GrTexture.h"
 
@@ -29,7 +29,7 @@
 // Assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2
 #define SK_DistanceFieldAAFactor     "0.7071"
 
-class GrGLDistanceFieldTextureEffect : public GrGLVertexEffect {
+class GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor {
 public:
     GrGLDistanceFieldTextureEffect(const GrBackendEffectFactory& factory,
                                    const GrDrawEffect& drawEffect)
@@ -43,13 +43,13 @@
                           const char* inputColor,
                           const TransformedCoordsArray&,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        SkASSERT(1 == drawEffect.castEffect<GrDistanceFieldTextureEffect>().numVertexAttribs());
+        const GrDistanceFieldTextureEffect& dfTexEffect =
+                                              drawEffect.castEffect<GrDistanceFieldTextureEffect>();
+        SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
 
         GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
         SkAssertResult(fsBuilder->enableFeature(
                 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
-        const GrDistanceFieldTextureEffect& dfTexEffect =
-                                              drawEffect.castEffect<GrDistanceFieldTextureEffect>();
 
         SkString fsCoordName;
         const char* vsCoordName;
@@ -58,9 +58,7 @@
         fsCoordName = fsCoordNamePtr;
 
         GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-        const SkString* attr0Name =
-            vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-        vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
+        vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
 
         const char* textureSizeUniName = NULL;
         fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
@@ -165,7 +163,7 @@
     GrGLProgramDataManager::UniformHandle fLuminanceUni;
     float                                 fLuminance;
 
-    typedef GrGLVertexEffect INHERITED;
+    typedef GrGLGeometryProcessor INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -183,13 +181,15 @@
     , fGammaTextureAccess(gamma, gammaParams)
     , fLuminance(luminance)
 #endif
-    , fFlags(flags & kNonLCD_DistanceFieldEffectMask) {
+    , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
+    , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
+                                                         kVec2f_GrSLType,
+                                                         GrShaderVar::kAttribute_TypeModifier))) {
     SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
     this->addTextureAccess(&fTextureAccess);
 #ifdef SK_GAMMA_APPLY_TO_A8
     this->addTextureAccess(&fGammaTextureAccess);
 #endif
-    this->addVertexAttrib(kVec2f_GrSLType);
 }
 
 bool GrDistanceFieldTextureEffect::onIsEqual(const GrEffect& other) const {
@@ -257,7 +257,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-class GrGLDistanceFieldLCDTextureEffect : public GrGLVertexEffect {
+class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor {
 public:
     GrGLDistanceFieldLCDTextureEffect(const GrBackendEffectFactory& factory,
                                       const GrDrawEffect& drawEffect)
@@ -271,10 +271,9 @@
                           const char* inputColor,
                           const TransformedCoordsArray&,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        SkASSERT(1 == drawEffect.castEffect<GrDistanceFieldLCDTextureEffect>().numVertexAttribs());
-
         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
                                            drawEffect.castEffect<GrDistanceFieldLCDTextureEffect>();
+        SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
 
         SkString fsCoordName;
         const char* vsCoordName;
@@ -283,9 +282,7 @@
         fsCoordName = fsCoordNamePtr;
 
         GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-        const SkString* attr0Name =
-            vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-        vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
+        vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
 
         const char* textureSizeUniName = NULL;
         // width, height, 1/(3*width)
@@ -443,7 +440,7 @@
     GrGLProgramDataManager::UniformHandle fTextColorUni;
     SkColor                               fTextColor;
 
-    typedef GrGLVertexEffect INHERITED;
+    typedef GrGLGeometryProcessor INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -456,12 +453,14 @@
     : fTextureAccess(texture, params)
     , fGammaTextureAccess(gamma, gParams)
     , fTextColor(textColor)
-    , fFlags(flags & kLCD_DistanceFieldEffectMask) {
+    , fFlags(flags & kLCD_DistanceFieldEffectMask)
+    , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
+                                                         kVec2f_GrSLType,
+                                                         GrShaderVar::kAttribute_TypeModifier))) {
     SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
         
     this->addTextureAccess(&fTextureAccess);
     this->addTextureAccess(&fGammaTextureAccess);
-    this->addVertexAttrib(kVec2f_GrSLType);
 }
 
 bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrEffect& other) const {
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.h b/src/gpu/effects/GrDistanceFieldTextureEffect.h
index dca1949..5f08eda 100644
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.h
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.h
@@ -9,7 +9,7 @@
 #define GrDistanceFieldTextureEffect_DEFINED
 
 #include "GrEffect.h"
-#include "GrVertexEffect.h"
+#include "GrGeometryProcessor.h"
 
 class GrGLDistanceFieldTextureEffect;
 class GrGLDistanceFieldLCDTextureEffect;
@@ -38,7 +38,7 @@
  * It allows explicit specification of the filtering and wrap modes (GrTextureParams). The input
  * coords are a custom attribute. Gamma correction is handled via a texture LUT.
  */
-class GrDistanceFieldTextureEffect : public GrVertexEffect {
+class GrDistanceFieldTextureEffect : public GrGeometryProcessor {
 public:
 #ifdef SK_GAMMA_APPLY_TO_A8
     static GrEffect* Create(GrTexture* tex, const GrTextureParams& params,
@@ -59,6 +59,8 @@
     static const char* Name() { return "DistanceFieldTexture"; }
 
     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
+
+    const GrShaderVar& inTextureCoords() const { return fInTextureCoords; }
 #ifdef SK_GAMMA_APPLY_TO_A8
     float getLuminance() const { return fLuminance; }
 #endif
@@ -77,12 +79,13 @@
 
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
 
-    GrTextureAccess fTextureAccess;
+    GrTextureAccess    fTextureAccess;
 #ifdef SK_GAMMA_APPLY_TO_A8
-    GrTextureAccess fGammaTextureAccess;
-    float           fLuminance;
+    GrTextureAccess    fGammaTextureAccess;
+    float              fLuminance;
 #endif
-    uint32_t        fFlags;
+    uint32_t           fFlags;
+    const GrShaderVar& fInTextureCoords;
 
     GR_DECLARE_EFFECT_TEST;
 
@@ -95,7 +98,7 @@
  * It allows explicit specification of the filtering and wrap modes (GrTextureParams). The input
  * coords are a custom attribute. Gamma correction is handled via a texture LUT.
  */
-class GrDistanceFieldLCDTextureEffect : public GrVertexEffect {
+class GrDistanceFieldLCDTextureEffect : public GrGeometryProcessor {
 public:
     static GrEffect* Create(GrTexture* tex, const GrTextureParams& params,
                             GrTexture* gamma, const GrTextureParams& gammaParams, 
@@ -108,6 +111,7 @@
 
     static const char* Name() { return "DistanceFieldLCDTexture"; }
 
+    const GrShaderVar& inTextureCoords() const { return fInTextureCoords; }
     virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
     GrColor getTextColor() const { return fTextColor; }
     uint32_t getFlags() const { return fFlags; }
@@ -124,10 +128,11 @@
 
     virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE;
 
-    GrTextureAccess fTextureAccess;
-    GrTextureAccess fGammaTextureAccess;
-    GrColor         fTextColor;
-    uint32_t        fFlags;
+    GrTextureAccess    fTextureAccess;
+    GrTextureAccess    fGammaTextureAccess;
+    GrColor            fTextColor;
+    uint32_t           fFlags;
+    const GrShaderVar& fInTextureCoords;
 
     GR_DECLARE_EFFECT_TEST;
 
diff --git a/src/gpu/effects/GrGeometryProcessor.h b/src/gpu/effects/GrGeometryProcessor.h
new file mode 100644
index 0000000..0e1c80c
--- /dev/null
+++ b/src/gpu/effects/GrGeometryProcessor.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGeometryProcessor_DEFINED
+#define GrGeometryProcessor_DEFINED
+
+#include "GrEffect.h"
+
+/**
+ * If an effect needs specialized vertex shader code, then it must inherit from this class.
+ * Otherwise it won't be able to add vertex attribs, and it will be given a vertexless shader
+ * program in emitCode.
+ */
+class GrGeometryProcessor : public GrEffect {
+public:
+    GrGeometryProcessor() { fRequiresVertexShader = true; }
+
+protected:
+    /**
+     * Subclasses call this from their constructor to register vertex attributes (at most
+     * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
+     * immutable.
+     *
+     * We return a reference to the added var so that derived classes can name it nicely and use it
+     * in shader code.
+     */
+    const GrShaderVar& addVertexAttrib(const GrShaderVar& var) {
+        SkASSERT(GrShaderVar::kAttribute_TypeModifier == var.getTypeModifier());
+        SkASSERT(fVertexAttribs.count() < kMaxVertexAttribs);
+        return fVertexAttribs.push_back(var);
+    }
+
+private:
+    typedef GrEffect INHERITED;
+};
+
+#endif
diff --git a/src/gpu/effects/GrVertexEffect.h b/src/gpu/effects/GrVertexEffect.h
deleted file mode 100644
index 323c85e..0000000
--- a/src/gpu/effects/GrVertexEffect.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2013 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrVertexEffect_DEFINED
-#define GrVertexEffect_DEFINED
-
-#include "GrEffect.h"
-
-/**
- * If an effect needs specialized vertex shader code, then it must inherit from this class.
- * Otherwise it won't be able to add vertex attribs, and it might be given a vertexless shader
- * program in emitCode.
- */
-class GrVertexEffect : public GrEffect {
-public:
-    GrVertexEffect() { fRequiresVertexShader = true; }
-
-protected:
-    /**
-     * Subclasses call this from their constructor to register vertex attributes (at most
-     * kMaxVertexAttribs). This must only be called from the constructor because GrEffects are
-     * immutable.
-     */
-    void addVertexAttrib(GrSLType type) {
-        SkASSERT(fVertexAttribTypes.count() < kMaxVertexAttribs);
-        fVertexAttribTypes.push_back(type);
-    }
-
-private:
-    typedef GrEffect INHERITED;
-};
-
-#endif
diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h
index 88aa4cd..e7d847d 100644
--- a/src/gpu/gl/GrGLEffect.h
+++ b/src/gpu/gl/GrGLEffect.h
@@ -34,7 +34,7 @@
 
 class GrDrawEffect;
 class GrGLTexture;
-class GrGLVertexEffect;
+class GrGLGeometryProcessor;
 
 class GrGLEffect {
 
@@ -90,14 +90,14 @@
     static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
 
     /** Used by the system when generating shader code, to see if this effect can be downcasted to
-        the internal GrGLVertexEffect type */
+        the internal GrGLGeometryProcessor type */
     bool isVertexEffect() const { return fIsVertexEffect; }
 
 protected:
     const GrBackendEffectFactory& fFactory;
 
 private:
-    friend class GrGLVertexEffect; // to set fIsVertexEffect
+    friend class GrGLGeometryProcessor; // to set fIsVertexEffect
 
     bool fIsVertexEffect;
 };
diff --git a/src/gpu/gl/GrGLVertexEffect.h b/src/gpu/gl/GrGLGeometryProcessor.h
similarity index 84%
rename from src/gpu/gl/GrGLVertexEffect.h
rename to src/gpu/gl/GrGLGeometryProcessor.h
index 2e82fbc..4b9bd44 100644
--- a/src/gpu/gl/GrGLVertexEffect.h
+++ b/src/gpu/gl/GrGLGeometryProcessor.h
@@ -5,8 +5,8 @@
  * found in the LICENSE file.
  */
 
-#ifndef GrGLVertexEffect_DEFINED
-#define GrGLVertexEffect_DEFINED
+#ifndef GrGLGeometryProcessor_DEFINED
+#define GrGLGeometryProcessor_DEFINED
 
 #include "GrGLEffect.h"
 
@@ -15,9 +15,9 @@
  * from this class. Since paths don't have vertices, this class is only meant to be used internally
  * by skia, for special cases.
  */
-class GrGLVertexEffect : public GrGLEffect {
+class GrGLGeometryProcessor : public GrGLEffect {
 public:
-    GrGLVertexEffect(const GrBackendEffectFactory& factory)
+    GrGLGeometryProcessor(const GrBackendEffectFactory& factory)
         : INHERITED(factory) { fIsVertexEffect = true; }
 
     /**
@@ -41,7 +41,7 @@
                           const char* inputColor,
                           const TransformedCoordsArray& coords,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        SkFAIL("GrGLVertexEffect requires GrGLFullProgramBuilder* overload for emitCode().");
+        SkFAIL("GrGLGeometryProcessor requires GrGLFullProgramBuilder* overload for emitCode().");
     }
 
 
diff --git a/src/gpu/gl/GrGLProgramEffects.cpp b/src/gpu/gl/GrGLProgramEffects.cpp
index 98e8138..369ec10 100644
--- a/src/gpu/gl/GrGLProgramEffects.cpp
+++ b/src/gpu/gl/GrGLProgramEffects.cpp
@@ -11,7 +11,7 @@
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLPathRendering.h"
 #include "gl/builders/GrGLProgramBuilder.h"
-#include "gl/GrGLVertexEffect.h"
+#include "gl/GrGLGeometryProcessor.h"
 #include "gl/GrGpuGL.h"
 
 typedef GrGLProgramEffects::TransformedCoords TransformedCoords;
@@ -123,7 +123,7 @@
 
     uint32_t textureKey = GrGLProgramEffects::GenTextureKey(drawEffect, caps);
     uint32_t transformKey = GrGLProgramEffects::GenTransformKey(drawEffect);
-    uint32_t attribKey = GrGLProgramEffects::GenAttribKey(drawEffect);
+    uint32_t attribKey = GrGLProgramEffects::GenAttribKey(drawEffect.castEffect<GrEffect>());
     uint32_t classID = drawEffect.effect()->getFactory().effectClassID();
 
     // Currently we allow 16 bits for each of the above portions of the meta-key. Fail if they
@@ -139,14 +139,14 @@
     return true;
 }
 
-uint32_t GrGLProgramEffects::GenAttribKey(const GrDrawEffect& drawEffect) {
+uint32_t GrGLProgramEffects::GenAttribKey(const GrEffect& effect) {
     uint32_t key = 0;
-    int numAttributes = drawEffect.getVertexAttribIndexCount();
+
+    const GrEffect::VertexAttribArray& vars = effect.getVertexAttribs();
+    int numAttributes = vars.count();
     SkASSERT(numAttributes <= 2);
-    const int* attributeIndices = drawEffect.getVertexAttribIndices();
     for (int a = 0; a < numAttributes; ++a) {
-        uint32_t value = attributeIndices[a] << 3 * a;
-        SkASSERT(0 == (value & key)); // keys for each attribute ought not to overlap
+        uint32_t value = 1 << a;
         key |= value;
     }
     return key;
@@ -279,7 +279,7 @@
     vsBuilder->codeAppend(openBrace.c_str());
 
     if (glEffect->isVertexEffect()) {
-        GrGLVertexEffect* vertexEffect = static_cast<GrGLVertexEffect*>(glEffect);
+        GrGLGeometryProcessor* vertexEffect = static_cast<GrGLGeometryProcessor*>(glEffect);
         vertexEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers);
     } else {
         glEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers);
@@ -478,7 +478,7 @@
     SkSTArray<2, TransformedCoords> coords(effect->numTransforms());
     SkSTArray<4, TextureSampler> samplers(effect->numTextures());
 
-    SkASSERT(0 == stage.getVertexAttribIndexCount());
+    SkASSERT(0 == effect->getVertexAttribs().count());
     this->setupPathTexGen(builder, drawEffect, &coords);
     this->emitSamplers(builder, effect, &samplers);
 
diff --git a/src/gpu/gl/GrGLProgramEffects.h b/src/gpu/gl/GrGLProgramEffects.h
index daaebd6..79afa0a 100644
--- a/src/gpu/gl/GrGLProgramEffects.h
+++ b/src/gpu/gl/GrGLProgramEffects.h
@@ -114,7 +114,7 @@
     /**
      * Helpers for GenEffectMetaKey.
      */
-    static uint32_t GenAttribKey(const GrDrawEffect&);
+    static uint32_t GenAttribKey(const GrEffect&);
     static uint32_t GenTransformKey(const GrDrawEffect&);
     static uint32_t GenTextureKey(const GrDrawEffect&, const GrGLCaps&);
 
diff --git a/src/gpu/gl/GrGLShaderVar.h b/src/gpu/gl/GrGLShaderVar.h
index 68c4bbd..8e7e36e 100644
--- a/src/gpu/gl/GrGLShaderVar.h
+++ b/src/gpu/gl/GrGLShaderVar.h
@@ -10,43 +10,15 @@
 
 #include "GrGLContext.h"
 #include "GrGLSL.h"
-#include "SkString.h"
+#include "GrShaderVar.h"
 
 #define USE_UNIFORM_FLOAT_ARRAYS true
 
 /**
  * Represents a variable in a shader
  */
-class GrGLShaderVar {
+class GrGLShaderVar : public GrShaderVar {
 public:
-
-    /**
-     * Early versions of GLSL have Varying and Attribute; those are later
-     * deprecated, but we still need to know whether a Varying variable
-     * should be treated as In or Out.
-     */
-    enum TypeModifier {
-        kNone_TypeModifier,
-        kOut_TypeModifier,
-        kIn_TypeModifier,
-        kInOut_TypeModifier,
-        kUniform_TypeModifier,
-        kAttribute_TypeModifier,
-        kVaryingIn_TypeModifier,
-        kVaryingOut_TypeModifier
-    };
-
-    enum Precision {
-        kLow_Precision,         // lowp
-        kMedium_Precision,      // mediump
-        kHigh_Precision,        // highp
-        kDefault_Precision,     // Default for the current context. We make
-                                // fragment shaders default to mediump on ES2
-                                // because highp support is not guaranteed (and
-                                // we haven't been motivated to test for it).
-                                // Otherwise, highp.
-    };
-
     /**
      * See GL_ARB_fragment_coord_conventions.
      */
@@ -58,36 +30,43 @@
     /**
      * Defaults to a float with no precision specifier
      */
-    GrGLShaderVar() {
-        fType = kFloat_GrSLType;
-        fTypeModifier = kNone_TypeModifier;
-        fCount = kNonArray;
-        fPrecision = kDefault_Precision;
-        fOrigin = kDefault_Origin;
-        fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
+    GrGLShaderVar()
+        : GrShaderVar()
+        , fOrigin(kDefault_Origin)
+        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
     }
 
     GrGLShaderVar(const char* name, GrSLType type, int arrayCount = kNonArray,
-                  Precision precision = kDefault_Precision) {
+                  Precision precision = kDefault_Precision)
+        : GrShaderVar(name, type, arrayCount, precision)
+        , fOrigin(kDefault_Origin)
+        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
         SkASSERT(kVoid_GrSLType != type);
-        fType = type;
-        fTypeModifier = kNone_TypeModifier;
-        fCount = arrayCount;
-        fPrecision = precision;
         fOrigin = kDefault_Origin;
         fUseUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS;
-        fName = name;
+    }
+
+    GrGLShaderVar(const char* name, GrSLType type, TypeModifier typeModifier,
+                  int arrayCount = kNonArray, Precision precision = kDefault_Precision)
+        : GrShaderVar(name, type, typeModifier, arrayCount, precision)
+        , fOrigin(kDefault_Origin)
+        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
+        SkASSERT(kVoid_GrSLType != type);
+    }
+
+    GrGLShaderVar(const GrShaderVar& var)
+        : GrShaderVar(var)
+        , fOrigin(kDefault_Origin)
+        , fUseUniformFloatArrays(USE_UNIFORM_FLOAT_ARRAYS) {
+        SkASSERT(kVoid_GrSLType != var.getType());
     }
 
     GrGLShaderVar(const GrGLShaderVar& var)
-        : fType(var.fType)
-        , fTypeModifier(var.fTypeModifier)
-        , fName(var.fName)
-        , fCount(var.fCount)
-        , fPrecision(var.fPrecision)
+        : GrShaderVar(var.c_str(), var.getType(), var.getTypeModifier(),
+                      var.getArrayCount(), var.getPrecision())
         , fOrigin(var.fOrigin)
         , fUseUniformFloatArrays(var.fUseUniformFloatArrays) {
-        SkASSERT(kVoid_GrSLType != var.fType);
+        SkASSERT(kVoid_GrSLType != var.getType());
     }
 
     /**
@@ -108,11 +87,7 @@
              Origin origin = kDefault_Origin,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
         SkASSERT(kVoid_GrSLType != type);
-        fType = type;
-        fTypeModifier = typeModifier;
-        fName = name;
-        fCount = kNonArray;
-        fPrecision = precision;
+        INHERITED::set(type, typeModifier, name, precision);
         fOrigin = origin;
         fUseUniformFloatArrays = useUniformFloatArrays;
     }
@@ -127,11 +102,7 @@
              Origin origin = kDefault_Origin,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
         SkASSERT(kVoid_GrSLType != type);
-        fType = type;
-        fTypeModifier = typeModifier;
-        fName = name;
-        fCount = kNonArray;
-        fPrecision = precision;
+        INHERITED::set(type, typeModifier, name, precision);
         fOrigin = origin;
         fUseUniformFloatArrays = useUniformFloatArrays;
     }
@@ -147,11 +118,7 @@
              Origin origin = kDefault_Origin,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
         SkASSERT(kVoid_GrSLType != type);
-        fType = type;
-        fTypeModifier = typeModifier;
-        fName = name;
-        fCount = count;
-        fPrecision = precision;
+        INHERITED::set(type, typeModifier, name, count, precision);
         fOrigin = origin;
         fUseUniformFloatArrays = useUniformFloatArrays;
     }
@@ -167,83 +134,12 @@
              Origin origin = kDefault_Origin,
              bool useUniformFloatArrays = USE_UNIFORM_FLOAT_ARRAYS) {
         SkASSERT(kVoid_GrSLType != type);
-        fType = type;
-        fTypeModifier = typeModifier;
-        fName = name;
-        fCount = count;
-        fPrecision = precision;
+        INHERITED::set(type, typeModifier, name, count, precision);
         fOrigin = origin;
         fUseUniformFloatArrays = useUniformFloatArrays;
     }
 
     /**
-     * Is the var an array.
-     */
-    bool isArray() const { return kNonArray != fCount; }
-    /**
-     * Is this an unsized array, (i.e. declared with []).
-     */
-    bool isUnsizedArray() const { return kUnsizedArray == fCount; }
-    /**
-     * Get the array length of the var.
-     */
-    int getArrayCount() const { return fCount; }
-    /**
-     * Set the array length of the var
-     */
-    void setArrayCount(int count) { fCount = count; }
-    /**
-     * Set to be a non-array.
-     */
-    void setNonArray() { fCount = kNonArray; }
-    /**
-     * Set to be an unsized array.
-     */
-    void setUnsizedArray() { fCount = kUnsizedArray; }
-
-    /**
-     * Access the var name as a writable string
-     */
-    SkString* accessName() { return &fName; }
-    /**
-     * Set the var name
-     */
-    void setName(const SkString& n) { fName = n; }
-    void setName(const char* n) { fName = n; }
-
-    /**
-     * Get the var name.
-     */
-    const SkString& getName() const { return fName; }
-
-    /**
-     * Shortcut for this->getName().c_str();
-     */
-    const char* c_str() const { return this->getName().c_str(); }
-
-    /**
-     * Get the type of the var
-     */
-    GrSLType getType() const { return fType; }
-    /**
-     * Set the type of the var
-     */
-    void setType(GrSLType type) { fType = type; }
-
-    TypeModifier getTypeModifier() const { return fTypeModifier; }
-    void setTypeModifier(TypeModifier type) { fTypeModifier = type; }
-
-    /**
-     * Get the precision of the var
-     */
-    Precision getPrecision() const { return fPrecision; }
-
-    /**
-     * Set the precision of the var
-     */
-    void setPrecision(Precision p) { fPrecision = p; }
-
-    /**
      * Get the origin of the var
      */
     Origin getOrigin() const { return fOrigin; }
@@ -346,15 +242,12 @@
         }
     }
 
-    GrSLType        fType;
-    TypeModifier    fTypeModifier;
-    SkString        fName;
-    int             fCount;
-    Precision       fPrecision;
     Origin          fOrigin;
     /// Work around driver bugs on some hardware that don't correctly
     /// support uniform float []
     bool            fUseUniformFloatArrays;
+
+    typedef GrShaderVar INHERITED;
 };
 
 #endif
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index 01269aa..6eaf575 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -228,6 +228,7 @@
         int                     fCurrentIndex;
         const GrEffectStage*    fEffectStage;
     } fCodeStage;
+
 private:
 
     /**
diff --git a/src/gpu/gl/builders/GrGLShaderBuilder.h b/src/gpu/gl/builders/GrGLShaderBuilder.h
index 4921fd3..3abd0c0 100644
--- a/src/gpu/gl/builders/GrGLShaderBuilder.h
+++ b/src/gpu/gl/builders/GrGLShaderBuilder.h
@@ -12,7 +12,6 @@
 #include "gl/GrGLProgramEffects.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLProgramDataManager.h"
-#include "GrAllocator.h"
 #include "GrBackendEffectFactory.h"
 #include "GrColor.h"
 #include "GrEffect.h"
diff --git a/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp b/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
index 6abc085..f06c646 100644
--- a/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
@@ -14,8 +14,8 @@
 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
 
 namespace {
-inline const char* color_attribute_name() { return "aColor"; }
-inline const char* coverage_attribute_name() { return "aCoverage"; }
+inline const char* color_attribute_name() { return "inColor"; }
+inline const char* coverage_attribute_name() { return "inCoverage"; }
 }
 
 GrGLVertexShaderBuilder::GrGLVertexShaderBuilder(GrGLFullProgramBuilder* program)
@@ -23,53 +23,29 @@
     , fPositionVar(NULL)
     , fLocalCoordsVar(NULL) {
 }
-bool GrGLVertexShaderBuilder::addAttribute(GrSLType type, const char* name) {
+bool GrGLVertexShaderBuilder::addAttribute(const GrShaderVar& var) {
+    SkASSERT(GrShaderVar::kAttribute_TypeModifier == var.getTypeModifier());
     for (int i = 0; i < fInputs.count(); ++i) {
         const GrGLShaderVar& attr = fInputs[i];
         // if attribute already added, don't add it again
-        if (attr.getName().equals(name)) {
+        if (attr.getName().equals(var.getName())) {
             return false;
         }
     }
-    fInputs.push_back().set(type, GrGLShaderVar::kAttribute_TypeModifier, name);
-    return true;
-}
-
-bool GrGLVertexShaderBuilder::addEffectAttribute(int attributeIndex,
-                                               GrSLType type,
-                                               const SkString& name) {
-    if (!this->addAttribute(type, name.c_str())) {
-        return false;
-    }
-
-    fEffectAttributes.push_back().set(attributeIndex, name);
+    fInputs.push_back(var);
     return true;
 }
 
 void GrGLVertexShaderBuilder::emitAttributes(const GrEffectStage& stage) {
-    int numAttributes = stage.getVertexAttribIndexCount();
-    const int* attributeIndices = stage.getVertexAttribIndices();
+    const GrEffect& effect = *stage.getEffect();
+    const GrEffect::VertexAttribArray& vars =
+            effect.getVertexAttribs();
+    int numAttributes = vars.count();
     for (int a = 0; a < numAttributes; ++a) {
-        // TODO: Make addAttribute mangle the name.
-        SkString attributeName("aAttr");
-        attributeName.appendS32(attributeIndices[a]);
-        this->addEffectAttribute(attributeIndices[a],
-                                 stage.getEffect()->vertexAttribType(a),
-                                 attributeName);
+        this->addAttribute(vars[a]);
     }
 }
 
-const SkString* GrGLVertexShaderBuilder::getEffectAttributeName(int attributeIndex) const {
-    const AttributePair* attribEnd = fEffectAttributes.end();
-    for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) {
-        if (attrib->fIndex == attributeIndex) {
-            return &attrib->fName;
-        }
-    }
-
-    return NULL;
-}
-
 void GrGLVertexShaderBuilder::addVarying(GrSLType type, const char* name, const char** vsOutName) {
     fOutputs.push_back();
     fOutputs.back().setType(type);
@@ -107,10 +83,27 @@
                                    coverage_attribute_name()));
     }
 
-    const AttributePair* attribEnd = fEffectAttributes.end();
-    for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) {
-         GL_CALL(BindAttribLocation(programId, attrib->fIndex, attrib->fName.c_str()));
+    // We pull the current state of attributes off of drawstate and bind them in order
+    const GrRODrawState* ds = fProgramBuilder->gpu()->drawState();
+    const GrVertexAttrib* vaPtr = ds->getVertexAttribs();
+    const int vaCount = ds->getVertexAttribCount();
+
+    int i = fEffectAttribOffset;
+    for (int index = 0; index < vaCount; index++) {
+        if (kEffect_GrVertexAttribBinding != vaPtr[index].fBinding) {
+            continue;
+        }
+        SkASSERT(index != header.fPositionAttributeIndex &&
+                 index != header.fLocalCoordAttributeIndex &&
+                 index != header.fColorAttributeIndex &&
+                 index != header.fCoverageAttributeIndex);
+        // We should never find another effect attribute if we have bound everything
+        SkASSERT(i < fInputs.count());
+        GL_CALL(BindAttribLocation(programId, index, fInputs[i].c_str()));
+        i++;
     }
+    // Make sure we bound everything
+    SkASSERT(fInputs.count() == i);
 }
 
 bool GrGLVertexShaderBuilder::compileAndAttachShaders(GrGLuint programId,
@@ -183,7 +176,9 @@
     }
 
     if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) {
-        this->addAttribute(kVec4f_GrSLType, color_attribute_name());
+        this->addAttribute(GrShaderVar(color_attribute_name(),
+                                       kVec4f_GrSLType,
+                                       GrShaderVar::kAttribute_TypeModifier));
         const char *vsName, *fsName;
         fFullProgramBuilder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
         this->codeAppendf("\t%s = %s;\n", vsName, color_attribute_name());
@@ -191,10 +186,13 @@
     }
 
     if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) {
-        this->addAttribute(kVec4f_GrSLType, coverage_attribute_name());
+        this->addAttribute(GrShaderVar(coverage_attribute_name(),
+                                       kVec4f_GrSLType,
+                                       GrShaderVar::kAttribute_TypeModifier));
         const char *vsName, *fsName;
         fFullProgramBuilder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
         this->codeAppendf("\t%s = %s;\n", vsName, coverage_attribute_name());
         *coverage = fsName;
     }
+    fEffectAttribOffset = fInputs.count();
 }
diff --git a/src/gpu/gl/builders/GrGLVertexShaderBuilder.h b/src/gpu/gl/builders/GrGLVertexShaderBuilder.h
index c576f57..434e7e6 100644
--- a/src/gpu/gl/builders/GrGLVertexShaderBuilder.h
+++ b/src/gpu/gl/builders/GrGLVertexShaderBuilder.h
@@ -16,14 +16,6 @@
     GrGLVertexShaderBuilder(GrGLFullProgramBuilder* program);
 
     /*
-     * Add attribute will push a new attribute onto the end.  It will also assert if there is
-     * a duplicate attribute
-     */
-    bool addAttribute(GrSLType type, const char* name);
-
-    bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name);
-
-    /*
      * this call is only for GrGLProgramEffects' internal use
      */
     void emitAttributes(const GrEffectStage& stage);
@@ -47,6 +39,12 @@
 
 private:
     /*
+     * Add attribute will push a new attribute onto the end.  It will also assert if there is
+     * a duplicate attribute
+     */
+    bool addAttribute(const GrShaderVar& var);
+
+    /*
      * Internal call for GrGLFullProgramBuilder.addVarying
      */
     void addVarying(GrSLType type,
@@ -69,9 +67,9 @@
         SkString fName;
     };
 
-    SkSTArray<10, AttributePair, true>  fEffectAttributes;
     GrGLShaderVar*                      fPositionVar;
     GrGLShaderVar*                      fLocalCoordsVar;
+    int                                 fEffectAttribOffset;
 
     friend class GrGLFullProgramBuilder;
 
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index a641fe2..931789c 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -162,6 +162,37 @@
     return true;
 }
 
+// TODO clean this up, we have to do this to test geometry processors but there has got to be
+// a better way.  In the mean time, we actually fill out these generic vertex attribs below with
+// the correct vertex attribs from the GP.  We have to ensure, however, we don't try to add more
+// than two attributes.
+GrVertexAttrib genericVertexAttribs[] = {
+    { kVec2f_GrVertexAttribType, 0,   kPosition_GrVertexAttribBinding },
+    { kVec2f_GrVertexAttribType, 0,   kEffect_GrVertexAttribBinding },
+    { kVec2f_GrVertexAttribType, 0,   kEffect_GrVertexAttribBinding }
+};
+
+/*
+ * convert sl type to vertexattrib type, not a complete implementation, only use for debugging
+ */
+GrVertexAttribType convert_sltype_to_attribtype(GrSLType type) {
+    switch (type) {
+        case kFloat_GrSLType:
+            return kFloat_GrVertexAttribType;
+        case kVec2f_GrSLType:
+            return kVec2f_GrVertexAttribType;
+        case kVec3f_GrSLType:
+            return kVec3f_GrVertexAttribType;
+        case kVec4f_GrSLType:
+            return kVec4f_GrVertexAttribType;
+        default:
+            SkFAIL("Type isn't convertible");
+            return kFloat_GrVertexAttribType;
+    }
+}
+// TODO end test hack
+
+
 bool GrGpuGL::programUnitTest(int maxStages) {
 
     GrTextureDesc dummyDesc;
@@ -197,7 +228,6 @@
 
         int currAttribIndex = 1;  // we need to always leave room for position
         int currTextureCoordSet = 0;
-        int attribIndices[2] = { 0, 0 };
         GrTexture* dummyTextures[] = {dummyTexture1.get(), dummyTexture2.get()};
 
         int numStages = random.nextULessThan(maxStages + 1);
@@ -220,19 +250,32 @@
                                                                                 *this->caps(),
                                                                                 dummyTextures));
                 SkASSERT(effect);
-
                 // Only geometryProcessor can use vertex shader
                 if (!effect->requiresVertexShader()) {
                     continue;
                 }
 
-                int numAttribs = effect->numVertexAttribs();
-                for (int i = 0; i < numAttribs; ++i) {
-                    attribIndices[i] = currAttribIndex++;
-                }
-                GrEffectStage* stage = SkNEW_ARGS(GrEffectStage,
-                                                  (effect.get(), attribIndices[0], attribIndices[1]));
+                GrEffectStage* stage = SkNEW_ARGS(GrEffectStage, (effect.get()));
                 geometryProcessor.reset(stage);
+
+                // we have to set dummy vertex attribs
+                const GrEffect::VertexAttribArray& v = effect->getVertexAttribs();
+                int numVertexAttribs = v.count();
+
+                SkASSERT(GrEffect::kMaxVertexAttribs == 2 &&
+                         GrEffect::kMaxVertexAttribs >= numVertexAttribs);
+                size_t runningStride = GrVertexAttribTypeSize(genericVertexAttribs[0].fType);
+                for (int i = 0; i < numVertexAttribs; i++) {
+                    genericVertexAttribs[i + 1].fOffset = runningStride;
+                    genericVertexAttribs[i + 1].fType =
+                            convert_sltype_to_attribtype(v[i].getType());
+                    runningStride += GrVertexAttribTypeSize(genericVertexAttribs[i + 1].fType);
+                }
+
+                // update the vertex attributes with the ds
+                GrDrawState* ds = this->drawState();
+                ds->setVertexAttribs<genericVertexAttribs>(numVertexAttribs + 1, runningStride);
+                currAttribIndex = numVertexAttribs + 1;
                 break;
             }
         }
@@ -258,8 +301,7 @@
                 }
                 currTextureCoordSet += numTransforms;
             }
-            GrEffectStage* stage = SkNEW_ARGS(GrEffectStage,
-                                              (effect.get(), attribIndices[0], attribIndices[1]));
+            GrEffectStage* stage = SkNEW_ARGS(GrEffectStage, (effect.get()));
 
             stages[s] = stage;
             ++s;
@@ -288,6 +330,9 @@
         if (NULL == program.get()) {
             return false;
         }
+
+        // We have to reset the drawstate because we might have added a gp
+        this->drawState()->reset();
     }
     return true;
 }