Move VertexBuilder to a GrGLFullShaderBuilder subclass

Removes the VertexBuilder nested class from GrGLShaderBuilder in favor
of a new GrGLFullShaderBuilder subclass, and adds an optional emitCode
overload to GrGLEffect that takes a GrGLFullShaderBuilder. Makes
setData virtual in GrGLEffectArray and adds a GrGLVertexEffectArray
subclass that gets built using a GrGLFullShaderBuilder. Also adds a
new GrGLVertexEffect subclass that makes the GrGLFullShaderBuilder
overload required for emitCode, and updates GrGLEffects to inherit
from GrGLVertexEffect where needed.

R=bsalomon@google.com

Author: cdalton@nvidia.com

Review URL: https://codereview.chromium.org/25474006

git-svn-id: http://skia.googlecode.com/svn/trunk/src@11612 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/GrAAConvexPathRenderer.cpp b/gpu/GrAAConvexPathRenderer.cpp
index 78f2045..ebb2f69 100644
--- a/gpu/GrAAConvexPathRenderer.cpp
+++ b/gpu/GrAAConvexPathRenderer.cpp
@@ -20,6 +20,7 @@
 
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
+#include "gl/GrGLVertexEffect.h"
 
 #include "effects/GrVertexEffect.h"
 
@@ -521,29 +522,26 @@
         return GrTBackendEffectFactory<QuadEdgeEffect>::getInstance();
     }
 
-    class GLEffect : public GrGLEffect {
+    class GLEffect : public GrGLVertexEffect {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
             : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLFullShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
-            GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-            SkASSERT(NULL != vertexBuilder);
-
             const char *vsName, *fsName;
             const SkString* attrName =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
             builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
 
             SkAssertResult(builder->enableFeature(
                                               GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
-            vertexBuilder->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
+            builder->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
 
             // keep the derivative instructions outside the conditional
             builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
@@ -565,7 +563,7 @@
             GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
             builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
 
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+            builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
         }
 
         static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
@@ -575,7 +573,7 @@
         virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
 
     private:
-        typedef GrGLEffect INHERITED;
+        typedef GrGLVertexEffect INHERITED;
     };
 
 private:
diff --git a/gpu/GrAARectRenderer.cpp b/gpu/GrAARectRenderer.cpp
index 320b3d7..b2052a8 100644
--- a/gpu/GrAARectRenderer.cpp
+++ b/gpu/GrAARectRenderer.cpp
@@ -8,6 +8,7 @@
 #include "GrAARectRenderer.h"
 #include "GrGpu.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "SkColorPriv.h"
 #include "effects/GrVertexEffect.h"
@@ -39,29 +40,26 @@
         return GrTBackendEffectFactory<GrAlignedRectEffect>::getInstance();
     }
 
-    class GLEffect : public GrGLEffect {
+    class GLEffect : public GrGLVertexEffect {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLFullShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
-            GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-            SkASSERT(NULL != vertexBuilder);
-
             // setup the varying for the Axis aligned rect effect
             //      xy -> interpolated offset
             //      zw -> w/2+0.5, h/2+0.5
             const char *vsRectName, *fsRectName;
-            vertexBuilder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
+            builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
             const SkString* attr0Name =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
 
             // TODO: compute all these offsets, spans, and scales in the VS
             builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
@@ -98,7 +96,7 @@
         virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
 
     private:
-        typedef GrGLEffect INHERITED;
+        typedef GrGLVertexEffect INHERITED;
     };
 
 
@@ -160,37 +158,34 @@
         return GrTBackendEffectFactory<GrRectEffect>::getInstance();
     }
 
-    class GLEffect : public GrGLEffect {
+    class GLEffect : public GrGLVertexEffect {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLFullShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
-            GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-            SkASSERT(NULL != vertexBuilder);
-
             // setup the varying for the center point and the unit vector
             // that points down the height of the rect
             const char *vsRectEdgeName, *fsRectEdgeName;
-            vertexBuilder->addVarying(kVec4f_GrSLType, "RectEdge",
-                                      &vsRectEdgeName, &fsRectEdgeName);
+            builder->addVarying(kVec4f_GrSLType, "RectEdge",
+                                &vsRectEdgeName, &fsRectEdgeName);
             const SkString* attr0Name =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
 
             // setup the varying for width/2+.5 and height/2+.5
             const char *vsWidthHeightName, *fsWidthHeightName;
-            vertexBuilder->addVarying(kVec2f_GrSLType, "WidthHeight",
-                                      &vsWidthHeightName, &fsWidthHeightName);
+            builder->addVarying(kVec2f_GrSLType, "WidthHeight",
+                                &vsWidthHeightName, &fsWidthHeightName);
             const SkString* attr1Name =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
 
             // TODO: compute all these offsets, spans, and scales in the VS
             builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
@@ -234,7 +229,7 @@
         virtual void setData(const GrGLUniformManager& uman, const GrDrawEffect&) SK_OVERRIDE {}
 
     private:
-        typedef GrGLEffect INHERITED;
+        typedef GrGLVertexEffect INHERITED;
     };
 
 
diff --git a/gpu/GrOvalRenderer.cpp b/gpu/GrOvalRenderer.cpp
index 2c923f8..7851265 100644
--- a/gpu/GrOvalRenderer.cpp
+++ b/gpu/GrOvalRenderer.cpp
@@ -10,6 +10,7 @@
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
+#include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
 
 #include "GrDrawState.h"
@@ -88,28 +89,25 @@
 
     inline bool isStroked() const { return fStroke; }
 
-    class GLEffect : public GrGLEffect {
+    class GLEffect : public GrGLVertexEffect {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLFullShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
-            GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-            SkASSERT(NULL != vertexBuilder);
-
             const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleEdgeEffect>();
             const char *vsName, *fsName;
-            vertexBuilder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
+            builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
 
             const SkString* attrName =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
 
             builder->fsCodeAppendf("\tfloat d = length(%s.xy);\n", fsName);
             builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
@@ -132,7 +130,7 @@
         virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
 
     private:
-        typedef GrGLEffect INHERITED;
+        typedef GrGLVertexEffect INHERITED;
     };
 
 
@@ -203,35 +201,32 @@
 
     inline bool isStroked() const { return fStroke; }
 
-    class GLEffect : public GrGLEffect {
+    class GLEffect : public GrGLVertexEffect {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLFullShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
-            GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-            SkASSERT(NULL != vertexBuilder);
-
             const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>();
 
             const char *vsOffsetName, *fsOffsetName;
             const char *vsRadiiName, *fsRadiiName;
 
-            vertexBuilder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName, &fsOffsetName);
+            builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName, &fsOffsetName);
             const SkString* attr0Name =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_str());
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_str());
 
-            vertexBuilder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName);
+            builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName);
             const SkString* attr1Name =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str());
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str());
 
             // for outer curve
             builder->fsCodeAppendf("\tvec2 scaledOffset = %s*%s.xy;\n", fsOffsetName, fsRadiiName);
@@ -269,7 +264,7 @@
         }
 
     private:
-        typedef GrGLEffect INHERITED;
+        typedef GrGLVertexEffect INHERITED;
     };
 
 private:
@@ -347,38 +342,35 @@
 
     inline Mode getMode() const { return fMode; }
 
-    class GLEffect : public GrGLEffect {
+    class GLEffect : public GrGLVertexEffect {
     public:
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLFullShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
-            GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-            SkASSERT(NULL != vertexBuilder);
-
             const DIEllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<DIEllipseEdgeEffect>();
 
             SkAssertResult(builder->enableFeature(
                                               GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
 
             const char *vsOffsetName0, *fsOffsetName0;
-            vertexBuilder->addVarying(kVec2f_GrSLType, "EllipseOffsets0",
+            builder->addVarying(kVec2f_GrSLType, "EllipseOffsets0",
                                       &vsOffsetName0, &fsOffsetName0);
             const SkString* attr0Name =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName0, attr0Name->c_str());
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName0, attr0Name->c_str());
             const char *vsOffsetName1, *fsOffsetName1;
-            vertexBuilder->addVarying(kVec2f_GrSLType, "EllipseOffsets1",
+            builder->addVarying(kVec2f_GrSLType, "EllipseOffsets1",
                                       &vsOffsetName1, &fsOffsetName1);
             const SkString* attr1Name =
-                vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
-            vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName1, attr1Name->c_str());
+                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName1, attr1Name->c_str());
 
             // for outer curve
             builder->fsCodeAppendf("\tvec2 scaledOffset = %s.xy;\n", fsOffsetName0);
@@ -431,7 +423,7 @@
         }
 
     private:
-        typedef GrGLEffect INHERITED;
+        typedef GrGLVertexEffect INHERITED;
     };
 
 private:
diff --git a/gpu/effects/GrBezierEffect.cpp b/gpu/effects/GrBezierEffect.cpp
index 9adf592..4dca884 100644
--- a/gpu/effects/GrBezierEffect.cpp
+++ b/gpu/effects/GrBezierEffect.cpp
@@ -9,13 +9,14 @@
 
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
+#include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
 
-class GrGLConicEffect : public GrGLEffect {
+class GrGLConicEffect : public GrGLVertexEffect {
 public:
     GrGLConicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLFullShaderBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           EffectKey key,
                           const char* outputColor,
@@ -30,7 +31,7 @@
 private:
     GrBezierEdgeType fEdgeType;
 
-    typedef GrGLEffect INHERITED;
+    typedef GrGLVertexEffect INHERITED;
 };
 
 GrGLConicEffect::GrGLConicEffect(const GrBackendEffectFactory& factory,
@@ -40,23 +41,20 @@
     fEdgeType = ce.getEdgeType();
 }
 
-void GrGLConicEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLConicEffect::emitCode(GrGLFullShaderBuilder* builder,
                                const GrDrawEffect& drawEffect,
                                EffectKey key,
                                const char* outputColor,
                                const char* inputColor,
                                const TransformedCoordsArray&,
                                const TextureSamplerArray& samplers) {
-    GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-    SkASSERT(NULL != vertexBuilder);
-
     const char *vsName, *fsName;
 
-    vertexBuilder->addVarying(kVec4f_GrSLType, "ConicCoeffs",
+    builder->addVarying(kVec4f_GrSLType, "ConicCoeffs",
                               &vsName, &fsName);
     const SkString* attr0Name =
-        vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
+        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
 
     builder->fsCodeAppend("\t\tfloat edgeAlpha;\n");
 
@@ -156,11 +154,11 @@
 // Quad
 //////////////////////////////////////////////////////////////////////////////
 
-class GrGLQuadEffect : public GrGLEffect {
+class GrGLQuadEffect : public GrGLVertexEffect {
 public:
     GrGLQuadEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLFullShaderBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           EffectKey key,
                           const char* outputColor,
@@ -175,7 +173,7 @@
 private:
     GrBezierEdgeType fEdgeType;
 
-    typedef GrGLEffect INHERITED;
+    typedef GrGLVertexEffect INHERITED;
 };
 
 GrGLQuadEffect::GrGLQuadEffect(const GrBackendEffectFactory& factory,
@@ -185,23 +183,20 @@
     fEdgeType = ce.getEdgeType();
 }
 
-void GrGLQuadEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLQuadEffect::emitCode(GrGLFullShaderBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               EffectKey key,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) {
-    GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-    SkASSERT(NULL != vertexBuilder);
-
     const char *vsName, *fsName;
 
     const SkString* attrName =
-        vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
     builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
 
-    vertexBuilder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName);
+    builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName);
 
     switch (fEdgeType) {
         case kHairAA_GrBezierEdgeType: {
@@ -248,7 +243,7 @@
     GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha");
     builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
 
-    vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+    builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
 }
 
 GrGLEffect::EffectKey GrGLQuadEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
@@ -290,11 +285,11 @@
 // Cubic
 //////////////////////////////////////////////////////////////////////////////
 
-class GrGLCubicEffect : public GrGLEffect {
+class GrGLCubicEffect : public GrGLVertexEffect {
 public:
     GrGLCubicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLFullShaderBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           EffectKey key,
                           const char* outputColor,
@@ -309,7 +304,7 @@
 private:
     GrBezierEdgeType fEdgeType;
 
-    typedef GrGLEffect INHERITED;
+    typedef GrGLVertexEffect INHERITED;
 };
 
 GrGLCubicEffect::GrGLCubicEffect(const GrBackendEffectFactory& factory,
@@ -319,23 +314,20 @@
     fEdgeType = ce.getEdgeType();
 }
 
-void GrGLCubicEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLCubicEffect::emitCode(GrGLFullShaderBuilder* builder,
                                const GrDrawEffect& drawEffect,
                                EffectKey key,
                                const char* outputColor,
                                const char* inputColor,
                                const TransformedCoordsArray&,
                                const TextureSamplerArray& samplers) {
-    GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-    SkASSERT(NULL != vertexBuilder);
-
     const char *vsName, *fsName;
 
-    vertexBuilder->addVarying(kVec4f_GrSLType, "CubicCoeffs",
+    builder->addVarying(kVec4f_GrSLType, "CubicCoeffs",
                               &vsName, &fsName);
     const SkString* attr0Name =
-        vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
+        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
 
     builder->fsCodeAppend("\t\tfloat edgeAlpha;\n");
 
diff --git a/gpu/effects/GrCustomCoordsTextureEffect.cpp b/gpu/effects/GrCustomCoordsTextureEffect.cpp
index b14de8b..f85a927 100644
--- a/gpu/effects/GrCustomCoordsTextureEffect.cpp
+++ b/gpu/effects/GrCustomCoordsTextureEffect.cpp
@@ -9,34 +9,33 @@
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
+#include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "GrTexture.h"
 
-class GrGLCustomCoordsTextureEffect : public GrGLEffect {
+class GrGLCustomCoordsTextureEffect : public GrGLVertexEffect {
 public:
     GrGLCustomCoordsTextureEffect(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect)
         : INHERITED (factory) {}
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLFullShaderBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           EffectKey key,
                           const char* outputColor,
                           const char* inputColor,
                           const TransformedCoordsArray&,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder->getVertexBuilder();
-        SkASSERT(NULL != vertexBuilder);
         SkASSERT(1 == drawEffect.castEffect<GrCustomCoordsTextureEffect>().numVertexAttribs());
 
         SkString fsCoordName;
         const char* vsVaryingName;
         const char* fsVaryingNamePtr;
-        vertexBuilder->addVarying(kVec2f_GrSLType, "textureCoords", &vsVaryingName, &fsVaryingNamePtr);
+        builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsVaryingName, &fsVaryingNamePtr);
         fsCoordName = fsVaryingNamePtr;
 
         const char* attrName =
-            vertexBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str();
-        vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, attrName);
+            builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str();
+        builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, attrName);
 
         builder->fsCodeAppendf("\t%s = ", outputColor);
         builder->fsAppendTextureLookupAndModulate(inputColor,
@@ -50,7 +49,7 @@
                          const GrDrawEffect& drawEffect) SK_OVERRIDE {}
 
 private:
-    typedef GrGLEffect INHERITED;
+    typedef GrGLVertexEffect INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/gpu/gl/GrGLEffect.h b/gpu/gl/GrGLEffect.h
index 52b1e92..b680738 100644
--- a/gpu/gl/GrGLEffect.h
+++ b/gpu/gl/GrGLEffect.h
@@ -14,8 +14,6 @@
 #include "GrGLShaderVar.h"
 #include "GrGLSL.h"
 
-class GrGLTexture;
-
 /** @file
     This file contains specializations for OpenGL of the shader stages declared in
     include/gpu/GrEffect.h. Objects of type GrGLEffect are responsible for emitting the
@@ -34,6 +32,8 @@
 */
 
 class GrDrawEffect;
+class GrGLTexture;
+class GrGLVertexEffect;
 
 class GrGLEffect {
 
@@ -48,7 +48,10 @@
         kEffectKeyBits = GrBackendEffectFactory::kEffectKeyBits,
     };
 
-    GrGLEffect(const GrBackendEffectFactory& factory) : fFactory(factory) {}
+    GrGLEffect(const GrBackendEffectFactory& factory)
+        : fFactory(factory)
+        , fIsVertexEffect(false) {
+    }
 
     virtual ~GrGLEffect() {}
 
@@ -93,8 +96,17 @@
 
     static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&) { return 0; }
 
+    /** Used by the system when generating shader code, to see if this effect can be downcasted to
+        the internal GrGLVertexEffect type */
+    bool isVertexEffect() const { return fIsVertexEffect; }
+
 protected:
     const GrBackendEffectFactory& fFactory;
+
+private:
+    friend class GrGLVertexEffect; // to set fIsVertexEffect
+
+    bool fIsVertexEffect;
 };
 
 #endif
diff --git a/gpu/gl/GrGLProgram.cpp b/gpu/gl/GrGLProgram.cpp
index 3691fe9..4fe7a2b 100644
--- a/gpu/gl/GrGLProgram.cpp
+++ b/gpu/gl/GrGLProgram.cpp
@@ -211,12 +211,8 @@
 
     const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
 
-    bool needsVertexShader = true;
-
-    GrGLShaderBuilder builder(fGpu, fUniformManager, fDesc, needsVertexShader);
-    if (GrGLShaderBuilder::VertexBuilder* vertexBuilder = builder.getVertexBuilder()) {
-        fUniformHandles.fViewMatrixUni = vertexBuilder->getViewMatrixUniform();
-    }
+    GrGLFullShaderBuilder builder(fGpu, fUniformManager, fDesc);
+    fUniformHandles.fViewMatrixUni = builder.getViewMatrixUniform();
 
     // incoming color to current stage being processed.
     SkString inColor = builder.getInputColor();
diff --git a/gpu/gl/GrGLProgramDesc.h b/gpu/gl/GrGLProgramDesc.h
index e160438..0c7c8cf 100644
--- a/gpu/gl/GrGLProgramDesc.h
+++ b/gpu/gl/GrGLProgramDesc.h
@@ -113,6 +113,17 @@
         kColorInputCnt
     };
 
+    static GrSLConstantVec KnownColorInputValue(ColorInput ci) {
+        switch (ci) {
+            case GrGLProgramDesc::kTransBlack_ColorInput:
+                return kZeros_GrSLConstantVec;
+            case GrGLProgramDesc::kSolidWhite_ColorInput:
+                return kOnes_GrSLConstantVec;
+            default:
+                return kNone_GrSLConstantVec;
+        }
+    }
+
     enum CoverageOutput {
         // modulate color and coverage, write result as the color output.
         kModulate_CoverageOutput,
@@ -221,6 +232,7 @@
     // code generation to GrGLShaderBuilder (and maybe add getters rather than friending).
     friend class GrGLProgram;
     friend class GrGLShaderBuilder;
+    friend class GrGLFullShaderBuilder;
 };
 
 #endif
diff --git a/gpu/gl/GrGLProgramEffects.cpp b/gpu/gl/GrGLProgramEffects.cpp
index b6decf8..d5826ab 100644
--- a/gpu/gl/GrGLProgramEffects.cpp
+++ b/gpu/gl/GrGLProgramEffects.cpp
@@ -9,6 +9,7 @@
 #include "GrDrawEffect.h"
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLShaderBuilder.h"
+#include "gl/GrGLVertexEffect.h"
 #include "gl/GrGpuGL.h"
 
 typedef GrGLProgramEffects::EffectKey EffectKey;
@@ -157,9 +158,9 @@
     }
 }
 
-void GrGLProgramEffects::setData(GrGpuGL* gpu,
-                                 const GrGLUniformManager& uniformManager,
-                                 const GrEffectStage* effectStages[]) {
+void GrGLVertexProgramEffects::setData(GrGpuGL* gpu,
+                                       const GrGLUniformManager& uniformManager,
+                                       const GrEffectStage* effectStages[]) {
     int numEffects = fGLEffects.count();
     SkASSERT(numEffects == fTransforms.count());
     SkASSERT(numEffects == fSamplers.count());
@@ -171,9 +172,9 @@
     }
 }
 
-void GrGLProgramEffects::setTransformData(const GrGLUniformManager& uniformManager,
-                                          const GrDrawEffect& drawEffect,
-                                          int effectIdx) {
+void GrGLVertexProgramEffects::setTransformData(const GrGLUniformManager& uniformManager,
+                                                const GrDrawEffect& drawEffect,
+                                                int effectIdx) {
     SkTArray<Transform, true>& transforms = fTransforms[effectIdx];
     int numTransforms = transforms.count();
     SkASSERT(numTransforms == (*drawEffect.effect())->numTransforms());
@@ -243,21 +244,18 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-GrGLProgramEffectsBuilder::GrGLProgramEffectsBuilder(GrGLShaderBuilder* builder, int reserveCount)
-    : fBuilder(builder) {
-    GrGLShaderBuilder::VertexBuilder* vertexBuilder = fBuilder->getVertexBuilder();
-    SkASSERT(NULL != vertexBuilder);
-    fProgramEffects.reset(SkNEW_ARGS(GrGLProgramEffects,
-                                     (reserveCount, vertexBuilder->hasExplicitLocalCoords())));
+GrGLVertexProgramEffectsBuilder::GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder* builder,
+                                                                 int reserveCount)
+    : fBuilder(builder)
+    , fProgramEffects(SkNEW_ARGS(GrGLVertexProgramEffects,
+                                 (reserveCount, fBuilder->hasExplicitLocalCoords()))) {
 }
 
-void GrGLProgramEffectsBuilder::emitEffect(const GrEffectStage& stage,
-                                           EffectKey key,
-                                           const char* outColor,
-                                           const char* inColor,
-                                           int stageIndex) {
-    GrGLShaderBuilder::VertexBuilder* vertexBuilder = fBuilder->getVertexBuilder();
-    SkASSERT(NULL != vertexBuilder);
+void GrGLVertexProgramEffectsBuilder::emitEffect(const GrEffectStage& stage,
+                                                 EffectKey key,
+                                                 const char* outColor,
+                                                 const char* inColor,
+                                                 int stageIndex) {
     SkASSERT(NULL != fProgramEffects.get());
 
     GrDrawEffect drawEffect(stage, fProgramEffects->fHasExplicitLocalCoords);
@@ -267,7 +265,7 @@
 
     this->emitAttributes(stage);
     this->emitTransforms(effect, key, &coords);
-    this->emitSamplers(effect, &samplers);
+    INHERITED::emitSamplers(fBuilder, fProgramEffects.get(), effect, &samplers);
 
     GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
     fProgramEffects->fGLEffects.push_back(glEffect);
@@ -275,38 +273,37 @@
     // Enclose custom code in a block to avoid namespace conflicts
     SkString openBrace;
     openBrace.printf("\t{ // Stage %d: %s\n", stageIndex, glEffect->name());
-    vertexBuilder->vsCodeAppend(openBrace.c_str());
+    fBuilder->vsCodeAppend(openBrace.c_str());
     fBuilder->fsCodeAppend(openBrace.c_str());
 
-    glEffect->emitCode(fBuilder, drawEffect, key, outColor, inColor, coords, samplers);
+    if (glEffect->isVertexEffect()) {
+        GrGLVertexEffect* vertexEffect = static_cast<GrGLVertexEffect*>(glEffect);
+        vertexEffect->emitCode(fBuilder, drawEffect, key, outColor, inColor, coords, samplers);
+    } else {
+        glEffect->emitCode(fBuilder, drawEffect, key, outColor, inColor, coords, samplers);
+    }
 
-    vertexBuilder->vsCodeAppend("\t}\n");
+    fBuilder->vsCodeAppend("\t}\n");
     fBuilder->fsCodeAppend("\t}\n");
 }
 
-void GrGLProgramEffectsBuilder::emitAttributes(const GrEffectStage& stage) {
-    GrGLShaderBuilder::VertexBuilder* vertexBuilder = fBuilder->getVertexBuilder();
-    SkASSERT(NULL != vertexBuilder);
-
+void GrGLVertexProgramEffectsBuilder::emitAttributes(const GrEffectStage& stage) {
     int numAttributes = stage.getVertexAttribIndexCount();
     const int* attributeIndices = stage.getVertexAttribIndices();
     for (int a = 0; a < numAttributes; ++a) {
         // TODO: Make addAttribute mangle the name.
         SkString attributeName("aAttr");
         attributeName.appendS32(attributeIndices[a]);
-        vertexBuilder->addEffectAttribute(attributeIndices[a],
-                                          (*stage.getEffect())->vertexAttribType(a),
-                                          attributeName);
+        fBuilder->addEffectAttribute(attributeIndices[a],
+                                     (*stage.getEffect())->vertexAttribType(a),
+                                     attributeName);
     }
 }
 
-void GrGLProgramEffectsBuilder::emitTransforms(const GrEffectRef& effect,
-                                               EffectKey effectKey,
-                                               TransformedCoordsArray* outCoords) {
-    GrGLShaderBuilder::VertexBuilder* vertexBuilder = fBuilder->getVertexBuilder();
-    SkASSERT(NULL != vertexBuilder);
-
-    typedef GrGLProgramEffects::Transform Transform;
+void GrGLVertexProgramEffectsBuilder::emitTransforms(const GrEffectRef& effect,
+                                                     EffectKey effectKey,
+                                                     TransformedCoordsArray* outCoords) {
+    typedef GrGLVertexProgramEffects::Transform Transform;
     SkTArray<Transform, true>& transforms = fProgramEffects->fTransforms.push_back();
     EffectKey totalKey = GrBackendEffectFactory::GetTransformKey(effectKey);
     int numTransforms = effect->numTransforms();
@@ -361,30 +358,30 @@
         }
         const char* vsVaryingName;
         const char* fsVaryingName;
-        vertexBuilder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
+        fBuilder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
 
         const GrGLShaderVar& coords = (kPositionCoords_Flag & key) ?
-                                          vertexBuilder->positionAttribute() :
-                                          vertexBuilder->localCoordsAttribute();
+                                          fBuilder->positionAttribute() :
+                                          fBuilder->localCoordsAttribute();
         // varying = matrix * coords (logically)
         switch (transforms[t].fType) {
             case kVoid_GrSLType:
                 SkASSERT(kVec2f_GrSLType == varyingType);
-                vertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, coords.c_str());
+                fBuilder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, coords.c_str());
                 break;
             case kVec2f_GrSLType:
                 SkASSERT(kVec2f_GrSLType == varyingType);
-                vertexBuilder->vsCodeAppendf("\t%s = %s + %s;\n",
-                                             vsVaryingName, uniName, coords.c_str());
+                fBuilder->vsCodeAppendf("\t%s = %s + %s;\n",
+                                        vsVaryingName, uniName, coords.c_str());
                 break;
             case kMat33f_GrSLType: {
                 SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
                 if (kVec2f_GrSLType == varyingType) {
-                    vertexBuilder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
-                                                 vsVaryingName, uniName, coords.c_str());
+                    fBuilder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
+                                            vsVaryingName, uniName, coords.c_str());
                 } else {
-                    vertexBuilder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n",
-                                                 vsVaryingName, uniName, coords.c_str());
+                    fBuilder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n",
+                                            vsVaryingName, uniName, coords.c_str());
                 }
                 break;
             }
@@ -395,18 +392,20 @@
     }
 }
 
-void GrGLProgramEffectsBuilder::emitSamplers(const GrEffectRef& effect,
+void GrGLProgramEffectsBuilder::emitSamplers(GrGLShaderBuilder* builder,
+                                             GrGLProgramEffects* programEffects,
+                                             const GrEffectRef& effect,
                                              TextureSamplerArray* outSamplers) {
     typedef GrGLProgramEffects::Sampler Sampler;
-    SkTArray<Sampler, true>& samplers = fProgramEffects->fSamplers.push_back();
+    SkTArray<Sampler, true>& samplers = programEffects->fSamplers.push_back();
     int numTextures = effect->numTextures();
     samplers.push_back_n(numTextures);
     SkString name;
     for (int t = 0; t < numTextures; ++t) {
         name.printf("Sampler%d", t);
-        samplers[t].fUniform = fBuilder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
-                                                    kSampler2D_GrSLType,
-                                                    name.c_str());
+        samplers[t].fUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                                   kSampler2D_GrSLType,
+                                                   name.c_str());
         SkNEW_APPEND_TO_TARRAY(outSamplers, TextureSampler,
                                (samplers[t].fUniform, effect->textureAccess(t)));
     }
diff --git a/gpu/gl/GrGLProgramEffects.h b/gpu/gl/GrGLProgramEffects.h
index b74dc96..f6f975a 100644
--- a/gpu/gl/GrGLProgramEffects.h
+++ b/gpu/gl/GrGLProgramEffects.h
@@ -15,7 +15,9 @@
 
 class GrEffectStage;
 class GrGLProgramEffectsBuilder;
+class GrGLVertexProgramEffectsBuilder;
 class GrGLShaderBuilder;
+class GrGLFullShaderBuilder;
 
 /**
  * This class encapsulates an array of GrGLEffects and their supporting data (coord transforms
@@ -34,7 +36,7 @@
     static EffectKey GenTransformKey(const GrDrawEffect&);
     static EffectKey GenTextureKey(const GrDrawEffect&, const GrGLCaps&);
 
-    ~GrGLProgramEffects();
+    virtual ~GrGLProgramEffects();
 
     /**
      * Assigns a texture unit to each sampler. It starts on *texUnitIdx and writes the next
@@ -45,9 +47,9 @@
     /**
      * Calls setData() on each effect, and sets their transformation matrices and texture bindings.
      */
-    void setData(GrGpuGL*,
-                 const GrGLUniformManager&,
-                 const GrEffectStage* effectStages[]);
+    virtual void setData(GrGpuGL*,
+                         const GrGLUniformManager&,
+                         const GrEffectStage* effectStages[]) = 0;
 
     /**
      * Passed to GrGLEffects so they can add transformed coordinates to their shader code.
@@ -94,13 +96,44 @@
 
     typedef SkTArray<TextureSampler> TextureSamplerArray;
 
-private:
+protected:
     friend class GrGLProgramEffectsBuilder;
 
-    GrGLProgramEffects(int reserveCount, bool explicitLocalCoords)
+    GrGLProgramEffects(int reserveCount)
         : fGLEffects(reserveCount)
+        , fSamplers(reserveCount) {
+    }
+
+    /**
+     * Helper for setData(). Binds all the textures for an effect.
+     */
+    void bindTextures(GrGpuGL*, const GrEffectRef&, int effectIdx);
+
+    struct Sampler {
+        SkDEBUGCODE(Sampler() : fTextureUnit(-1) {})
+        UniformHandle fUniform;
+        int           fTextureUnit;
+    };
+
+    SkTArray<GrGLEffect*>                  fGLEffects;
+    SkTArray<SkSTArray<4, Sampler, true> > fSamplers;
+};
+
+/**
+ * This is a GrGLProgramEffects implementation that does coord transforms with the vertex shader.
+ */
+class GrGLVertexProgramEffects : public GrGLProgramEffects {
+public:
+    virtual void setData(GrGpuGL*,
+                         const GrGLUniformManager&,
+                         const GrEffectStage* effectStages[]) SK_OVERRIDE;
+
+private:
+    friend class GrGLVertexProgramEffectsBuilder;
+
+    GrGLVertexProgramEffects(int reserveCount, bool explicitLocalCoords)
+        : INHERITED(reserveCount)
         , fTransforms(reserveCount)
-        , fSamplers(reserveCount)
         , fHasExplicitLocalCoords(explicitLocalCoords) {
     }
 
@@ -109,11 +142,6 @@
      */
     void setTransformData(const GrGLUniformManager&, const GrDrawEffect&, int effectIdx);
 
-    /**
-     * Helper for setData(). Binds all the textures for an effect.
-     */
-    void bindTextures(GrGpuGL*, const GrEffectRef&, int effectIdx);
-
     struct Transform {
         Transform() { fCurrentValue = SkMatrix::InvalidMatrix(); }
         UniformHandle fHandle;
@@ -121,35 +149,51 @@
         SkMatrix      fCurrentValue;
     };
 
-    struct Sampler {
-        SkDEBUGCODE(Sampler() : fTextureUnit(-1) {})
-        UniformHandle fUniform;
-        int           fTextureUnit;
-    };
-
-    SkTArray<GrGLEffect*>                    fGLEffects;
     SkTArray<SkSTArray<2, Transform, true> > fTransforms;
-    SkTArray<SkSTArray<4, Sampler, true> >   fSamplers;
     bool                                     fHasExplicitLocalCoords;
+
+    typedef GrGLProgramEffects INHERITED;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 /**
- * This class is used to construct a GrGLProgramEffects.
+ * This is an abstract base class for constructing different types of GrGLProgramEffects objects.
  */
 class GrGLProgramEffectsBuilder {
 public:
-    GrGLProgramEffectsBuilder(GrGLShaderBuilder* builder, int reserveCount);
-
     /**
      * Emits the effect's shader code, and stores the necessary uniforms internally.
      */
-    void emitEffect(const GrEffectStage&,
-                    GrGLProgramEffects::EffectKey,
-                    const char* outColor,
-                    const char* inColor,
-                    int stageIndex);
+    virtual void emitEffect(const GrEffectStage&,
+                            GrGLProgramEffects::EffectKey,
+                            const char* outColor,
+                            const char* inColor,
+                            int stageIndex) = 0;
+
+protected:
+    /**
+     * Helper for emitEffect(). Emits uniforms for an effect's texture accesses and appends the
+     * necessary data to the TextureSamplerArray* object so effects can add texture lookups.
+     */
+    static void emitSamplers(GrGLShaderBuilder*,
+                             GrGLProgramEffects*,
+                             const GrEffectRef&,
+                             GrGLProgramEffects::TextureSamplerArray*);
+};
+
+/**
+ * This class is used to construct a GrGLVertexProgramEffects object.
+ */
+class GrGLVertexProgramEffectsBuilder : public GrGLProgramEffectsBuilder {
+public:
+    GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder*, int reserveCount);
+
+    virtual void emitEffect(const GrEffectStage&,
+                            GrGLProgramEffects::EffectKey,
+                            const char* outColor,
+                            const char* inColor,
+                            int stageIndex) SK_OVERRIDE;
 
     /**
      * Finalizes the building process and returns the effect array. After this call, the builder
@@ -174,16 +218,10 @@
                         GrGLProgramEffects::EffectKey,
                         GrGLProgramEffects::TransformedCoordsArray*);
 
-    /**
-     * Helper for emitEffect(). Emits uniforms for an effect's texture accesses. The uniform info
-     * as well as texture access parameters are appended to the TextureSamplerArray* object, which
-     * is in turn passed to the effect's emitCode() function.
-     */
-    void emitSamplers(const GrEffectRef&,
-                      GrGLProgramEffects::TextureSamplerArray*);
+    GrGLFullShaderBuilder*                  fBuilder;
+    SkAutoTDelete<GrGLVertexProgramEffects> fProgramEffects;
 
-    GrGLShaderBuilder*                fBuilder;
-    SkAutoTDelete<GrGLProgramEffects> fProgramEffects;
+    typedef GrGLProgramEffectsBuilder INHERITED;
 };
 
 #endif
diff --git a/gpu/gl/GrGLShaderBuilder.cpp b/gpu/gl/GrGLShaderBuilder.cpp
index c33f04b..089ece7 100644
--- a/gpu/gl/GrGLShaderBuilder.cpp
+++ b/gpu/gl/GrGLShaderBuilder.cpp
@@ -15,8 +15,8 @@
 #include "SkRTConf.h"
 #include "SkTrace.h"
 
-#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
-#define GL_CALL_RET(R, X) GR_GL_CALL_RET(fGpu->glInterface(), R, X)
+#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
+#define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
 
 // number of each input/output type in a single allocation block
 static const int kVarsPerBlock = 8;
@@ -91,27 +91,22 @@
 
 GrGLShaderBuilder::GrGLShaderBuilder(GrGpuGL* gpu,
                                      GrGLUniformManager& uniformManager,
-                                     const GrGLProgramDesc& desc,
-                                     bool needsVertexShader)
-    : fUniforms(kVarsPerBlock)
-    , fGpu(gpu)
+                                     const GrGLProgramDesc& desc)
+    : fGpu(gpu)
     , fUniformManager(uniformManager)
     , fFSFeaturesAddedMask(0)
     , fFSInputs(kVarsPerBlock)
     , fFSOutputs(kMaxFSOutputs)
+    , fUniforms(kVarsPerBlock)
     , fSetupFragPosition(false)
-    , fKnownColorValue(kNone_GrSLConstantVec)
-    , fKnownCoverageValue(kNone_GrSLConstantVec)
+    , fKnownColorValue(GrGLProgramDesc::KnownColorInputValue(desc.getHeader().fColorInput))
+    , fKnownCoverageValue(GrGLProgramDesc::KnownColorInputValue(desc.getHeader().fCoverageInput))
     , fHasCustomColorOutput(false)
     , fHasSecondaryOutput(false)
     , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey) {
 
     const GrGLProgramDesc::KeyHeader& header = desc.getHeader();
 
-    if (needsVertexShader) {
-        fVertexBuilder.reset(SkNEW_ARGS(VertexBuilder, (this, fGpu, desc)));
-    }
-
     // Emit code to read the dst copy textue if necessary.
     if (kNoDstRead_DstReadKey != header.fDstReadKey &&
         GrGLCaps::kNone_FBFetchType == fGpu->glCaps().fbFetchType()) {
@@ -152,58 +147,18 @@
         this->fsCodeAppend(";\n\n");
     }
 
-    switch (header.fColorInput) {
-        case GrGLProgramDesc::kAttribute_ColorInput: {
-            SkASSERT(NULL != fVertexBuilder.get());
-            fVertexBuilder->addAttribute(kVec4f_GrSLType, color_attribute_name());
-            const char *vsName, *fsName;
-            fVertexBuilder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
-            fVertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, color_attribute_name());
-            fInputColor = fsName;
-            break;
-        }
-        case GrGLProgramDesc::kUniform_ColorInput: {
-            const char* name;
-            fColorUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility,
-                                             kVec4f_GrSLType, "Color", &name);
-            fInputColor = name;
-            break;
-        }
-        case GrGLProgramDesc::kTransBlack_ColorInput:
-            fKnownColorValue = kZeros_GrSLConstantVec;
-            break;
-        case GrGLProgramDesc::kSolidWhite_ColorInput:
-            fKnownColorValue = kOnes_GrSLConstantVec;
-            break;
-        default:
-            GrCrash("Unknown color type.");
+    if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) {
+        const char* name;
+        fColorUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                         kVec4f_GrSLType, "Color", &name);
+        fInputColor = name;
     }
 
-    switch (header.fCoverageInput) {
-        case GrGLProgramDesc::kAttribute_ColorInput: {
-            SkASSERT(NULL != fVertexBuilder.get());
-            fVertexBuilder->addAttribute(kVec4f_GrSLType, coverage_attribute_name());
-            const char *vsName, *fsName;
-            fVertexBuilder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
-            fVertexBuilder->vsCodeAppendf("\t%s = %s;\n", vsName, coverage_attribute_name());
-            fInputCoverage = fsName;
-            break;
-        }
-        case GrGLProgramDesc::kUniform_ColorInput: {
-            const char* name;
-            fCoverageUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility,
-                                                kVec4f_GrSLType, "Coverage", &name);
-            fInputCoverage = name;
-            break;
-        }
-        case GrGLProgramDesc::kTransBlack_ColorInput:
-            fKnownCoverageValue = kZeros_GrSLConstantVec;
-            break;
-        case GrGLProgramDesc::kSolidWhite_ColorInput:
-            fKnownCoverageValue = kOnes_GrSLConstantVec;
-            break;
-        default:
-            GrCrash("Unknown coverage type.");
+    if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
+        const char* name;
+        fCoverageUniform = this->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                                            kVec4f_GrSLType, "Coverage", &name);
+        fInputCoverage = name;
     }
 
     if (k110_GrGLSLGeneration != fGpu->glslGeneration()) {
@@ -551,14 +506,12 @@
     }
 }
 
-GrGLProgramEffects* GrGLShaderBuilder::createAndEmitEffects(
-        const GrEffectStage* effectStages[],
-        const EffectKey effectKeys[],
-        int effectCnt,
-        SkString* fsInOutColor,
-        GrSLConstantVec* fsInOutColorKnownValue) {
-
-    GrGLProgramEffectsBuilder programEffectsBuilder(this, effectCnt);
+void GrGLShaderBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder,
+                                             const GrEffectStage* effectStages[],
+                                             const EffectKey effectKeys[],
+                                             int effectCnt,
+                                             SkString* fsInOutColor,
+                                             GrSLConstantVec* fsInOutColorKnownValue) {
     bool effectEmitted = false;
 
     SkString inColor = *fsInOutColor;
@@ -580,11 +533,11 @@
         this->nameVariable(&outColor, '\0', "output");
         this->fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
 
-        programEffectsBuilder.emitEffect(stage,
-                                         effectKeys[e],
-                                         outColor.c_str(),
-                                         inColor.isEmpty() ? NULL : inColor.c_str(),
-                                         fCodeStage.stageIndex());
+        programEffectsBuilder->emitEffect(stage,
+                                          effectKeys[e],
+                                          outColor.c_str(),
+                                          inColor.isEmpty() ? NULL : inColor.c_str(),
+                                          fCodeStage.stageIndex());
 
         inColor = outColor;
         *fsInOutColorKnownValue = kNone_GrSLConstantVec;
@@ -594,8 +547,6 @@
     if (effectEmitted) {
         *fsInOutColor = outColor;
     }
-
-    return programEffectsBuilder.finish();
 }
 
 const char* GrGLShaderBuilder::getColorOutputName() const {
@@ -706,10 +657,6 @@
 }
 
 bool GrGLShaderBuilder::compileAndAttachShaders(GrGLuint programId) const {
-    if (NULL != fVertexBuilder.get() && !fVertexBuilder->compileAndAttachShaders(programId)) {
-        return false;
-    }
-
     SkString fragShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo()));
     fragShaderSrc.append(fFSExtensions);
     append_default_precision_qualifier(kDefaultFragmentPrecision,
@@ -732,10 +679,6 @@
 }
 
 void GrGLShaderBuilder::bindProgramLocations(GrGLuint programId) const {
-    if (NULL != fVertexBuilder.get()) {
-        fVertexBuilder->bindProgramLocations(programId);
-    }
-
     if (fHasCustomColorOutput) {
         GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name()));
     }
@@ -748,13 +691,12 @@
     return fGpu->ctxInfo();
 }
 
-////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
 
-GrGLShaderBuilder::VertexBuilder::VertexBuilder(GrGLShaderBuilder* parent,
-                                                GrGpuGL* gpu,
-                                                const GrGLProgramDesc& desc)
-    : fParent(parent)
-    , fGpu(gpu)
+GrGLFullShaderBuilder::GrGLFullShaderBuilder(GrGpuGL* gpu,
+                                             GrGLUniformManager& uniformManager,
+                                             const GrGLProgramDesc& desc)
+    : INHERITED(gpu, uniformManager, desc)
     , fDesc(desc)
     , fVSAttrs(kVarsPerBlock)
     , fVSOutputs(kVarsPerBlock)
@@ -775,8 +717,8 @@
     }
 
     const char* viewMName;
-    fViewMatrixUniform = fParent->addUniform(GrGLShaderBuilder::kVertex_Visibility,
-                                             kMat33f_GrSLType, "ViewM", &viewMName);
+    fViewMatrixUniform = this->addUniform(GrGLShaderBuilder::kVertex_Visibility,
+                                          kMat33f_GrSLType, "ViewM", &viewMName);
 
     this->vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n"
                         "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n",
@@ -790,10 +732,25 @@
         ) {
         this->vsCodeAppend("\tgl_PointSize = 1.0;\n");
     }
+
+    if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) {
+        this->addAttribute(kVec4f_GrSLType, color_attribute_name());
+        const char *vsName, *fsName;
+        this->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
+        this->vsCodeAppendf("\t%s = %s;\n", vsName, color_attribute_name());
+        this->setInputColor(fsName);
+    }
+
+    if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) {
+        this->addAttribute(kVec4f_GrSLType, coverage_attribute_name());
+        const char *vsName, *fsName;
+        this->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
+        this->vsCodeAppendf("\t%s = %s;\n", vsName, coverage_attribute_name());
+        this->setInputCoverage(fsName);
+    }
 }
 
-bool GrGLShaderBuilder::VertexBuilder::addAttribute(GrSLType type,
-                                                    const char* name) {
+bool GrGLFullShaderBuilder::addAttribute(GrSLType type, const char* name) {
     for (int i = 0; i < fVSAttrs.count(); ++i) {
         const GrGLShaderVar& attr = fVSAttrs[i];
         // if attribute already added, don't add it again
@@ -808,9 +765,9 @@
     return true;
 }
 
-bool GrGLShaderBuilder::VertexBuilder::addEffectAttribute(int attributeIndex,
-                                                          GrSLType type,
-                                                          const SkString& name) {
+bool GrGLFullShaderBuilder::addEffectAttribute(int attributeIndex,
+                                               GrSLType type,
+                                               const SkString& name) {
     if (!this->addAttribute(type, name.c_str())) {
         return false;
     }
@@ -819,14 +776,14 @@
     return true;
 }
 
-void GrGLShaderBuilder::VertexBuilder::addVarying(GrSLType type,
-                                                  const char* name,
-                                                  const char** vsOutName,
-                                                  const char** fsInName) {
+void GrGLFullShaderBuilder::addVarying(GrSLType type,
+                                       const char* name,
+                                       const char** vsOutName,
+                                       const char** fsInName) {
     fVSOutputs.push_back();
     fVSOutputs.back().setType(type);
     fVSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
-    fParent->nameVariable(fVSOutputs.back().accessName(), 'v', name);
+    this->nameVariable(fVSOutputs.back().accessName(), 'v', name);
 
     if (vsOutName) {
         *vsOutName = fVSOutputs.back().getName().c_str();
@@ -845,22 +802,20 @@
         fGSOutputs.push_back();
         fGSOutputs.back().setType(type);
         fGSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
-        fParent->nameVariable(fGSOutputs.back().accessName(), 'g', name);
+        this->nameVariable(fGSOutputs.back().accessName(), 'g', name);
         fsName = fGSOutputs.back().accessName();
     } else
 #endif
     {
         fsName = fVSOutputs.back().accessName();
     }
-    fParent->fsInputAppend().set(type,
-                                 GrGLShaderVar::kVaryingIn_TypeModifier,
-                                 *fsName);
+    this->fsInputAppend().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, *fsName);
     if (fsInName) {
         *fsInName = fsName->c_str();
     }
 }
 
-const SkString* GrGLShaderBuilder::VertexBuilder::getEffectAttributeName(int attributeIndex) const {
+const SkString* GrGLFullShaderBuilder::getEffectAttributeName(int attributeIndex) const {
     const AttributePair* attribEnd = fEffectAttributes.end();
     for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) {
         if (attrib->fIndex == attributeIndex) {
@@ -871,26 +826,44 @@
     return NULL;
 }
 
-bool GrGLShaderBuilder::VertexBuilder::compileAndAttachShaders(GrGLuint programId) const {
-    SkString vertShaderSrc(GrGetGLSLVersionDecl(fParent->ctxInfo()));
-    fParent->appendUniformDecls(kVertex_Visibility, &vertShaderSrc);
-    fParent->appendDecls(fVSAttrs, &vertShaderSrc);
-    fParent->appendDecls(fVSOutputs, &vertShaderSrc);
+GrGLProgramEffects* GrGLFullShaderBuilder::createAndEmitEffects(
+        const GrEffectStage* effectStages[],
+        const EffectKey effectKeys[],
+        int effectCnt,
+        SkString* inOutFSColor,
+        GrSLConstantVec* fsInOutColorKnownValue) {
+
+    GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt);
+    this->INHERITED::createAndEmitEffects(&programEffectsBuilder,
+                                          effectStages,
+                                          effectKeys,
+                                          effectCnt,
+                                          inOutFSColor,
+                                          fsInOutColorKnownValue);
+    return programEffectsBuilder.finish();
+}
+
+bool GrGLFullShaderBuilder::compileAndAttachShaders(GrGLuint programId) const {
+    const GrGLInterface* glInterface = this->gpu()->glInterface();
+    SkString vertShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo()));
+    this->appendUniformDecls(kVertex_Visibility, &vertShaderSrc);
+    this->appendDecls(fVSAttrs, &vertShaderSrc);
+    this->appendDecls(fVSOutputs, &vertShaderSrc);
     vertShaderSrc.append("void main() {\n");
     vertShaderSrc.append(fVSCode);
     vertShaderSrc.append("}\n");
-    if (!attach_shader(fGpu->glInterface(), programId, GR_GL_VERTEX_SHADER, vertShaderSrc)) {
+    if (!attach_shader(glInterface, programId, GR_GL_VERTEX_SHADER, vertShaderSrc)) {
         return false;
     }
 
 #if GR_GL_EXPERIMENTAL_GS
     if (fDesc.getHeader().fExperimentalGS) {
-        SkASSERT(fGpu->glslGeneration() >= k150_GrGLSLGeneration);
-        SkString geomShaderSrc(GrGetGLSLVersionDecl(fParent->ctxInfo()));
+        SkASSERT(this->ctxInfo().glslGeneration() >= k150_GrGLSLGeneration);
+        SkString geomShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo()));
         geomShaderSrc.append("layout(triangles) in;\n"
                              "layout(triangle_strip, max_vertices = 6) out;\n");
-        fParent->appendDecls(fGSInputs, &geomShaderSrc);
-        fParent->appendDecls(fGSOutputs, &geomShaderSrc);
+        this->appendDecls(fGSInputs, &geomShaderSrc);
+        this->appendDecls(fGSOutputs, &geomShaderSrc);
         geomShaderSrc.append("void main() {\n");
         geomShaderSrc.append("\tfor (int i = 0; i < 3; ++i) {\n"
                              "\t\tgl_Position = gl_in[i].gl_Position;\n");
@@ -907,16 +880,18 @@
                              "\t}\n"
                              "\tEndPrimitive();\n");
         geomShaderSrc.append("}\n");
-        if (!attach_shader(fGpu->glInterface(), programId, GR_GL_GEOMETRY_SHADER, geomShaderSrc)) {
+        if (!attach_shader(glInterface, programId, GR_GL_GEOMETRY_SHADER, geomShaderSrc)) {
             return false;
         }
     }
 #endif
 
-    return true;
+    return this->INHERITED::compileAndAttachShaders(programId);
 }
 
-void GrGLShaderBuilder::VertexBuilder::bindProgramLocations(GrGLuint programId) const {
+void GrGLFullShaderBuilder::bindProgramLocations(GrGLuint programId) const {
+    this->INHERITED::bindProgramLocations(programId);
+
     const GrGLProgramDesc::KeyHeader& header = fDesc.getHeader();
 
     // Bind the attrib locations to same values for all shaders
diff --git a/gpu/gl/GrGLShaderBuilder.h b/gpu/gl/GrGLShaderBuilder.h
index 4553ac3..4c43fc3 100644
--- a/gpu/gl/GrGLShaderBuilder.h
+++ b/gpu/gl/GrGLShaderBuilder.h
@@ -33,6 +33,7 @@
     typedef GrBackendEffectFactory::EffectKey EffectKey;
     typedef GrGLProgramEffects::TextureSampler TextureSampler;
     typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray;
+    typedef GrGLUniformManager::BuilderUniform BuilderUniform;
 
     enum ShaderVisibility {
         kVertex_Visibility   = 0x1,
@@ -40,10 +41,8 @@
         kFragment_Visibility = 0x4,
     };
 
-    GrGLShaderBuilder(GrGpuGL*,
-                      GrGLUniformManager&,
-                      const GrGLProgramDesc&,
-                      bool needsVertexShader);
+    GrGLShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&);
+    virtual ~GrGLShaderBuilder() {}
 
     /**
      * Use of these features may require a GLSL extension to be enabled. Shaders may not compile
@@ -104,9 +103,6 @@
                         const char* body,
                         SkString* outName);
 
-    /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */
-    GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); }
-
     typedef uint8_t DstReadKey;
     typedef uint8_t FragPosKey;
 
@@ -174,10 +170,22 @@
      * TODO: These are used by GrGLProgram to insert a mode color filter. Remove these when the
      * color filter is expressed as a GrEffect.
      */
-    const SkString& getInputColor() const { return fInputColor; }
-    GrSLConstantVec getKnownColorValue() const { return fKnownColorValue; }
-    const SkString& getInputCoverage() const { return fInputCoverage; }
-    GrSLConstantVec getKnownCoverageValue() const { return fKnownCoverageValue; }
+    const SkString& getInputColor() const {
+        SkASSERT(fInputColor.isEmpty() != (kNone_GrSLConstantVec == fKnownColorValue));
+        return fInputColor;
+    }
+    GrSLConstantVec getKnownColorValue() const {
+        SkASSERT(fInputColor.isEmpty() != (kNone_GrSLConstantVec == fKnownColorValue));
+        return fKnownColorValue;
+    }
+    const SkString& getInputCoverage() const {
+        SkASSERT(fInputCoverage.isEmpty() != (kNone_GrSLConstantVec == fKnownCoverageValue));
+        return fInputCoverage;
+    }
+    GrSLConstantVec getKnownCoverageValue() const {
+        SkASSERT(fInputCoverage.isEmpty() != (kNone_GrSLConstantVec == fKnownCoverageValue));
+        return fKnownCoverageValue;
+    }
 
     /**
      * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for
@@ -188,11 +196,11 @@
      * output color. The handles to texture samplers for effectStage[i] are added to
      * effectSamplerHandles[i].
      */
-    GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
-                                             const EffectKey effectKeys[],
-                                             int effectCnt,
-                                             SkString* inOutFSColor,
-                                             GrSLConstantVec* fsInOutColorKnownValue);
+    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
+                                                     const EffectKey effectKeys[],
+                                                     int effectCnt,
+                                                     SkString* inOutFSColor,
+                                                     GrSLConstantVec* fsInOutColorKnownValue) = 0;
 
     const char* getColorOutputName() const;
     const char* enableSecondaryOutput();
@@ -210,106 +218,38 @@
         return fDstCopySamplerUniform;
     }
 
-    /** Helper class used to build the vertex and geometry shaders. This functionality
-        is kept separate from the rest of GrGLShaderBuilder to allow for shaders programs
-        that only use the fragment shader. */
-    class VertexBuilder {
-    public:
-        VertexBuilder(GrGLShaderBuilder* parent, GrGpuGL* gpu, const GrGLProgramDesc&);
-
-        /**
-         * Called by GrGLEffects to add code to one of the shaders.
-         */
-        void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
-            va_list args;
-            va_start(args, format);
-            fVSCode.appendf(format, args);
-            va_end(args);
-        }
-
-        void vsCodeAppend(const char* str) { fVSCode.append(str); }
-
-       /** Add a vertex attribute to the current program that is passed in from the vertex data.
-           Returns false if the attribute was already there, true otherwise. */
-        bool addAttribute(GrSLType type, const char* name);
-
-       /** Add a varying variable to the current program to pass values between vertex and fragment
-            shaders. If the last two parameters are non-NULL, they are filled in with the name
-            generated. */
-        void addVarying(GrSLType type,
-                        const char* name,
-                        const char** vsOutName = NULL,
-                        const char** fsInName = NULL);
-
-        /** Returns a vertex attribute that represents the vertex position in the VS. This is the
-            pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
-          */
-        const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
-
-        /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
-            as positionAttribute() or it may not be. It depends upon whether the rendering code
-            specified explicit local coords or not in the GrDrawState. */
-        const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
-
-        /**
-         * Are explicit local coordinates provided as input to the vertex shader.
-         */
-        bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
-
-        bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name);
-        const SkString* getEffectAttributeName(int attributeIndex) const;
-
-        GrGLUniformManager::UniformHandle getViewMatrixUniform() const {
-            return fViewMatrixUniform;
-        }
-
-        bool compileAndAttachShaders(GrGLuint programId) const;
-        void bindProgramLocations(GrGLuint programId) const;
-
-    private:
-        GrGLShaderBuilder*                  fParent;
-        GrGpuGL*                            fGpu;
-        const GrGLProgramDesc&              fDesc;
-        VarArray                            fVSAttrs;
-        VarArray                            fVSOutputs;
-        VarArray                            fGSInputs;
-        VarArray                            fGSOutputs;
-
-        SkString                            fVSCode;
-
-        struct AttributePair {
-            void set(int index, const SkString& name) {
-                fIndex = index; fName = name;
-            }
-            int      fIndex;
-            SkString fName;
-        };
-        SkSTArray<10, AttributePair, true>  fEffectAttributes;
-
-        GrGLUniformManager::UniformHandle   fViewMatrixUniform;
-
-        GrGLShaderVar*                      fPositionVar;
-        GrGLShaderVar*                      fLocalCoordsVar;
-    };
-
-    /** Gets the vertex builder that is used to construct the vertex and geometry shaders.
-        It may be NULL if this shader program is only meant to have a fragment shader. */
-    VertexBuilder* getVertexBuilder() const { return fVertexBuilder.get(); }
-
     bool finish(GrGLuint* outProgramId);
 
     const GrGLContextInfo& ctxInfo() const;
 
-private:
+protected:
+    GrGpuGL* gpu() const { return fGpu; }
+
+    void setInputColor(const char* inputColor) { fInputColor = inputColor; }
+    void setInputCoverage(const char* inputCoverage) { fInputCoverage = inputCoverage; }
+
+    /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */
+    GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); }
+
+    // Generates a name for a variable. The generated string will be name prefixed by the prefix
+    // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
+    // generating stage code.
+    void nameVariable(SkString* out, char prefix, const char* name);
+
+    // Helper for emitEffects().
+    void createAndEmitEffects(GrGLProgramEffectsBuilder*,
+                              const GrEffectStage* effectStages[],
+                              const EffectKey effectKeys[],
+                              int effectCnt,
+                              SkString* inOutFSColor,
+                              GrSLConstantVec* fsInOutColorKnownValue);
+
+    virtual bool compileAndAttachShaders(GrGLuint programId) const;
+    virtual void bindProgramLocations(GrGLuint programId) const;
+
     void appendDecls(const VarArray&, SkString*) const;
     void appendUniformDecls(ShaderVisibility, SkString*) const;
 
-    bool compileAndAttachShaders(GrGLuint programId) const;
-    void bindProgramLocations(GrGLuint programId) const;
-
-    typedef GrGLUniformManager::BuilderUniform BuilderUniform;
-    GrGLUniformManager::BuilderUniformArray fUniforms;
-
 private:
     class CodeStage : public SkNoncopyable {
     public:
@@ -376,11 +316,6 @@
     // track the enables separately for each shader.
     void addFSFeature(uint32_t featureBit, const char* extensionName);
 
-    // Generates a name for a variable. The generated string will be name prefixed by the prefix
-    // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
-    // generating stage code.
-    void nameVariable(SkString* out, char prefix, const char* name);
-
     // Interpretation of DstReadKey when generating code
     enum {
         kNoDstRead_DstReadKey         = 0,
@@ -395,36 +330,124 @@
         kBottomLeftFragPosRead_FragPosKey   = 0x2,// Read frag pos relative to bottom-left.
     };
 
-    GrGpuGL*                            fGpu;
-    GrGLUniformManager&                 fUniformManager;
-    uint32_t                            fFSFeaturesAddedMask;
-    SkString                            fFSFunctions;
-    SkString                            fFSExtensions;
-    VarArray                            fFSInputs;
-    VarArray                            fFSOutputs;
+    GrGpuGL*                                fGpu;
+    GrGLUniformManager&                     fUniformManager;
+    uint32_t                                fFSFeaturesAddedMask;
+    SkString                                fFSFunctions;
+    SkString                                fFSExtensions;
+    VarArray                                fFSInputs;
+    VarArray                                fFSOutputs;
+    GrGLUniformManager::BuilderUniformArray fUniforms;
 
-    SkString                            fFSCode;
+    SkString                                fFSCode;
 
-    bool                                fSetupFragPosition;
-    GrGLUniformManager::UniformHandle   fDstCopySamplerUniform;
+    bool                                    fSetupFragPosition;
+    GrGLUniformManager::UniformHandle       fDstCopySamplerUniform;
 
-    SkString                            fInputColor;
-    GrSLConstantVec                     fKnownColorValue;
-    SkString                            fInputCoverage;
-    GrSLConstantVec                     fKnownCoverageValue;
+    SkString                                fInputColor;
+    GrSLConstantVec                         fKnownColorValue;
+    SkString                                fInputCoverage;
+    GrSLConstantVec                         fKnownCoverageValue;
 
-    bool                                fHasCustomColorOutput;
-    bool                                fHasSecondaryOutput;
+    bool                                    fHasCustomColorOutput;
+    bool                                    fHasSecondaryOutput;
 
-    GrGLUniformManager::UniformHandle   fRTHeightUniform;
-    GrGLUniformManager::UniformHandle   fDstCopyTopLeftUniform;
-    GrGLUniformManager::UniformHandle   fDstCopyScaleUniform;
-    GrGLUniformManager::UniformHandle   fColorUniform;
-    GrGLUniformManager::UniformHandle   fCoverageUniform;
+    GrGLUniformManager::UniformHandle       fRTHeightUniform;
+    GrGLUniformManager::UniformHandle       fDstCopyTopLeftUniform;
+    GrGLUniformManager::UniformHandle       fDstCopyScaleUniform;
+    GrGLUniformManager::UniformHandle       fColorUniform;
+    GrGLUniformManager::UniformHandle       fCoverageUniform;
 
-    bool                                fTopLeftFragPosRead;
+    bool                                    fTopLeftFragPosRead;
+};
 
-    SkAutoTDelete<VertexBuilder>        fVertexBuilder;
+////////////////////////////////////////////////////////////////////////////////
+
+class GrGLFullShaderBuilder : public GrGLShaderBuilder {
+public:
+    GrGLFullShaderBuilder(GrGpuGL*, GrGLUniformManager&, const GrGLProgramDesc&);
+
+    /**
+     * Called by GrGLEffects to add code to one of the shaders.
+     */
+    void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
+        va_list args;
+        va_start(args, format);
+        fVSCode.appendf(format, args);
+        va_end(args);
+    }
+
+    void vsCodeAppend(const char* str) { fVSCode.append(str); }
+
+   /** Add a vertex attribute to the current program that is passed in from the vertex data.
+       Returns false if the attribute was already there, true otherwise. */
+    bool addAttribute(GrSLType type, const char* name);
+
+   /** Add a varying variable to the current program to pass values between vertex and fragment
+        shaders. If the last two parameters are non-NULL, they are filled in with the name
+        generated. */
+    void addVarying(GrSLType type,
+                    const char* name,
+                    const char** vsOutName = NULL,
+                    const char** fsInName = NULL);
+
+    /** Returns a vertex attribute that represents the vertex position in the VS. This is the
+        pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
+      */
+    const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
+
+    /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
+        as positionAttribute() or it may not be. It depends upon whether the rendering code
+        specified explicit local coords or not in the GrDrawState. */
+    const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
+
+    /**
+     * Are explicit local coordinates provided as input to the vertex shader.
+     */
+    bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
+
+    bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name);
+    const SkString* getEffectAttributeName(int attributeIndex) const;
+
+    virtual GrGLProgramEffects* createAndEmitEffects(
+                const GrEffectStage* effectStages[],
+                const EffectKey effectKeys[],
+                int effectCnt,
+                SkString* inOutFSColor,
+                GrSLConstantVec* fsInOutColorKnownValue) SK_OVERRIDE;
+
+    GrGLUniformManager::UniformHandle getViewMatrixUniform() const {
+        return fViewMatrixUniform;
+    }
+
+protected:
+    virtual bool compileAndAttachShaders(GrGLuint programId) const SK_OVERRIDE;
+    virtual void bindProgramLocations(GrGLuint programId) const SK_OVERRIDE;
+
+private:
+    const GrGLProgramDesc&              fDesc;
+    VarArray                            fVSAttrs;
+    VarArray                            fVSOutputs;
+    VarArray                            fGSInputs;
+    VarArray                            fGSOutputs;
+
+    SkString                            fVSCode;
+
+    struct AttributePair {
+        void set(int index, const SkString& name) {
+            fIndex = index; fName = name;
+        }
+        int      fIndex;
+        SkString fName;
+    };
+    SkSTArray<10, AttributePair, true>  fEffectAttributes;
+
+    GrGLUniformManager::UniformHandle   fViewMatrixUniform;
+
+    GrGLShaderVar*                      fPositionVar;
+    GrGLShaderVar*                      fLocalCoordsVar;
+
+    typedef GrGLShaderBuilder INHERITED;
 };
 
 #endif
diff --git a/gpu/gl/GrGLVertexEffect.h b/gpu/gl/GrGLVertexEffect.h
new file mode 100644
index 0000000..1b4c744
--- /dev/null
+++ b/gpu/gl/GrGLVertexEffect.h
@@ -0,0 +1,52 @@
+/*
+ * 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 GrGLVertexEffect_DEFINED
+#define GrGLVertexEffect_DEFINED
+
+#include "GrGLEffect.h"
+
+/**
+ * If a GL effect needs a GrGLFullShaderBuilder* object to emit vertex code, then it must inherit
+ * 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 {
+public:
+    GrGLVertexEffect(const GrBackendEffectFactory& factory)
+        : INHERITED(factory) { fIsVertexEffect = true; }
+
+    /**
+     * This is similar to emitCode() in the base class, except it takes a full shader builder.
+     * This allows the effect subclass to emit vertex code.
+     */
+    virtual void emitCode(GrGLFullShaderBuilder* builder,
+                          const GrDrawEffect& drawEffect,
+                          EffectKey key,
+                          const char* outputColor,
+                          const char* inputColor,
+                          const TransformedCoordsArray& coords,
+                          const TextureSamplerArray& samplers) = 0;
+
+    /**
+     * Provide a default override for base class's emitCode() function.
+     */
+    virtual void emitCode(GrGLShaderBuilder* builder,
+                          const GrDrawEffect& drawEffect,
+                          EffectKey key,
+                          const char* outputColor,
+                          const char* inputColor,
+                          const TransformedCoordsArray& coords,
+                          const TextureSamplerArray& samplers) SK_OVERRIDE {
+        GrCrash("GrGLVertexEffect requires GrGLFullShaderBuilder* overload for emitCode().");
+    }
+
+private:
+    typedef GrGLEffect INHERITED;
+};
+
+#endif