Create GrGLSLVaryingHandler class for program building

BUG=skia:

Review URL: https://codereview.chromium.org/1462123003
diff --git a/src/gpu/GrDefaultGeoProcFactory.cpp b/src/gpu/GrDefaultGeoProcFactory.cpp
index 7b92133..85339ea 100644
--- a/src/gpu/GrDefaultGeoProcFactory.cpp
+++ b/src/gpu/GrDefaultGeoProcFactory.cpp
@@ -12,6 +12,7 @@
 #include "glsl/GrGLSLGeometryProcessor.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLVertexShaderBuilder.h"
+#include "glsl/GrGLSLVarying.h"
 #include "glsl/GrGLSLUtil.h"
 
 /*
@@ -66,14 +67,15 @@
             GrGLSLGPBuilder* pb = args.fPB;
             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
+            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
             // emit attributes
-            vertBuilder->emitAttributes(gp);
+            varyingHandler->emitAttributes(gp);
 
             // Setup pass through color
             if (!gp.colorIgnored()) {
                 if (gp.hasVertexColor()) {
-                    pb->addPassThroughAttribute(gp.inColor(), args.fOutputColor);
+                    varyingHandler->addPassThroughAttribute(gp.inColor(), args.fOutputColor);
                 } else {
                     this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform);
                 }
@@ -91,6 +93,7 @@
                 // emit transforms with explicit local coords
                 this->emitTransforms(pb,
                                      vertBuilder,
+                                     varyingHandler,
                                      gpArgs->fPositionVar,
                                      gp.inLocalCoords()->fName,
                                      gp.localMatrix(),
@@ -100,6 +103,7 @@
                 // transforms have already been applied to vertex attributes on the cpu
                 this->emitTransforms(pb,
                                      vertBuilder,
+                                     varyingHandler,
                                      gp.inLocalCoords()->fName,
                                      args.fTransformsIn,
                                      args.fTransformsOut);
@@ -107,6 +111,7 @@
                 // emit transforms with position
                 this->emitTransforms(pb,
                                      vertBuilder,
+                                     varyingHandler,
                                      gpArgs->fPositionVar,
                                      gp.inPosition()->fName,
                                      gp.localMatrix(),
@@ -118,7 +123,7 @@
             if (!gp.coverageWillBeIgnored()) {
                 if (gp.hasVertexCoverage()) {
                     fragBuilder->codeAppendf("float alpha = 1.0;");
-                    args.fPB->addPassThroughAttribute(gp.inCoverage(), "alpha");
+                    varyingHandler->addPassThroughAttribute(gp.inCoverage(), "alpha");
                     fragBuilder->codeAppendf("%s = vec4(alpha);", args.fOutputCoverage);
                 } else if (gp.coverage() == 0xff) {
                     fragBuilder->codeAppendf("%s = vec4(1);", args.fOutputCoverage);
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 128894c..c66e125 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -25,6 +25,7 @@
 #include "glsl/GrGLSLGeometryProcessor.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLVarying.h"
 #include "glsl/GrGLSLVertexShaderBuilder.h"
 #include "glsl/GrGLSLUtil.h"
 
@@ -99,12 +100,13 @@
             const CircleEdgeEffect& ce = args.fGP.cast<CircleEdgeEffect>();
             GrGLSLGPBuilder* pb = args.fPB;
             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
             // emit attributes
-            vertBuilder->emitAttributes(ce);
+            varyingHandler->emitAttributes(ce);
 
             GrGLSLVertToFrag v(kVec4f_GrSLType);
-            args.fPB->addVarying("CircleEdge", &v);
+            varyingHandler->addVarying("CircleEdge", &v);
             vertBuilder->codeAppendf("%s = %s;", v.vsOut(), ce.inCircleEdge()->fName);
 
             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
@@ -119,6 +121,7 @@
             // emit transforms
             this->emitTransforms(args.fPB,
                                  vertBuilder,
+                                 varyingHandler,
                                  gpArgs->fPositionVar,
                                  ce.inPosition()->fName,
                                  ce.localMatrix(),
@@ -253,17 +256,18 @@
             const EllipseEdgeEffect& ee = args.fGP.cast<EllipseEdgeEffect>();
             GrGLSLGPBuilder* pb = args.fPB;
             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
             // emit attributes
-            vertBuilder->emitAttributes(ee);
+            varyingHandler->emitAttributes(ee);
 
             GrGLSLVertToFrag ellipseOffsets(kVec2f_GrSLType);
-            args.fPB->addVarying("EllipseOffsets", &ellipseOffsets);
+            varyingHandler->addVarying("EllipseOffsets", &ellipseOffsets);
             vertBuilder->codeAppendf("%s = %s;", ellipseOffsets.vsOut(),
                                    ee.inEllipseOffset()->fName);
 
             GrGLSLVertToFrag ellipseRadii(kVec4f_GrSLType);
-            args.fPB->addVarying("EllipseRadii", &ellipseRadii);
+            varyingHandler->addVarying("EllipseRadii", &ellipseRadii);
             vertBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(),
                                    ee.inEllipseRadii()->fName);
 
@@ -279,6 +283,7 @@
             // emit transforms
             this->emitTransforms(args.fPB,
                                  vertBuilder,
+                                 varyingHandler,
                                  gpArgs->fPositionVar,
                                  ee.inPosition()->fName,
                                  ee.localMatrix(),
@@ -433,17 +438,18 @@
             const DIEllipseEdgeEffect& ee = args.fGP.cast<DIEllipseEdgeEffect>();
             GrGLSLGPBuilder* pb = args.fPB;
             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
             // emit attributes
-            vertBuilder->emitAttributes(ee);
+            varyingHandler->emitAttributes(ee);
 
             GrGLSLVertToFrag offsets0(kVec2f_GrSLType);
-            args.fPB->addVarying("EllipseOffsets0", &offsets0);
+            varyingHandler->addVarying("EllipseOffsets0", &offsets0);
             vertBuilder->codeAppendf("%s = %s;", offsets0.vsOut(),
                                    ee.inEllipseOffsets0()->fName);
 
             GrGLSLVertToFrag offsets1(kVec2f_GrSLType);
-            args.fPB->addVarying("EllipseOffsets1", &offsets1);
+            varyingHandler->addVarying("EllipseOffsets1", &offsets1);
             vertBuilder->codeAppendf("%s = %s;", offsets1.vsOut(),
                                    ee.inEllipseOffsets1()->fName);
 
@@ -464,6 +470,7 @@
             // emit transforms
             this->emitTransforms(args.fPB,
                                  vertBuilder,
+                                 varyingHandler,
                                  gpArgs->fPositionVar,
                                  ee.inPosition()->fName,
                                  args.fTransformsIn,
diff --git a/src/gpu/GrPathProcessor.cpp b/src/gpu/GrPathProcessor.cpp
index 0e85652..f52ef48 100644
--- a/src/gpu/GrPathProcessor.cpp
+++ b/src/gpu/GrPathProcessor.cpp
@@ -12,6 +12,7 @@
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLProcessorTypes.h"
 #include "glsl/GrGLSLProgramBuilder.h"
+#include "glsl/GrGLSLVarying.h"
 
 class GrGLPathProcessor : public GrGLSLPrimitiveProcessor {
 public:
@@ -30,7 +31,7 @@
         const GrPathProcessor& pathProc = args.fGP.cast<GrPathProcessor>();
 
         // emit transforms
-        this->emitTransforms(args.fPB, args.fTransformsIn, args.fTransformsOut);
+        this->emitTransforms(args.fVaryingHandler, args.fTransformsIn, args.fTransformsOut);
 
         // Setup uniform color
         if (pathProc.opts().readsColor()) {
@@ -49,7 +50,9 @@
         }
     }
 
-    void emitTransforms(GrGLSLGPBuilder* pb, const TransformsIn& tin, TransformsOut* tout) {
+    void emitTransforms(GrGLSLVaryingHandler* varyingHandler,
+                        const TransformsIn& tin,
+                        TransformsOut* tout) {
         tout->push_back_n(tin.count());
         fInstalledTransforms.push_back_n(tin.count());
         for (int i = 0; i < tin.count(); i++) {
@@ -63,8 +66,10 @@
                 SkString strVaryingName("MatrixCoord");
                 strVaryingName.appendf("_%i_%i", i, t);
                 GrGLSLVertToFrag v(varyingType);
+                GrGLVaryingHandler* glVaryingHandler = (GrGLVaryingHandler*) varyingHandler;
                 fInstalledTransforms[i][t].fHandle =
-                        pb->addSeparableVarying(strVaryingName.c_str(), &v).toIndex();
+                        glVaryingHandler->addPathProcessingVarying(strVaryingName.c_str(),
+                                                                   &v).toIndex();
                 fInstalledTransforms[i][t].fType = varyingType;
 
                 SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLSLTransformedCoords,
diff --git a/src/gpu/batches/GrAAConvexPathRenderer.cpp b/src/gpu/batches/GrAAConvexPathRenderer.cpp
index b78ecd8..aee18b7 100644
--- a/src/gpu/batches/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/batches/GrAAConvexPathRenderer.cpp
@@ -28,6 +28,7 @@
 #include "glsl/GrGLSLGeometryProcessor.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLVarying.h"
 
 GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
 }
@@ -550,12 +551,13 @@
             const QuadEdgeEffect& qe = args.fGP.cast<QuadEdgeEffect>();
             GrGLSLGPBuilder* pb = args.fPB;
             GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+            GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
             // emit attributes
-            vertBuilder->emitAttributes(qe);
+            varyingHandler->emitAttributes(qe);
 
             GrGLSLVertToFrag v(kVec4f_GrSLType);
-            args.fPB->addVarying("QuadEdge", &v);
+            varyingHandler->addVarying("QuadEdge", &v);
             vertBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.inQuadEdge()->fName);
 
             GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
@@ -570,6 +572,7 @@
             // emit transforms
             this->emitTransforms(args.fPB,
                                  vertBuilder,
+                                 varyingHandler,
                                  gpArgs->fPositionVar,
                                  qe.inPosition()->fName,
                                  qe.localMatrix(),
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 7ce2b31..13672da 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -11,6 +11,7 @@
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
 #include "glsl/GrGLSLUtil.h"
+#include "glsl/GrGLSLVarying.h"
 
 class GrGLConicEffect : public GrGLSLGeometryProcessor {
 public:
@@ -75,12 +76,13 @@
     GrGLSLGPBuilder* pb = args.fPB;
     GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
     const GrConicEffect& gp = args.fGP.cast<GrConicEffect>();
+    GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
     // emit attributes
-    vertBuilder->emitAttributes(gp);
+    varyingHandler->emitAttributes(gp);
 
     GrGLSLVertToFrag v(kVec4f_GrSLType);
-    args.fPB->addVarying("ConicCoeffs", &v);
+    varyingHandler->addVarying("ConicCoeffs", &v);
     vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inConicCoeffs()->fName);
 
     GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
@@ -100,6 +102,7 @@
     // emit transforms with position
     this->emitTransforms(pb,
                          vertBuilder,
+                         varyingHandler,
                          gpArgs->fPositionVar,
                          gp.inPosition()->fName,
                          gp.localMatrix(),
@@ -301,12 +304,13 @@
     GrGLSLGPBuilder* pb = args.fPB;
     GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
     const GrQuadEffect& gp = args.fGP.cast<GrQuadEffect>();
+    GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
     // emit attributes
-    vertBuilder->emitAttributes(gp);
+    varyingHandler->emitAttributes(gp);
 
     GrGLSLVertToFrag v(kVec4f_GrSLType);
-    args.fPB->addVarying("HairQuadEdge", &v);
+    varyingHandler->addVarying("HairQuadEdge", &v);
     vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inHairQuadEdge()->fName);
 
     GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
@@ -326,6 +330,7 @@
     // emit transforms with position
     this->emitTransforms(pb,
                          vertBuilder,
+                         varyingHandler,
                          gpArgs->fPositionVar,
                          gp.inPosition()->fName,
                          gp.localMatrix(),
@@ -501,12 +506,13 @@
 void GrGLCubicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
     GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
     const GrCubicEffect& gp = args.fGP.cast<GrCubicEffect>();
+    GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
     // emit attributes
-    vertBuilder->emitAttributes(gp);
+    varyingHandler->emitAttributes(gp);
 
     GrGLSLVertToFrag v(kVec4f_GrSLType);
-    args.fPB->addVarying("CubicCoeffs", &v, kHigh_GrSLPrecision);
+    varyingHandler->addVarying("CubicCoeffs", &v, kHigh_GrSLPrecision);
     vertBuilder->codeAppendf("%s = %s;", v.vsOut(), gp.inCubicCoeffs()->fName);
 
     GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
@@ -526,6 +532,7 @@
     // emit transforms with position
     this->emitTransforms(args.fPB,
                          vertBuilder,
+                         varyingHandler,
                          gpArgs->fPositionVar,
                          gp.inPosition()->fName,
                          args.fTransformsIn,
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index 28c6f0f..5946462 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -12,6 +12,7 @@
 #include "glsl/GrGLSLGeometryProcessor.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLVarying.h"
 #include "glsl/GrGLSLVertexShaderBuilder.h"
 
 class GrGLBitmapTextGeoProc : public GrGLSLGeometryProcessor {
@@ -23,9 +24,10 @@
 
         GrGLSLGPBuilder* pb = args.fPB;
         GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+        GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
         // emit attributes
-        vertBuilder->emitAttributes(cte);
+        varyingHandler->emitAttributes(cte);
 
         // compute numbers to be hardcoded to convert texture coordinates from int to float
         SkASSERT(cte.numTextures() == 1);
@@ -35,7 +37,7 @@
         SkScalar recipHeight = 1.0f / atlas->height();
 
         GrGLSLVertToFrag v(kVec2f_GrSLType);
-        pb->addVarying("TextureCoords", &v);
+        varyingHandler->addVarying("TextureCoords", &v);
         vertBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", v.vsOut(),
                                  GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipWidth,
                                  GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipHeight,
@@ -45,7 +47,7 @@
         // Setup pass through color
         if (!cte.colorIgnored()) {
             if (cte.hasVertexColor()) {
-                pb->addPassThroughAttribute(cte.inColor(), args.fOutputColor);
+                varyingHandler->addPassThroughAttribute(cte.inColor(), args.fOutputColor);
             } else {
                 this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform);
             }
@@ -57,6 +59,7 @@
         // emit transforms
         this->emitTransforms(args.fPB,
                              vertBuilder,
+                             varyingHandler,
                              gpArgs->fPositionVar,
                              cte.inPosition()->fName,
                              cte.localMatrix(),
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index 94cfd80..c1e2011 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -25,6 +25,7 @@
 #include "glsl/GrGLSLGeometryProcessor.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLVarying.h"
 #include "glsl/GrGLSLVertexShaderBuilder.h"
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -853,18 +854,19 @@
     const DashingCircleEffect& dce = args.fGP.cast<DashingCircleEffect>();
     GrGLSLGPBuilder* pb = args.fPB;
     GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+    GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
     // emit attributes
-    vertBuilder->emitAttributes(dce);
+    varyingHandler->emitAttributes(dce);
 
     // XY are dashPos, Z is dashInterval
     GrGLSLVertToFrag dashParams(kVec3f_GrSLType);
-    args.fPB->addVarying("DashParam", &dashParams);
+    varyingHandler->addVarying("DashParam", &dashParams);
     vertBuilder->codeAppendf("%s = %s;", dashParams.vsOut(), dce.inDashParams()->fName);
 
     // x refers to circle radius - 0.5, y refers to cicle's center x coord
     GrGLSLVertToFrag circleParams(kVec2f_GrSLType);
-    args.fPB->addVarying("CircleParams", &circleParams);
+    varyingHandler->addVarying("CircleParams", &circleParams);
     vertBuilder->codeAppendf("%s = %s;", circleParams.vsOut(), dce.inCircleParams()->fName);
 
     GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
@@ -879,6 +881,7 @@
     // emit transforms
     this->emitTransforms(args.fPB,
                          vertBuilder,
+                         varyingHandler,
                          gpArgs->fPositionVar,
                          dce.inPosition()->fName,
                          dce.localMatrix(),
@@ -1064,19 +1067,20 @@
     GrGLSLGPBuilder* pb = args.fPB;
 
     GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+    GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
     // emit attributes
-    vertBuilder->emitAttributes(de);
+    varyingHandler->emitAttributes(de);
 
     // XY refers to dashPos, Z is the dash interval length
     GrGLSLVertToFrag inDashParams(kVec3f_GrSLType);
-    args.fPB->addVarying("DashParams", &inDashParams, GrSLPrecision::kHigh_GrSLPrecision);
+    varyingHandler->addVarying("DashParams", &inDashParams, GrSLPrecision::kHigh_GrSLPrecision);
     vertBuilder->codeAppendf("%s = %s;", inDashParams.vsOut(), de.inDashParams()->fName);
 
     // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
     // respectively.
     GrGLSLVertToFrag inRectParams(kVec4f_GrSLType);
-    args.fPB->addVarying("RectParams", &inRectParams, GrSLPrecision::kHigh_GrSLPrecision);
+    varyingHandler->addVarying("RectParams", &inRectParams, GrSLPrecision::kHigh_GrSLPrecision);
     vertBuilder->codeAppendf("%s = %s;", inRectParams.vsOut(), de.inRectParams()->fName);
 
     GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
@@ -1091,6 +1095,7 @@
     // emit transforms
     this->emitTransforms(args.fPB,
                          vertBuilder,
+                         varyingHandler,
                          gpArgs->fPositionVar,
                          de.inPosition()->fName,
                          de.localMatrix(),
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index 1f3fede..cf77157 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -15,8 +15,9 @@
 #include "glsl/GrGLSLGeometryProcessor.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
-#include "glsl/GrGLSLVertexShaderBuilder.h"
 #include "glsl/GrGLSLUtil.h"
+#include "glsl/GrGLSLVarying.h"
+#include "glsl/GrGLSLVertexShaderBuilder.h"
 
 // Assuming a radius of a little less than the diagonal of the fragment
 #define SK_DistanceFieldAAFactor     "0.65"
@@ -40,9 +41,10 @@
                 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
 
         GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+        GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
         // emit attributes
-        vertBuilder->emitAttributes(dfTexEffect);
+        varyingHandler->emitAttributes(dfTexEffect);
 
 #ifdef SK_GAMMA_APPLY_TO_A8
         // adjust based on gamma
@@ -56,7 +58,7 @@
         // Setup pass through color
         if (!dfTexEffect.colorIgnored()) {
             if (dfTexEffect.hasVertexColor()) {
-                pb->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
+                varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
             } else {
                 this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform);
             }
@@ -73,6 +75,7 @@
         // emit transforms
         this->emitTransforms(pb,
                              vertBuilder,
+                             varyingHandler,
                              gpArgs->fPositionVar,
                              dfTexEffect.inPosition()->fName,
                              args.fTransformsIn,
@@ -82,7 +85,7 @@
         GrGLSLVertToFrag recipScale(kFloat_GrSLType);
         GrGLSLVertToFrag st(kVec2f_GrSLType);
         bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
-        pb->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
+        varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
         vertBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
 
         // compute numbers to be hardcoded to convert texture coordinates from int to float
@@ -93,7 +96,7 @@
         SkScalar recipHeight = 1.0f / atlas->height();
 
         GrGLSLVertToFrag uv(kVec2f_GrSLType);
-        pb->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
+        varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
         vertBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", uv.vsOut(),
                                  GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipWidth,
                                  GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipHeight,
@@ -299,17 +302,18 @@
                                      GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
 
         GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+        GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
         // emit attributes
-        vertBuilder->emitAttributes(dfTexEffect);
+        varyingHandler->emitAttributes(dfTexEffect);
 
         GrGLSLVertToFrag v(kVec2f_GrSLType);
-        pb->addVarying("TextureCoords", &v, kHigh_GrSLPrecision);
+        varyingHandler->addVarying("TextureCoords", &v, kHigh_GrSLPrecision);
 
         // setup pass through color
         if (!dfTexEffect.colorIgnored()) {
             if (dfTexEffect.hasVertexColor()) {
-                pb->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
+                varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
             } else {
                 this->setupUniformColor(pb, fragBuilder, args.fOutputColor, &fColorUniform);
             }
@@ -327,6 +331,7 @@
         // emit transforms
         this->emitTransforms(pb,
                              vertBuilder,
+                             varyingHandler,
                              gpArgs->fPositionVar,
                              dfTexEffect.inPosition()->fName,
                              args.fTransformsIn,
@@ -519,9 +524,10 @@
         GrGLSLGPBuilder* pb = args.fPB;
 
         GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
+        GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
 
         // emit attributes
-        vertBuilder->emitAttributes(dfTexEffect);
+        varyingHandler->emitAttributes(dfTexEffect);
 
         GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
 
@@ -541,6 +547,7 @@
         // emit transforms
         this->emitTransforms(pb,
                              vertBuilder,
+                             varyingHandler,
                              gpArgs->fPositionVar,
                              dfTexEffect.inPosition()->fName,
                              args.fTransformsIn,
@@ -550,7 +557,7 @@
         bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
         GrGLSLVertToFrag recipScale(kFloat_GrSLType);
         GrGLSLVertToFrag st(kVec2f_GrSLType);
-        pb->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
+        varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
         vertBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
 
         // compute numbers to be hardcoded to convert texture coordinates from int to float
@@ -561,7 +568,7 @@
         SkScalar recipHeight = 1.0f / atlas->height();
 
         GrGLSLVertToFrag uv(kVec2f_GrSLType);
-        pb->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
+        varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
         vertBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", uv.vsOut(),
                                  GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipWidth,
                                  GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipHeight,
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 1fe1d17..3cf9e4d 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -30,7 +30,7 @@
                          const BuiltinUniformHandles& builtinUniforms,
                          GrGLuint programID,
                          const UniformInfoArray& uniforms,
-                         const SeparableVaryingInfoArray& separableVaryings,
+                         const VaryingInfoArray& pathProcVaryings,
                          GrGLInstalledGeoProc* geometryProcessor,
                          GrGLInstalledXferProc* xferProcessor,
                          GrGLInstalledFragProcs* fragmentProcessors,
@@ -42,7 +42,7 @@
     , fFragmentProcessors(SkRef(fragmentProcessors))
     , fDesc(desc)
     , fGpu(gpu)
-    , fProgramDataManager(gpu, programID, uniforms, separableVaryings) {
+    , fProgramDataManager(gpu, programID, uniforms, pathProcVaryings) {
     fSamplerUniforms.swap(passSamplerUniforms);
     // Assign texture units to sampler uniforms one time up front.
     GL_CALL(UseProgram(fProgramID));
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 117d5a2..72fa9b0 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -99,14 +99,14 @@
 protected:
     typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
     typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray;
-    typedef GrGLProgramDataManager::SeparableVaryingInfoArray SeparableVaryingInfoArray;
+    typedef GrGLProgramDataManager::VaryingInfoArray VaryingInfoArray;
 
     GrGLProgram(GrGLGpu*,
                 const GrProgramDesc&,
                 const BuiltinUniformHandles&,
                 GrGLuint programID,
                 const UniformInfoArray&,
-                const SeparableVaryingInfoArray&,
+                const VaryingInfoArray&, // used for NVPR only currently
                 GrGLInstalledGeoProc* geometryProcessor,
                 GrGLInstalledXferProc* xferProcessor,
                 GrGLInstalledFragProcs* fragmentProcessors,
diff --git a/src/gpu/gl/GrGLProgramDataManager.cpp b/src/gpu/gl/GrGLProgramDataManager.cpp
index 7320b2d..a61e697 100644
--- a/src/gpu/gl/GrGLProgramDataManager.cpp
+++ b/src/gpu/gl/GrGLProgramDataManager.cpp
@@ -15,7 +15,7 @@
 
 GrGLProgramDataManager::GrGLProgramDataManager(GrGLGpu* gpu, GrGLuint programID,
                                                const UniformInfoArray& uniforms,
-                                               const SeparableVaryingInfoArray& separableVaryings)
+                                               const VaryingInfoArray& pathProcVaryings)
     : fGpu(gpu)
     , fProgramID(programID) {
     int count = uniforms.count();
@@ -44,19 +44,19 @@
     }
 
     // NVPR programs have separable varyings
-    count = separableVaryings.count();
-    fSeparableVaryings.push_back_n(count);
+    count = pathProcVaryings.count();
+    fPathProcVaryings.push_back_n(count);
     for (int i = 0; i < count; i++) {
         SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
-        SeparableVarying& separableVarying = fSeparableVaryings[i];
-        const SeparableVaryingInfo& builderSeparableVarying = separableVaryings[i];
-        SkASSERT(GrGLSLShaderVar::kNonArray == builderSeparableVarying.fVariable.getArrayCount() ||
-                 builderSeparableVarying.fVariable.getArrayCount() > 0);
+        PathProcVarying& pathProcVarying = fPathProcVaryings[i];
+        const VaryingInfo& builderPathProcVarying = pathProcVaryings[i];
+        SkASSERT(GrGLSLShaderVar::kNonArray == builderPathProcVarying.fVariable.getArrayCount() ||
+                 builderPathProcVarying.fVariable.getArrayCount() > 0);
         SkDEBUGCODE(
-            separableVarying.fArrayCount = builderSeparableVarying.fVariable.getArrayCount();
-            separableVarying.fType = builderSeparableVarying.fVariable.getType();
+            pathProcVarying.fArrayCount = builderPathProcVarying.fVariable.getArrayCount();
+            pathProcVarying.fType = builderPathProcVarying.fVariable.getType();
         );
-        separableVarying.fLocation = builderSeparableVarying.fLocation;
+        pathProcVarying.fLocation = builderPathProcVarying.fLocation;
     }
 }
 
@@ -276,11 +276,11 @@
     this->setMatrix3f(u, mt);
 }
 
-void GrGLProgramDataManager::setPathFragmentInputTransform(SeparableVaryingHandle u,
+void GrGLProgramDataManager::setPathFragmentInputTransform(VaryingHandle u,
                                                            int components,
                                                            const SkMatrix& matrix) const {
     SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
-    const SeparableVarying& fragmentInput = fSeparableVaryings[u.toIndex()];
+    const PathProcVarying& fragmentInput = fPathProcVaryings[u.toIndex()];
 
     SkASSERT((components == 2 && fragmentInput.fType == kVec2f_GrSLType) ||
               (components == 3 && fragmentInput.fType == kVec3f_GrSLType));
diff --git a/src/gpu/gl/GrGLProgramDataManager.h b/src/gpu/gl/GrGLProgramDataManager.h
index ea7b19e..d477453 100644
--- a/src/gpu/gl/GrGLProgramDataManager.h
+++ b/src/gpu/gl/GrGLProgramDataManager.h
@@ -33,7 +33,7 @@
         GrGLint         fLocation;
     };
 
-    struct SeparableVaryingInfo {
+    struct VaryingInfo {
         GrGLSLShaderVar fVariable;
         GrGLint         fLocation;
     };
@@ -42,10 +42,10 @@
     // after they are inserted. Users of GrGLShaderBuilder get refs to the vars and ptrs to their
     // name strings. Otherwise, we'd have to hand out copies.
     typedef GrTAllocator<UniformInfo> UniformInfoArray;
-    typedef GrTAllocator<SeparableVaryingInfo> SeparableVaryingInfoArray;
+    typedef GrTAllocator<VaryingInfo> VaryingInfoArray;
 
     GrGLProgramDataManager(GrGLGpu*, GrGLuint programID, const UniformInfoArray&,
-                           const SeparableVaryingInfoArray&);
+                           const VaryingInfoArray&);
 
     /** Functions for uploading uniform values. The varities ending in v can be used to upload to an
      *  array of uniforms. arrayCount must be <= the array count of the uniform.
@@ -71,7 +71,7 @@
     void setSkMatrix(UniformHandle, const SkMatrix&) const override;
 
     // for nvpr only
-    void setPathFragmentInputTransform(SeparableVaryingHandle u, int components,
+    void setPathFragmentInputTransform(VaryingHandle u, int components,
                                        const SkMatrix& matrix) const override;
 
 private:
@@ -89,9 +89,9 @@
     };
 
     enum {
-        kUnusedSeparableVarying = -1,
+        kUnusedPathProcVarying = -1,
     };
-    struct SeparableVarying {
+    struct PathProcVarying {
         GrGLint     fLocation;
         SkDEBUGCODE(
             GrSLType    fType;
@@ -102,7 +102,7 @@
     SkDEBUGCODE(void printUnused(const Uniform&) const;)
 
     SkTArray<Uniform, true> fUniforms;
-    SkTArray<SeparableVarying, true> fSeparableVaryings;
+    SkTArray<PathProcVarying, true> fPathProcVaryings;
     GrGLGpu* fGpu;
     GrGLuint fProgramID;
 
diff --git a/src/gpu/gl/GrGLVaryingHandler.cpp b/src/gpu/gl/GrGLVaryingHandler.cpp
new file mode 100644
index 0000000..b27a996
--- /dev/null
+++ b/src/gpu/gl/GrGLVaryingHandler.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gl/GrGLVaryingHandler.h"
+
+#include "gl/GrGLGpu.h"
+#include "gl/builders/GrGLProgramBuilder.h"
+
+
+GrGLSLVaryingHandler::VaryingHandle GrGLVaryingHandler::addPathProcessingVarying(
+                                                                       const char* name,
+                                                                       GrGLSLVertToFrag* v,
+                                                                       GrSLPrecision fsPrecision) {
+#ifdef SK_DEBUG
+    GrGLProgramBuilder* glPB = (GrGLProgramBuilder*) fProgramBuilder;
+    // This call is not used for non-NVPR backends.
+    SkASSERT(glPB->gpu()->glCaps().shaderCaps()->pathRenderingSupport() &&
+             glPB->fArgs.fPrimitiveProcessor->isPathRendering() &&
+             !glPB->fArgs.fPrimitiveProcessor->willUseGeoShader() &&
+             glPB->fArgs.fPrimitiveProcessor->numAttribs() == 0);
+#endif
+    this->addVarying(name, v, fsPrecision);
+    VaryingInfo& varyingInfo = fPathProcVaryingInfos.push_back();
+    varyingInfo.fVariable = fFragInputs.back();
+    varyingInfo.fLocation = fPathProcVaryingInfos.count() - 1;
+    return VaryingHandle(varyingInfo.fLocation);
+}
diff --git a/src/gpu/gl/GrGLVaryingHandler.h b/src/gpu/gl/GrGLVaryingHandler.h
new file mode 100644
index 0000000..ab931de
--- /dev/null
+++ b/src/gpu/gl/GrGLVaryingHandler.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLVaryingHandler_DEFINED
+#define GrGLVaryingHandler_DEFINED
+
+#include "glsl/GrGLSLVarying.h"
+#include "GrTypesPriv.h"
+#include "gl/GrGLProgramDataManager.h"
+
+class GrGLVaryingHandler : public GrGLSLVaryingHandler {
+public:
+    GrGLVaryingHandler(GrGLSLProgramBuilder* program)
+        : INHERITED(program),
+        fPathProcVaryingInfos(kVaryingsPerBlock) {}
+
+    // This function is used by the NVPR PathProcessor to add a varying directly into the fragment
+    // shader since there is no vertex shader.
+    VaryingHandle addPathProcessingVarying(const char* name, GrGLSLVertToFrag*,
+                                       GrSLPrecision fsPrecision = kDefault_GrSLPrecision);
+
+private:
+    typedef GrGLProgramDataManager::VaryingInfo VaryingInfo;
+    typedef GrGLProgramDataManager::VaryingInfoArray VaryingInfoArray;
+
+    VaryingInfoArray fPathProcVaryingInfos;
+
+    friend class GrGLProgramBuilder;
+
+    typedef GrGLSLVaryingHandler INHERITED; 
+};
+
+#endif
+
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 2283405..0ae4f96 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -57,47 +57,7 @@
     , fGpu(gpu)
     , fUniforms(kVarsPerBlock)
     , fSamplerUniforms(4)
-    , fSeparableVaryingInfos(kVarsPerBlock) {
-}
-
-void GrGLProgramBuilder::addVarying(const char* name,
-                                    GrGLSLVarying* varying,
-                                    GrSLPrecision precision) {
-    SkASSERT(varying);
-    if (varying->vsVarying()) {
-        fVS.addVarying(name, precision, varying);
-    }
-    if (this->primitiveProcessor().willUseGeoShader()) {
-        fGS.addVarying(name, precision, varying);
-    }
-    if (varying->fsVarying()) {
-        fFS.addVarying(varying, precision);
-    }
-}
-
-void GrGLProgramBuilder::addPassThroughAttribute(const GrPrimitiveProcessor::Attribute* input,
-                                                 const char* output) {
-    GrSLType type = GrVertexAttribTypeToSLType(input->fType);
-    GrGLSLVertToFrag v(type);
-    this->addVarying(input->fName, &v);
-    fVS.codeAppendf("%s = %s;", v.vsOut(), input->fName);
-    fFS.codeAppendf("%s = %s;", output, v.fsIn());
-}
-
-GrGLProgramBuilder::SeparableVaryingHandle GrGLProgramBuilder::addSeparableVarying(
-                                                                        const char* name,
-                                                                        GrGLSLVertToFrag* v,
-                                                                        GrSLPrecision fsPrecision) {
-    // This call is not used for non-NVPR backends.
-    SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport() &&
-             fArgs.fPrimitiveProcessor->isPathRendering() &&
-             !fArgs.fPrimitiveProcessor->willUseGeoShader() &&
-             fArgs.fPrimitiveProcessor->numAttribs() == 0);
-    this->addVarying(name, v, fsPrecision);
-    SeparableVaryingInfo& varyingInfo = fSeparableVaryingInfos.push_back();
-    varyingInfo.fVariable = fFS.fInputs.back();
-    varyingInfo.fLocation = fSeparableVaryingInfos.count() - 1;
-    return SeparableVaryingHandle(varyingInfo.fLocation);
+    , fVaryingHandler(this) {
 }
 
 GrGLSLProgramDataManager::UniformHandle GrGLProgramBuilder::internalAddUniformArray(
@@ -289,6 +249,7 @@
     GrGLSLGeometryProcessor::EmitArgs args(this,
                                            &fVS,
                                            &fFS,
+                                           &fVaryingHandler,
                                            this->glslCaps(),
                                            gp,
                                            outColor,
@@ -474,12 +435,11 @@
         !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
         return;
     }
-    int count = fSeparableVaryingInfos.count();
+    int count = fVaryingHandler.fPathProcVaryingInfos.count();
     for (int i = 0; i < count; ++i) {
-        GL_CALL(BindFragmentInputLocation(programID,
-                                          i,
-                                          fSeparableVaryingInfos[i].fVariable.c_str()));
-        fSeparableVaryingInfos[i].fLocation = i;
+        GL_CALL(BindFragmentInputLocation(programID, i,
+                                       fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
+        fVaryingHandler.fPathProcVaryingInfos[i].fLocation = i;
     }
 }
 
@@ -522,14 +482,14 @@
         !fGpu->glPathRendering()->shouldBindFragmentInputs()) {
         return;
     }
-    int count = fSeparableVaryingInfos.count();
+    int count = fVaryingHandler.fPathProcVaryingInfos.count();
     for (int i = 0; i < count; ++i) {
         GrGLint location;
-        GL_CALL_RET(location,
-                    GetProgramResourceLocation(programID,
-                                               GR_GL_FRAGMENT_INPUT,
-                                               fSeparableVaryingInfos[i].fVariable.c_str()));
-        fSeparableVaryingInfos[i].fLocation = location;
+        GL_CALL_RET(location, GetProgramResourceLocation(
+                                       programID,
+                                       GR_GL_FRAGMENT_INPUT,
+                                       fVaryingHandler.fPathProcVaryingInfos[i].fVariable.c_str()));
+        fVaryingHandler.fPathProcVaryingInfos[i].fLocation = location;
     }
 }
 
@@ -545,7 +505,7 @@
 
 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
     return new GrGLProgram(fGpu, this->desc(), fUniformHandles, programID, fUniforms,
-                           fSeparableVaryingInfos,
+                           fVaryingHandler.fPathProcVaryingInfos,
                            fGeometryProcessor, fXferProcessor, fFragmentProcessors.get(),
                            &fSamplerUniforms);
 }
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index 3a8dcd8..edc467c 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -10,6 +10,7 @@
 
 #include "GrPipeline.h"
 #include "gl/GrGLProgramDataManager.h"
+#include "gl/GrGLVaryingHandler.h"
 #include "glsl/GrGLSLPrimitiveProcessor.h"
 #include "glsl/GrGLSLProgramBuilder.h"
 #include "glsl/GrGLSLProgramDataManager.h"
@@ -69,24 +70,9 @@
 
     GrGLGpu* gpu() const { return fGpu; }
 
-    void addVarying(
-            const char* name,
-            GrGLSLVarying*,
-            GrSLPrecision precision = kDefault_GrSLPrecision) override;
-
-    void addPassThroughAttribute(const GrPrimitiveProcessor::Attribute*,
-                                 const char* output) override;
-
-    SeparableVaryingHandle addSeparableVarying(
-        const char* name,
-        GrGLSLVertToFrag*,
-        GrSLPrecision fsPrecision = kDefault_GrSLPrecision) override;
-
 private:
     typedef GrGLProgramDataManager::UniformInfo UniformInfo;
     typedef GrGLProgramDataManager::UniformInfoArray UniformInfoArray;
-    typedef GrGLProgramDataManager::SeparableVaryingInfo SeparableVaryingInfo;
-    typedef GrGLProgramDataManager::SeparableVaryingInfoArray SeparableVaryingInfoArray;
 
     GrGLProgramBuilder(GrGLGpu*, const DrawArgs&);
 
@@ -148,6 +134,8 @@
 
     void onAppendUniformDecls(ShaderVisibility visibility, SkString* out) const override;
 
+    GrGLSLVaryingHandler* varyingHandler() override { return &fVaryingHandler; }
+
     // reset is called by program creator between each processor's emit code.  It increments the
     // stage offset for variable name mangling, and also ensures verfication variables in the
     // fragment shader are cleared.
@@ -179,13 +167,11 @@
     GrGLSLPrimitiveProcessor::TransformsIn fCoordTransforms;
     GrGLSLPrimitiveProcessor::TransformsOut fOutCoords;
     SkTArray<UniformHandle> fSamplerUniforms;
-    SeparableVaryingInfoArray fSeparableVaryingInfos;
 
-    friend class GrGLSLShaderBuilder;
-    friend class GrGLSLVertexBuilder;
-    friend class GrGLSLFragmentShaderBuilder;
-    friend class GrGLSLGeometryBuilder;
+    GrGLVaryingHandler        fVaryingHandler;
 
-   typedef GrGLSLProgramBuilder INHERITED; 
+    friend class GrGLVaryingHandler; 
+
+    typedef GrGLSLProgramBuilder INHERITED; 
 };
 #endif
diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
index 5a3e09d..122db10 100644
--- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp
@@ -10,6 +10,7 @@
 #include "glsl/GrGLSL.h"
 #include "glsl/GrGLSLCaps.h"
 #include "glsl/GrGLSLProgramBuilder.h"
+#include "glsl/GrGLSLVarying.h"
 
 const char* GrGLSLFragmentShaderBuilder::kDstTextureColorName = "_dstColor";
 
@@ -237,19 +238,12 @@
 }
 
 void GrGLSLFragmentShaderBuilder::onFinalize() {
+    fProgramBuilder->varyingHandler()->getFragDecls(&this->inputs(), &this->outputs());
     GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
                                                  *fProgramBuilder->glslCaps(),
                                                  &this->precisionQualifier());
 }
 
-void GrGLSLFragmentShaderBuilder::addVarying(GrGLSLVarying* v, GrSLPrecision fsPrec) {
-    v->fFsIn = v->fVsOut;
-    if (v->fGsOut) {
-        v->fFsIn = v->fGsOut;
-    }
-    fInputs.push_back().set(v->fType, GrGLSLShaderVar::kVaryingIn_TypeModifier, v->fFsIn, fsPrec);
-}
-
 void GrGLSLFragmentBuilder::onBeforeChildProcEmitCode() {
     SkASSERT(fSubstageIndices.count() >= 1);
     fSubstageIndices.push_back(0);
diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
index 706a8a8..8a1e81a 100644
--- a/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
+++ b/src/gpu/glsl/GrGLSLGeometryProcessor.cpp
@@ -10,6 +10,7 @@
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
 #include "glsl/GrGLSLProcessorTypes.h"
 #include "glsl/GrGLSLProgramBuilder.h"
+#include "glsl/GrGLSLVarying.h"
 #include "glsl/GrGLSLVertexShaderBuilder.h"
 
 void GrGLSLGeometryProcessor::emitCode(EmitArgs& args) {
@@ -21,6 +22,7 @@
 
 void GrGLSLGeometryProcessor::emitTransforms(GrGLSLGPBuilder* pb,
                                              GrGLSLVertexBuilder* vb,
+                                             GrGLSLVaryingHandler* varyingHandler,
                                              const GrShaderVar& posVar,
                                              const char* localCoords,
                                              const SkMatrix& localMatrix,
@@ -56,7 +58,7 @@
             strVaryingName.appendf("_%i_%i", i, t);
 
             GrGLSLVertToFrag v(varyingType);
-            pb->addVarying(strVaryingName.c_str(), &v, precision);
+            varyingHandler->addVarying(strVaryingName.c_str(), &v, precision);
 
             SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
             SkNEW_APPEND_TO_TARRAY(&(*tout)[i], GrGLSLTransformedCoords,
@@ -94,6 +96,7 @@
 
 void GrGLSLGeometryProcessor::emitTransforms(GrGLSLGPBuilder* pb,
                                              GrGLSLVertexBuilder* vb,
+                                             GrGLSLVaryingHandler* varyingHandler,
                                              const char* localCoords,
                                              const TransformsIn& tin,
                                              TransformsOut* tout) {
@@ -111,7 +114,7 @@
             strVaryingName.appendf("_%i_%i", i, t);
 
             GrGLSLVertToFrag v(varyingType);
-            pb->addVarying(strVaryingName.c_str(), &v, precision);
+            varyingHandler->addVarying(strVaryingName.c_str(), &v, precision);
             vb->codeAppendf("%s = %s;", v.vsOut(), localCoords);
 
             SkNEW_APPEND_TO_TARRAY(&(*tout)[i],
diff --git a/src/gpu/glsl/GrGLSLGeometryProcessor.h b/src/gpu/glsl/GrGLSLGeometryProcessor.h
index 1d9c512..4c586a7 100644
--- a/src/gpu/glsl/GrGLSLGeometryProcessor.h
+++ b/src/gpu/glsl/GrGLSLGeometryProcessor.h
@@ -44,16 +44,18 @@
     // Emit a uniform matrix for each coord transform.
     void emitTransforms(GrGLSLGPBuilder* gp,
                         GrGLSLVertexBuilder* vb,
+                        GrGLSLVaryingHandler* varyingHandler,
                         const GrShaderVar& posVar,
                         const char* localCoords,
                         const TransformsIn& tin,
                         TransformsOut* tout) {
-        this->emitTransforms(gp, vb, posVar, localCoords, SkMatrix::I(), tin, tout);
+        this->emitTransforms(gp, vb, varyingHandler, posVar, localCoords, SkMatrix::I(), tin, tout);
     }
 
     // Emit pre-transformed coords as a vertex attribute per coord-transform.
     void emitTransforms(GrGLSLGPBuilder*,
                         GrGLSLVertexBuilder*,
+                        GrGLSLVaryingHandler*,
                         const GrShaderVar& posVar,
                         const char* localCoords,
                         const SkMatrix& localMatrix,
@@ -63,6 +65,7 @@
     // caller has emitted transforms via attributes
     void emitTransforms(GrGLSLGPBuilder*,
                         GrGLSLVertexBuilder*,
+                        GrGLSLVaryingHandler*,
                         const char* localCoords,
                         const TransformsIn& tin,
                         TransformsOut* tout);
diff --git a/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp b/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp
index 275972b..25e9f9e 100644
--- a/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLGeometryShaderBuilder.cpp
@@ -7,34 +7,14 @@
 
 #include "GrGLSLGeometryShaderBuilder.h"
 #include "GrGLSLProgramBuilder.h"
+#include "GrGLSLVarying.h"
 
 GrGLSLGeometryBuilder::GrGLSLGeometryBuilder(GrGLSLProgramBuilder* program)
     : INHERITED(program) {
 
 }
 
-void GrGLSLGeometryBuilder::addVarying(const char* name,
-                                       GrSLPrecision precision,
-                                       GrGLSLVarying* v) {
-    // if we have a GS take each varying in as an array
-    // and output as non-array.
-    if (v->vsVarying()) {
-        fInputs.push_back();
-        fInputs.back().setType(v->fType);
-        fInputs.back().setTypeModifier(GrGLSLShaderVar::kVaryingIn_TypeModifier);
-        fInputs.back().setPrecision(precision);
-        fInputs.back().setUnsizedArray();
-        *fInputs.back().accessName() = v->fVsOut;
-        v->fGsIn = v->fVsOut;
-    }
-
-    if (v->fsVarying()) {
-        fOutputs.push_back();
-        fOutputs.back().setType(v->fType);
-        fOutputs.back().setTypeModifier(GrGLSLShaderVar::kVaryingOut_TypeModifier);
-        fOutputs.back().setPrecision(precision);
-        fProgramBuilder->nameVariable(fOutputs.back().accessName(), 'g', name);
-        v->fGsOut = fOutputs.back().getName().c_str();
-    }
+void GrGLSLGeometryBuilder::onFinalize() {
+    fProgramBuilder->varyingHandler()->getGeomDecls(&this->inputs(), &this->outputs());
 }
 
diff --git a/src/gpu/glsl/GrGLSLGeometryShaderBuilder.h b/src/gpu/glsl/GrGLSLGeometryShaderBuilder.h
index ca24c79..f5e09f1 100644
--- a/src/gpu/glsl/GrGLSLGeometryShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLGeometryShaderBuilder.h
@@ -17,12 +17,7 @@
     GrGLSLGeometryBuilder(GrGLSLProgramBuilder* program);
 
 private:
-    /*
-     * an internal call for GrGLFullProgramBuilder to add varyings
-     */
-    void addVarying(const char* name, GrSLPrecision precision, GrGLSLVarying*);
-
-    void onFinalize() override {}
+    void onFinalize() override;
 
     friend class GrGLProgramBuilder;
 
diff --git a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
index a458237..d164bbe 100644
--- a/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
+++ b/src/gpu/glsl/GrGLSLPrimitiveProcessor.h
@@ -18,6 +18,7 @@
 class GrGLSLCaps;
 class GrGLSLFragmentBuilder;
 class GrGLSLGPBuilder;
+class GrGLSLVaryingHandler;
 class GrGLSLVertexBuilder;
 
 class GrGLSLPrimitiveProcessor {
@@ -35,6 +36,7 @@
         EmitArgs(GrGLSLGPBuilder* pb,
                  GrGLSLVertexBuilder* vertBuilder,
                  GrGLSLFragmentBuilder* fragBuilder,
+                 GrGLSLVaryingHandler* varyingHandler,
                  const GrGLSLCaps* caps,
                  const GrPrimitiveProcessor& gp,
                  const char* outputColor,
@@ -45,6 +47,7 @@
             : fPB(pb)
             , fVertBuilder(vertBuilder)
             , fFragBuilder(fragBuilder)
+            , fVaryingHandler(varyingHandler)
             , fGLSLCaps(caps)
             , fGP(gp)
             , fOutputColor(outputColor)
@@ -55,6 +58,7 @@
         GrGLSLGPBuilder* fPB;
         GrGLSLVertexBuilder* fVertBuilder;
         GrGLSLFragmentBuilder* fFragBuilder;
+        GrGLSLVaryingHandler* fVaryingHandler;
         const GrGLSLCaps* fGLSLCaps;
         const GrPrimitiveProcessor& fGP;
         const char* fOutputColor;
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h
index e87ab0a..8103708 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.h
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.h
@@ -17,6 +17,7 @@
 
 class GrGLSLCaps;
 class GrGLSLShaderVar;
+class GrGLSLVaryingHandler;
 
 // Enough precision to represent 1 / 2048 accurately in printf
 #define GR_SIGNIFICANT_POW2_DECIMAL_DIG 11
@@ -32,7 +33,6 @@
     virtual ~GrGLSLUniformBuilder() {}
 
     typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
-    typedef GrGLSLProgramDataManager::SeparableVaryingHandle SeparableVaryingHandle;
 
     /** Add a uniform variable to the current program, that has visibility in one or more shaders.
         visibility is a bitfield of ShaderVisibility values indicating from which shaders the
@@ -79,91 +79,10 @@
         const char** outName) = 0;
 };
 
-// TODO move this into GrGLSLGPBuilder and move them both out of this file
-class GrGLSLVarying {
-public:
-    bool vsVarying() const { return kVertToFrag_Varying == fVarying ||
-                                    kVertToGeo_Varying == fVarying; }
-    bool fsVarying() const { return kVertToFrag_Varying == fVarying ||
-                                    kGeoToFrag_Varying == fVarying; }
-    const char* vsOut() const { return fVsOut; }
-    const char* gsIn() const { return fGsIn; }
-    const char* gsOut() const { return fGsOut; }
-    const char* fsIn() const { return fFsIn; }
-    GrSLType type() const { return fType; }
-
-protected:
-    enum Varying {
-        kVertToFrag_Varying,
-        kVertToGeo_Varying,
-        kGeoToFrag_Varying,
-    };
-
-    GrGLSLVarying(GrSLType type, Varying varying)
-        : fVarying(varying), fType(type), fVsOut(nullptr), fGsIn(nullptr), fGsOut(nullptr),
-          fFsIn(nullptr) {}
-
-    Varying fVarying;
-
-private:
-    GrSLType fType;
-    const char* fVsOut;
-    const char* fGsIn;
-    const char* fGsOut;
-    const char* fFsIn;
-
-    friend class GrGLSLVertexBuilder;
-    friend class GrGLSLGeometryBuilder;
-    friend class GrGLSLXferBuilder;
-    friend class GrGLSLFragmentShaderBuilder;
-};
-
-struct GrGLSLVertToFrag : public GrGLSLVarying {
-    GrGLSLVertToFrag(GrSLType type)
-        : GrGLSLVarying(type, kVertToFrag_Varying) {}
-};
-
-struct GrGLSLVertToGeo : public GrGLSLVarying {
-    GrGLSLVertToGeo(GrSLType type)
-        : GrGLSLVarying(type, kVertToGeo_Varying) {}
-};
-
-struct GrGLSLGeoToFrag : public GrGLSLVarying {
-    GrGLSLGeoToFrag(GrSLType type)
-        : GrGLSLVarying(type, kGeoToFrag_Varying) {}
-};
-
 /* a specialization of the above for GPs.  Lets the user add uniforms, varyings, and VS / FS code */
 class GrGLSLGPBuilder : public virtual GrGLSLUniformBuilder {
 public:
     /*
-     * addVarying allows fine grained control for setting up varyings between stages.  If you just
-     * need to take an attribute and pass it through to an output value in a fragment shader, use
-     * addPassThroughAttribute.
-     * TODO convert most uses of addVarying to addPassThroughAttribute
-     */
-    virtual void addVarying(const char* name,
-                            GrGLSLVarying*,
-                            GrSLPrecision precision = kDefault_GrSLPrecision) = 0;
-
-    /*
-     * This call can be used by GP to pass an attribute through all shaders directly to 'output' in
-     * the fragment shader.  Though this call effects both the vertex shader and fragment shader,
-     * it expects 'output' to be defined in the fragment shader before this call is made.
-     * TODO it might be nicer behavior to have a flag to declare output inside this call
-     */
-    virtual void addPassThroughAttribute(const GrGeometryProcessor::Attribute*,
-                                         const char* output) = 0;
-
-    /*
-     * Creates a fragment shader varying that can be referred to.
-     * Comparable to GrGLSLUniformBuilder::addUniform().
-     */
-    virtual SeparableVaryingHandle addSeparableVarying(
-        const char* name, GrGLSLVertToFrag*,
-        GrSLPrecision fsPrecision = kDefault_GrSLPrecision) = 0;
-
-    /*
      * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE
      */
 };
@@ -229,12 +148,15 @@
     // explicitly asked not to.
     void nameVariable(SkString* out, char prefix, const char* name, bool mangle = true);
 
+    virtual GrGLSLVaryingHandler* varyingHandler() = 0;
+
     // number of each input/output type in a single allocation block, used by many builders
     static const int kVarsPerBlock;
 
-    GrGLSLVertexBuilder fVS;
-    GrGLSLGeometryBuilder fGS;
+    GrGLSLVertexBuilder         fVS;
+    GrGLSLGeometryBuilder       fGS;
     GrGLSLFragmentShaderBuilder fFS;
+
     int fStageIndex;
 
     BuiltinUniformHandles fUniformHandles;
@@ -248,6 +170,7 @@
     friend class GrGLSLVertexBuilder;
     friend class GrGLSLFragmentShaderBuilder;
     friend class GrGLSLGeometryBuilder;
+    friend class GrGLSLVaryingHandler;
 };
 
 #endif
diff --git a/src/gpu/glsl/GrGLSLProgramDataManager.h b/src/gpu/glsl/GrGLSLProgramDataManager.h
index 2009fea..1a8f639 100644
--- a/src/gpu/glsl/GrGLSLProgramDataManager.h
+++ b/src/gpu/glsl/GrGLSLProgramDataManager.h
@@ -65,8 +65,8 @@
     virtual void setSkMatrix(UniformHandle, const SkMatrix&) const = 0;
 
     // for nvpr only
-    typedef ShaderResourceHandle SeparableVaryingHandle;
-    virtual void setPathFragmentInputTransform(SeparableVaryingHandle u, int components,
+    typedef ShaderResourceHandle VaryingHandle;
+    virtual void setPathFragmentInputTransform(VaryingHandle u, int components,
                                                const SkMatrix& matrix) const = 0;
 
 protected:
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
index d4d16fc..1fc15ec 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.cpp
@@ -190,10 +190,6 @@
     fProgramBuilder->appendUniformDecls((GrGLSLProgramBuilder::ShaderVisibility) visibility,
                                         &this->uniforms());
     this->appendDecls(fInputs, &this->inputs());
-    // We should not have any outputs in the fragment shader when using version 1.10
-    SkASSERT(GrGLSLProgramBuilder::kFragment_Visibility != visibility ||
-             k110_GrGLSLGeneration != fProgramBuilder->glslCaps()->generation() ||
-             fOutputs.empty());
     this->appendDecls(fOutputs, &this->outputs());
     this->onFinalize();
     // append the 'footer' to code
diff --git a/src/gpu/glsl/GrGLSLShaderBuilder.h b/src/gpu/glsl/GrGLSLShaderBuilder.h
index fde48dc..1a8255d 100644
--- a/src/gpu/glsl/GrGLSLShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLShaderBuilder.h
@@ -25,9 +25,6 @@
     GrGLSLShaderBuilder(GrGLSLProgramBuilder* program);
     virtual ~GrGLSLShaderBuilder() {}
 
-    void addInput(const GrGLSLShaderVar& input) { fInputs.push_back(input); }
-    void addOutput(const GrGLSLShaderVar& output) { fOutputs.push_back(output); }
-
     /*
      * We put texture lookups in the base class because it is TECHNICALLY possible to do texture
      * lookups in any kind of shader.  However, for the time being using these calls on non-fragment
diff --git a/src/gpu/glsl/GrGLSLVarying.cpp b/src/gpu/glsl/GrGLSLVarying.cpp
new file mode 100644
index 0000000..279dd59
--- /dev/null
+++ b/src/gpu/glsl/GrGLSLVarying.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "glsl/GrGLSLVarying.h"
+
+#include "glsl/GrGLSLProgramBuilder.h"
+
+void GrGLSLVaryingHandler::addPassThroughAttribute(const GrGeometryProcessor::Attribute* input,
+                                                   const char* output) {
+    GrSLType type = GrVertexAttribTypeToSLType(input->fType);
+    GrGLSLVertToFrag v(type);
+    this->addVarying(input->fName, &v);
+    fProgramBuilder->fVS.codeAppendf("%s = %s;", v.vsOut(), input->fName);
+
+    if (fProgramBuilder->primitiveProcessor().willUseGeoShader()) {
+        fProgramBuilder->fGS.codeAppendf("%s = %s[0];", v.gsOut(), v.gsIn());
+    }
+
+    fProgramBuilder->fFS.codeAppendf("%s = %s;", output, v.fsIn());
+}
+
+void GrGLSLVaryingHandler::addVarying(const char* name,
+                                      GrGLSLVarying* varying,
+                                      GrSLPrecision precision) {
+    SkASSERT(varying);
+    if (varying->vsVarying()) {
+        this->addVertexVarying(name, precision, varying);
+    }
+    if (fProgramBuilder->primitiveProcessor().willUseGeoShader()) {
+        this->addGeomVarying(name, precision, varying);
+    }
+    if (varying->fsVarying()) {
+        this->addFragVarying(precision, varying);
+    }
+}
+
+void GrGLSLVaryingHandler::addVertexVarying(const char* name,
+                                            GrSLPrecision precision,
+                                            GrGLSLVarying* v) {
+    fVertexOutputs.push_back();
+    fVertexOutputs.back().setType(v->fType);
+    fVertexOutputs.back().setTypeModifier(GrGLSLShaderVar::kVaryingOut_TypeModifier);
+    fVertexOutputs.back().setPrecision(precision);
+    fProgramBuilder->nameVariable(fVertexOutputs.back().accessName(), 'v', name);
+    v->fVsOut = fVertexOutputs.back().getName().c_str();
+}
+void GrGLSLVaryingHandler::addGeomVarying(const char* name,
+                                          GrSLPrecision precision,
+                                          GrGLSLVarying* v) {
+    // if we have a GS take each varying in as an array
+    // and output as non-array.
+    if (v->vsVarying()) {
+        fGeomInputs.push_back();
+        fGeomInputs.back().setType(v->fType);
+        fGeomInputs.back().setTypeModifier(GrGLSLShaderVar::kVaryingIn_TypeModifier);
+        fGeomInputs.back().setPrecision(precision);
+        fGeomInputs.back().setUnsizedArray();
+        *fGeomInputs.back().accessName() = v->fVsOut;
+        v->fGsIn = v->fVsOut;
+    }
+
+    if (v->fsVarying()) {
+        fGeomOutputs.push_back();
+        fGeomOutputs.back().setType(v->fType);
+        fGeomOutputs.back().setTypeModifier(GrGLSLShaderVar::kVaryingOut_TypeModifier);
+        fGeomOutputs.back().setPrecision(precision);
+        fProgramBuilder->nameVariable(fGeomOutputs.back().accessName(), 'g', name);
+        v->fGsOut = fGeomOutputs.back().getName().c_str();
+    }
+}
+
+void GrGLSLVaryingHandler::addFragVarying(GrSLPrecision precision, GrGLSLVarying* v) {
+    v->fFsIn = v->fGsOut ? v->fGsOut : v->fVsOut;
+    fFragInputs.push_back().set(v->fType,
+                                GrGLSLShaderVar::kVaryingIn_TypeModifier,
+                                v->fFsIn,
+                                precision);
+}
+
+void GrGLSLVaryingHandler::emitAttributes(const GrGeometryProcessor& gp) {
+    int vaCount = gp.numAttribs();
+    for (int i = 0; i < vaCount; i++) {
+        const GrGeometryProcessor::Attribute& attr = gp.getAttrib(i);
+        this->addAttribute(GrShaderVar(attr.fName,
+                                       GrVertexAttribTypeToSLType(attr.fType),
+                                       GrShaderVar::kAttribute_TypeModifier,
+                                       GrShaderVar::kNonArray,
+                                       attr.fPrecision));
+    }
+}
+
+void GrGLSLVaryingHandler::addAttribute(const GrShaderVar& var) {
+    SkASSERT(GrShaderVar::kAttribute_TypeModifier == var.getTypeModifier());
+    for (int j = 0; j < fVertexInputs.count(); ++j) {
+        const GrGLSLShaderVar& attr = fVertexInputs[j];
+        // if attribute already added, don't add it again
+        if (attr.getName().equals(var.getName())) {
+            return;
+        }
+    }
+    fVertexInputs.push_back(var);
+}
+
+void GrGLSLVaryingHandler::appendDecls(const VarArray& vars, SkString* out) const {
+    for (int i = 0; i < vars.count(); ++i) {
+        vars[i].appendDecl(fProgramBuilder->glslCaps(), out);
+        out->append(";");
+    }
+}
+
+void GrGLSLVaryingHandler::getVertexDecls(SkString* inputDecls, SkString* outputDecls) const {
+    this->appendDecls(fVertexInputs, inputDecls);
+    this->appendDecls(fVertexOutputs, outputDecls);
+}
+
+void GrGLSLVaryingHandler::getGeomDecls(SkString* inputDecls, SkString* outputDecls) const {
+    this->appendDecls(fGeomInputs, inputDecls);
+    this->appendDecls(fGeomOutputs, outputDecls);
+}
+
+void GrGLSLVaryingHandler::getFragDecls(SkString* inputDecls, SkString* outputDecls) const {
+    // We should not have any outputs in the fragment shader when using version 1.10
+    SkASSERT(k110_GrGLSLGeneration != fProgramBuilder->glslCaps()->generation() ||
+             fFragOutputs.empty());
+    this->appendDecls(fFragInputs, inputDecls);
+    this->appendDecls(fFragOutputs, outputDecls);
+}
+
diff --git a/src/gpu/glsl/GrGLSLVarying.h b/src/gpu/glsl/GrGLSLVarying.h
new file mode 100644
index 0000000..116ba09
--- /dev/null
+++ b/src/gpu/glsl/GrGLSLVarying.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLSLVarying_DEFINED
+#define GrGLSLVarying_DEFINED
+
+#include "GrAllocator.h"
+#include "GrGeometryProcessor.h"
+#include "GrTypesPriv.h"
+#include "glsl/GrGLSLProgramDataManager.h"
+#include "glsl/GrGLSLShaderVar.h"
+
+class GrGLSLProgramBuilder;
+
+class GrGLSLVarying {
+public:
+    bool vsVarying() const { return kVertToFrag_Varying == fVarying ||
+                                    kVertToGeo_Varying == fVarying; }
+    bool fsVarying() const { return kVertToFrag_Varying == fVarying ||
+                                    kGeoToFrag_Varying == fVarying; }
+    const char* vsOut() const { return fVsOut; }
+    const char* gsIn() const { return fGsIn; }
+    const char* gsOut() const { return fGsOut; }
+    const char* fsIn() const { return fFsIn; }
+    GrSLType type() const { return fType; }
+
+protected:
+    enum Varying {
+        kVertToFrag_Varying,
+        kVertToGeo_Varying,
+        kGeoToFrag_Varying,
+    };
+
+    GrGLSLVarying(GrSLType type, Varying varying)
+        : fVarying(varying), fType(type), fVsOut(nullptr), fGsIn(nullptr), fGsOut(nullptr),
+          fFsIn(nullptr) {}
+
+    Varying fVarying;
+
+private:
+    GrSLType fType;
+    const char* fVsOut;
+    const char* fGsIn;
+    const char* fGsOut;
+    const char* fFsIn;
+
+    friend class GrGLSLVaryingHandler;
+};
+
+struct GrGLSLVertToFrag : public GrGLSLVarying {
+    GrGLSLVertToFrag(GrSLType type)
+        : GrGLSLVarying(type, kVertToFrag_Varying) {}
+};
+
+struct GrGLSLVertToGeo : public GrGLSLVarying {
+    GrGLSLVertToGeo(GrSLType type)
+        : GrGLSLVarying(type, kVertToGeo_Varying) {}
+};
+
+struct GrGLSLGeoToFrag : public GrGLSLVarying {
+    GrGLSLGeoToFrag(GrSLType type)
+        : GrGLSLVarying(type, kGeoToFrag_Varying) {}
+};
+
+static const int kVaryingsPerBlock = 8;
+
+class GrGLSLVaryingHandler {
+public:
+    explicit GrGLSLVaryingHandler(GrGLSLProgramBuilder* program)
+        : fVertexInputs(kVaryingsPerBlock)
+        , fVertexOutputs(kVaryingsPerBlock)
+        , fGeomInputs(kVaryingsPerBlock)
+        , fGeomOutputs(kVaryingsPerBlock)
+        , fFragInputs(kVaryingsPerBlock)
+        , fFragOutputs(kVaryingsPerBlock)
+        , fProgramBuilder(program) {}
+
+    typedef GrTAllocator<GrGLSLShaderVar> VarArray;
+    typedef GrGLSLProgramDataManager::VaryingHandle VaryingHandle;
+
+    /*
+     * addVarying allows fine grained control for setting up varyings between stages. Calling this
+     * functions will make sure all necessary decls are setup for the client. The client however is
+     * responsible for setting up all shader code (e.g "vOut = vIn;") If you just need to take an
+     * attribute and pass it through to an output value in a fragment shader, use
+     * addPassThroughAttribute.
+     * TODO convert most uses of addVarying to addPassThroughAttribute
+     */
+    void addVarying(const char* name,
+                    GrGLSLVarying*,
+                    GrSLPrecision precision = kDefault_GrSLPrecision);
+
+    /*
+     * This call can be used by GP to pass an attribute through all shaders directly to 'output' in
+     * the fragment shader.  Though this call effects both the vertex shader and fragment shader,
+     * it expects 'output' to be defined in the fragment shader before this call is made. If there
+     * is a geometry shader, we will simply take the value of the varying from the first vertex and
+     * that will be set as the output varying for all emitted vertices.
+     * TODO it might be nicer behavior to have a flag to declare output inside this call
+     */
+    void addPassThroughAttribute(const GrGeometryProcessor::Attribute*, const char* output);
+
+    void emitAttributes(const GrGeometryProcessor& gp);
+
+    void getVertexDecls(SkString* inputDecls, SkString* outputDecls) const;
+    void getGeomDecls(SkString* inputDecls, SkString* outputDecls) const;
+    void getFragDecls(SkString* inputDecls, SkString* outputDecls) const;
+protected:
+    VarArray fVertexInputs;
+    VarArray fVertexOutputs;
+    VarArray fGeomInputs;
+    VarArray fGeomOutputs;
+    VarArray fFragInputs;
+    VarArray fFragOutputs;
+
+    // This is not owned by the class
+    GrGLSLProgramBuilder* fProgramBuilder;
+
+private:
+    void addVertexVarying(const char* name, GrSLPrecision precision, GrGLSLVarying* v);
+    void addGeomVarying(const char* name, GrSLPrecision precision, GrGLSLVarying* v);
+    void addFragVarying(GrSLPrecision precision, GrGLSLVarying* v);
+
+    void addAttribute(const GrShaderVar& var);
+
+    // helper function for get*Decls
+    void appendDecls(const VarArray& vars, SkString* out) const;
+
+    friend class GrGLSLProgramBuilder;
+};
+
+#endif
diff --git a/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp b/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp
index 1f68d0e..73c0fcd 100644
--- a/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLVertexShaderBuilder.cpp
@@ -7,29 +7,13 @@
 
 #include "GrGLSLVertexShaderBuilder.h"
 #include "glsl/GrGLSLProgramBuilder.h"
+#include "glsl/GrGLSLVarying.h"
 
 GrGLSLVertexBuilder::GrGLSLVertexBuilder(GrGLSLProgramBuilder* program)
     : INHERITED(program)
     , fRtAdjustName(nullptr) {
 }
 
-void GrGLSLVertexBuilder::addVarying(const char* name, GrSLPrecision precision, GrGLSLVarying* v) {
-    fOutputs.push_back();
-    fOutputs.back().setType(v->fType);
-    fOutputs.back().setTypeModifier(GrGLSLShaderVar::kVaryingOut_TypeModifier);
-    fOutputs.back().setPrecision(precision);
-    fProgramBuilder->nameVariable(fOutputs.back().accessName(), 'v', name);
-    v->fVsOut = fOutputs.back().getName().c_str();
-}
-
-void GrGLSLVertexBuilder::emitAttributes(const GrGeometryProcessor& gp) {
-    int vaCount = gp.numAttribs();
-    for (int i = 0; i < vaCount; i++) {
-        this->addAttribute(&gp.getAttrib(i));
-    }
-    return;
-}
-
 void GrGLSLVertexBuilder::transformToNormalizedDeviceSpace(const GrShaderVar& posVar) {
     SkASSERT(!fRtAdjustName);
 
@@ -72,16 +56,7 @@
     this->codeAppend("gl_PointSize = 1.0;");
 }
 
-bool GrGLSLVertexBuilder::addAttribute(const GrShaderVar& var) {
-    SkASSERT(GrShaderVar::kAttribute_TypeModifier == var.getTypeModifier());
-    for (int i = 0; i < fInputs.count(); ++i) {
-        const GrGLSLShaderVar& attr = fInputs[i];
-        // if attribute already added, don't add it again
-        if (attr.getName().equals(var.getName())) {
-            return false;
-        }
-    }
-    fInputs.push_back(var);
-    return true;
+void GrGLSLVertexBuilder::onFinalize() {
+    fProgramBuilder->varyingHandler()->getVertexDecls(&this->inputs(), &this->outputs());
 }
 
diff --git a/src/gpu/glsl/GrGLSLVertexShaderBuilder.h b/src/gpu/glsl/GrGLSLVertexShaderBuilder.h
index 92edd9a..b76721f 100644
--- a/src/gpu/glsl/GrGLSLVertexShaderBuilder.h
+++ b/src/gpu/glsl/GrGLSLVertexShaderBuilder.h
@@ -18,26 +18,8 @@
     GrGLSLVertexBuilder(GrGLSLProgramBuilder* program);
 
     void transformToNormalizedDeviceSpace(const GrShaderVar& posVar);
-    void emitAttributes(const GrGeometryProcessor& gp);
-
-    void addAttribute(const GrGeometryProcessor::Attribute* attr) {
-        this->addAttribute(GrShaderVar(attr->fName,
-                                       GrVertexAttribTypeToSLType(attr->fType),
-                                       GrShaderVar::kAttribute_TypeModifier,
-                                       GrShaderVar::kNonArray,
-                                       attr->fPrecision));
-    }
-
 private:
-    /*
-     * Internal call for GrGLProgramBuilder.addVarying
-     */
-    void addVarying(const char* name, GrSLPrecision, GrGLSLVarying*);
-
-    // an internal call which checks for uniquness of a var before adding it to the list of inputs
-    bool addAttribute(const GrShaderVar& var);
-
-    void onFinalize() override {}
+    void onFinalize() override;
     
     const char* fRtAdjustName;