Added varying struct

TBR=
BUG=skia:

Review URL: https://codereview.chromium.org/671023002
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index ef4a171..eecc722 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -529,38 +529,38 @@
             : INHERITED (factory) {}
 
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
-            const char *vsName, *fsName;
-            args.fPB->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
+            GrGLVertToFrag v(kVec4f_GrSLType);
+            args.fPB->addVarying("QuadEdge", &v);
 
             GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
 
             SkAssertResult(fsBuilder->enableFeature(
                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
-            fsBuilder->codeAppendf("\t\tfloat edgeAlpha;\n");
+            fsBuilder->codeAppendf("float edgeAlpha;");
 
             // keep the derivative instructions outside the conditional
-            fsBuilder->codeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            fsBuilder->codeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            fsBuilder->codeAppendf("\t\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
+            fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn());
+            fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn());
+            fsBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn());
             // today we know z and w are in device space. We could use derivatives
-            fsBuilder->codeAppendf("\t\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
-                                    fsName);
-            fsBuilder->codeAppendf ("\t\t} else {\n");
-            fsBuilder->codeAppendf("\t\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
-                                   "\t\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
-                                   fsName, fsName);
-            fsBuilder->codeAppendf("\t\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
-                                    fsName);
-            fsBuilder->codeAppendf("\t\t\tedgeAlpha = "
-                                   "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n\t\t}\n");
+            fsBuilder->codeAppendf("edgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);", v.fsIn(),
+                                    v.fsIn());
+            fsBuilder->codeAppendf ("} else {");
+            fsBuilder->codeAppendf("vec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,"
+                                   "               2.0*%s.x*duvdy.x - duvdy.y);",
+                                   v.fsIn(), v.fsIn());
+            fsBuilder->codeAppendf("edgeAlpha = (%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(),
+                                    v.fsIn());
+            fsBuilder->codeAppendf("edgeAlpha = "
+                                   "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);}");
 
 
-            fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
+            fsBuilder->codeAppendf("%s = %s;", args.fOutput,
                                    (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("edgeAlpha")).c_str());
 
             const GrShaderVar& inQuadEdge = args.fGP.cast<QuadEdgeEffect>().inQuadEdge();
             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsName, inQuadEdge.c_str());
+            vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), inQuadEdge.c_str());
         }
 
         static inline void GenKey(const GrProcessor&, const GrGLCaps&, GrProcessorKeyBuilder*) {}
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index e5d1593..18bba5a 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -45,17 +45,17 @@
             // 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;
-            args.fPB->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
+            GrGLVertToFrag v(kVec4f_GrSLType);
+            args.fPB->addVarying("Rect", &v);
 
             const GrShaderVar& inRect = args.fGP.cast<GrAlignedRectEffect>().inRect();
             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsRectName, inRect.c_str());
+            vsBuilder->codeAppendf("\t%s = %s;\n", v.fsIn(), inRect.c_str());
 
             GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
             // TODO: compute all these offsets, spans, and scales in the VS
-            fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
-            fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
+            fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", v.fsIn());
+            fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", v.fsIn());
             fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
             // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
             // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
@@ -69,12 +69,12 @@
 
             // Compute the coverage for the rect's width
             fsBuilder->codeAppendf(
-                "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
-                fsRectName);
+                "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", v.fsIn(),
+                v.fsIn());
             // Compute the coverage for the rect's height and merge with the width
             fsBuilder->codeAppendf(
                 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
-                fsRectName, fsRectName);
+                v.fsIn(), v.fsIn());
 
 
             fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
@@ -163,26 +163,24 @@
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
             // setup the varying for the center point and the unit vector
             // that points down the height of the rect
-            const char *vsRectEdgeName, *fsRectEdgeName;
-            args.fPB->addVarying(kVec4f_GrSLType, "RectEdge",
-                                &vsRectEdgeName, &fsRectEdgeName);
+            GrGLVertToFrag rectEdge(kVec4f_GrSLType);
+            args.fPB->addVarying("RectEdge", &rectEdge);
 
             const GrRectEffect& rectEffect = args.fGP.cast<GrRectEffect>();
             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-            vsBuilder->codeAppendf("%s = %s;", vsRectEdgeName, rectEffect.inRectEdge().c_str());
+            vsBuilder->codeAppendf("%s = %s;", rectEdge.vsOut(), rectEffect.inRectEdge().c_str());
 
             // setup the varying for width/2+.5 and height/2+.5
-            const char *vsWidthHeightName, *fsWidthHeightName;
-            args.fPB->addVarying(kVec2f_GrSLType, "WidthHeight",
-                                &vsWidthHeightName, &fsWidthHeightName);
+            GrGLVertToFrag widthHeight(kVec2f_GrSLType);
+            args.fPB->addVarying("WidthHeight", &widthHeight);
             vsBuilder->codeAppendf("%s = %s;",
-                                   vsWidthHeightName,
+                                   widthHeight.vsOut(),
                                    rectEffect.inWidthHeight().c_str());
 
             GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
             // TODO: compute all these offsets, spans, and scales in the VS
-            fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
-            fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
+            fsBuilder->codeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", widthHeight.fsIn());
+            fsBuilder->codeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", widthHeight.fsIn());
             fsBuilder->codeAppend("\tfloat outset = 0.5;\n");
             // For rects > 1 pixel wide and tall the span's are noops (i.e., 1.0). For rects
             // < 1 pixel wide or tall they serve to normalize the < 1 ramp to a 0 .. 1 range.
@@ -196,19 +194,19 @@
 
             // Compute the coverage for the rect's width
             fsBuilder->codeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
-                                   fsBuilder->fragmentPosition(), fsRectEdgeName);
+                                   fsBuilder->fragmentPosition(), rectEdge.fsIn());
             fsBuilder->codeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
-                                   fsRectEdgeName, fsRectEdgeName);
+                                   rectEdge.fsIn(), rectEdge.fsIn());
             fsBuilder->codeAppendf(
                 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
-                fsWidthHeightName);
+                widthHeight.fsIn());
 
             // Compute the coverage for the rect's height and merge with the width
             fsBuilder->codeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
-                                   fsRectEdgeName);
+                                   rectEdge.fsIn());
             fsBuilder->codeAppendf(
                     "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
-                    fsWidthHeightName);
+                    widthHeight.fsIn());
 
 
             fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 8c3b99c..72a0181 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -94,21 +94,22 @@
 
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
             const CircleEdgeEffect& circleEffect = args.fGP.cast<CircleEdgeEffect>();
-            const char *vsName, *fsName;
-            args.fPB->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
+            GrGLVertToFrag v(kVec4f_GrSLType);
+            args.fPB->addVarying("CircleEdge", &v);
 
             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();;
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsName, circleEffect.inCircleEdge().c_str());
+            vsBuilder->codeAppendf("%s = %s;", v.vsOut(), circleEffect.inCircleEdge().c_str());
 
             GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
-            fsBuilder->codeAppendf("\tfloat d = length(%s.xy);\n", fsName);
-            fsBuilder->codeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
+            fsBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn());
+            fsBuilder->codeAppendf("float edgeAlpha = clamp(%s.z - d, 0.0, 1.0);", v.fsIn());
             if (circleEffect.isStroked()) {
-                fsBuilder->codeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName);
-                fsBuilder->codeAppend("\tedgeAlpha *= innerAlpha;\n");
+                fsBuilder->codeAppendf("float innerAlpha = clamp(d - %s.w, 0.0, 1.0);",
+                                       v.fsIn());
+                fsBuilder->codeAppend("edgeAlpha *= innerAlpha;");
             }
 
-            fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
+            fsBuilder->codeAppendf("%s = %s;\n", args.fOutput,
                                    (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("edgeAlpha")).c_str());
         }
 
@@ -206,39 +207,43 @@
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
             const EllipseEdgeEffect& ellipseEffect = args.fGP.cast<EllipseEdgeEffect>();
 
-            const char *vsOffsetName, *fsOffsetName;
-            const char *vsRadiiName, *fsRadiiName;
-
-            args.fPB->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName, &fsOffsetName);
+            GrGLVertToFrag ellipseOffsets(kVec2f_GrSLType);
+            args.fPB->addVarying("EllipseOffsets", &ellipseOffsets);
 
             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-            vsBuilder->codeAppendf("%s = %s;", vsOffsetName,
+            vsBuilder->codeAppendf("%s = %s;", ellipseOffsets.vsOut(),
                                    ellipseEffect.inEllipseOffset().c_str());
 
-            args.fPB->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName);
-            vsBuilder->codeAppendf("%s = %s;", vsRadiiName, ellipseEffect.inEllipseRadii().c_str());
+            GrGLVertToFrag ellipseRadii(kVec4f_GrSLType);
+            args.fPB->addVarying("EllipseRadii", &ellipseRadii);
+            vsBuilder->codeAppendf("%s = %s;", ellipseRadii.vsOut(),
+                                   ellipseEffect.inEllipseRadii().c_str());
 
             // for outer curve
             GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
-            fsBuilder->codeAppendf("\tvec2 scaledOffset = %s*%s.xy;\n", fsOffsetName, fsRadiiName);
-            fsBuilder->codeAppend("\tfloat test = dot(scaledOffset, scaledOffset) - 1.0;\n");
-            fsBuilder->codeAppendf("\tvec2 grad = 2.0*scaledOffset*%s.xy;\n", fsRadiiName);
-            fsBuilder->codeAppend("\tfloat grad_dot = dot(grad, grad);\n");
+            fsBuilder->codeAppendf("vec2 scaledOffset = %s*%s.xy;", ellipseOffsets.fsIn(),
+                                   ellipseRadii.fsIn());
+            fsBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
+            fsBuilder->codeAppendf("vec2 grad = 2.0*scaledOffset*%s.xy;", ellipseRadii.fsIn());
+            fsBuilder->codeAppend("float grad_dot = dot(grad, grad);");
+
             // avoid calling inversesqrt on zero.
-            fsBuilder->codeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n");
-            fsBuilder->codeAppend("\tfloat invlen = inversesqrt(grad_dot);\n");
-            fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n");
+            fsBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
+            fsBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
+            fsBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
 
             // for inner curve
             if (ellipseEffect.isStroked()) {
-                fsBuilder->codeAppendf("\tscaledOffset = %s*%s.zw;\n", fsOffsetName, fsRadiiName);
-                fsBuilder->codeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n");
-                fsBuilder->codeAppendf("\tgrad = 2.0*scaledOffset*%s.zw;\n", fsRadiiName);
-                fsBuilder->codeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n");
-                fsBuilder->codeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
+                fsBuilder->codeAppendf("scaledOffset = %s*%s.zw;",
+                                       ellipseOffsets.fsIn(), ellipseRadii.fsIn());
+                fsBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
+                fsBuilder->codeAppendf("grad = 2.0*scaledOffset*%s.zw;",
+                                       ellipseRadii.fsIn());
+                fsBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
+                fsBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
             }
 
-            fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
+            fsBuilder->codeAppendf("%s = %s;", args.fOutput,
                                    (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("edgeAlpha")).c_str());
         }
 
@@ -348,57 +353,57 @@
         virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
             const DIEllipseEdgeEffect& ellipseEffect = args.fGP.cast<DIEllipseEdgeEffect>();
 
-            const char *vsOffsetName0, *fsOffsetName0;
-            args.fPB->addVarying(kVec2f_GrSLType, "EllipseOffsets0",
-                                      &vsOffsetName0, &fsOffsetName0);
+            GrGLVertToFrag offsets0(kVec2f_GrSLType);
+            args.fPB->addVarying("EllipseOffsets0", &offsets0);
 
             GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-            vsBuilder->codeAppendf("%s = %s;", vsOffsetName0,
+            vsBuilder->codeAppendf("%s = %s;", offsets0.vsOut(),
                                    ellipseEffect.inEllipseOffsets0().c_str());
-            const char *vsOffsetName1, *fsOffsetName1;
-            args.fPB->addVarying(kVec2f_GrSLType, "EllipseOffsets1",
-                                      &vsOffsetName1, &fsOffsetName1);
-            vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName1,
+
+            GrGLVertToFrag offsets1(kVec2f_GrSLType);
+            args.fPB->addVarying("EllipseOffsets1", &offsets1);
+            vsBuilder->codeAppendf("%s = %s;", offsets1.vsOut(),
                                    ellipseEffect.inEllipseOffsets1().c_str());
 
             GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
             SkAssertResult(fsBuilder->enableFeature(
                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
             // for outer curve
-            fsBuilder->codeAppendf("\tvec2 scaledOffset = %s.xy;\n", fsOffsetName0);
-            fsBuilder->codeAppend("\tfloat test = dot(scaledOffset, scaledOffset) - 1.0;\n");
-            fsBuilder->codeAppendf("\tvec2 duvdx = dFdx(%s);\n", fsOffsetName0);
-            fsBuilder->codeAppendf("\tvec2 duvdy = dFdy(%s);\n", fsOffsetName0);
-            fsBuilder->codeAppendf("\tvec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,\n"
-                                   "\t                 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);\n",
-                                   fsOffsetName0, fsOffsetName0, fsOffsetName0, fsOffsetName0);
+            fsBuilder->codeAppendf("vec2 scaledOffset = %s.xy;", offsets0.fsIn());
+            fsBuilder->codeAppend("float test = dot(scaledOffset, scaledOffset) - 1.0;");
+            fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s);", offsets0.fsIn());
+            fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s);", offsets0.fsIn());
+            fsBuilder->codeAppendf("vec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
+                                   "                 2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
+                                   offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn(), offsets0.fsIn());
 
-            fsBuilder->codeAppend("\tfloat grad_dot = dot(grad, grad);\n");
+            fsBuilder->codeAppend("float grad_dot = dot(grad, grad);");
             // avoid calling inversesqrt on zero.
-            fsBuilder->codeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n");
-            fsBuilder->codeAppend("\tfloat invlen = inversesqrt(grad_dot);\n");
+            fsBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
+            fsBuilder->codeAppend("float invlen = inversesqrt(grad_dot);");
             if (kHairline == ellipseEffect.getMode()) {
                 // can probably do this with one step
-                fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);\n");
-                fsBuilder->codeAppend("\tedgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);\n");
+                fsBuilder->codeAppend("float edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);");
+                fsBuilder->codeAppend("edgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);");
             } else {
-                fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n");
+                fsBuilder->codeAppend("float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);");
             }
 
             // for inner curve
             if (kStroke == ellipseEffect.getMode()) {
-                fsBuilder->codeAppendf("\tscaledOffset = %s.xy;\n", fsOffsetName1);
-                fsBuilder->codeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n");
-                fsBuilder->codeAppendf("\tduvdx = dFdx(%s);\n", fsOffsetName1);
-                fsBuilder->codeAppendf("\tduvdy = dFdy(%s);\n", fsOffsetName1);
-                fsBuilder->codeAppendf("\tgrad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,\n"
-                                       "\t            2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);\n",
-                                       fsOffsetName1, fsOffsetName1, fsOffsetName1, fsOffsetName1);
-                fsBuilder->codeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n");
-                fsBuilder->codeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
+                fsBuilder->codeAppendf("scaledOffset = %s.xy;", offsets1.fsIn());
+                fsBuilder->codeAppend("test = dot(scaledOffset, scaledOffset) - 1.0;");
+                fsBuilder->codeAppendf("duvdx = dFdx(%s);", offsets1.fsIn());
+                fsBuilder->codeAppendf("duvdy = dFdy(%s);", offsets1.fsIn());
+                fsBuilder->codeAppendf("grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,"
+                                       "            2.0*%s.x*duvdy.x + 2.0*%s.y*duvdy.y);",
+                                       offsets1.fsIn(), offsets1.fsIn(), offsets1.fsIn(),
+                                       offsets1.fsIn());
+                fsBuilder->codeAppend("invlen = inversesqrt(dot(grad, grad));");
+                fsBuilder->codeAppend("edgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);");
             }
 
-            fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
+            fsBuilder->codeAppendf("%s = %s;", args.fOutput,
                                    (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("edgeAlpha")).c_str());
         }
 
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 661923d..196168c 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -37,13 +37,12 @@
 }
 
 void GrGLConicEffect::emitCode(const EmitArgs& args) {
-    const char *vsName, *fsName;
-
-    args.fPB->addVarying(kVec4f_GrSLType, "ConicCoeffs", &vsName, &fsName);
+    GrGLVertToFrag v(kVec4f_GrSLType);
+    args.fPB->addVarying("ConicCoeffs", &v);
 
     const GrShaderVar& inConicCoeffs = args.fGP.cast<GrConicEffect>().inConicCoeffs();
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-    vsBuilder->codeAppendf("%s = %s;", vsName, inConicCoeffs.c_str());
+    vsBuilder->codeAppendf("%s = %s;", v.vsOut(), inConicCoeffs.c_str());
 
     GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
     fsBuilder->codeAppend("float edgeAlpha;");
@@ -52,18 +51,18 @@
         case kHairlineAA_GrProcessorEdgeType: {
             SkAssertResult(fsBuilder->enableFeature(
                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
-            fsBuilder->codeAppendf("vec3 dklmdx = dFdx(%s.xyz);", fsName);
-            fsBuilder->codeAppendf("vec3 dklmdy = dFdy(%s.xyz);", fsName);
+            fsBuilder->codeAppendf("vec3 dklmdx = dFdx(%s.xyz);", v.fsIn());
+            fsBuilder->codeAppendf("vec3 dklmdy = dFdy(%s.xyz);", v.fsIn());
             fsBuilder->codeAppendf("float dfdx ="
                                    "2.0 * %s.x * dklmdx.x - %s.y * dklmdx.z - %s.z * dklmdx.y;",
-                                   fsName, fsName, fsName);
+                                   v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppendf("float dfdy ="
                                    "2.0 * %s.x * dklmdy.x - %s.y * dklmdy.z - %s.z * dklmdy.y;",
-                                   fsName, fsName, fsName);
+                                   v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppend("vec2 gF = vec2(dfdx, dfdy);");
             fsBuilder->codeAppend("float gFM = sqrt(dot(gF, gF));");
-            fsBuilder->codeAppendf("float func = %s.x*%s.x - %s.y*%s.z;", fsName, fsName,
-                                   fsName, fsName);
+            fsBuilder->codeAppendf("float func = %s.x*%s.x - %s.y*%s.z;", v.fsIn(), v.fsIn(),
+                                   v.fsIn(), v.fsIn());
             fsBuilder->codeAppend("func = abs(func);");
             fsBuilder->codeAppend("edgeAlpha = func / gFM;");
             fsBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);");
@@ -74,18 +73,18 @@
         case kFillAA_GrProcessorEdgeType: {
             SkAssertResult(fsBuilder->enableFeature(
                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
-            fsBuilder->codeAppendf("vec3 dklmdx = dFdx(%s.xyz);", fsName);
-            fsBuilder->codeAppendf("vec3 dklmdy = dFdy(%s.xyz);", fsName);
+            fsBuilder->codeAppendf("vec3 dklmdx = dFdx(%s.xyz);", v.fsIn());
+            fsBuilder->codeAppendf("vec3 dklmdy = dFdy(%s.xyz);", v.fsIn());
             fsBuilder->codeAppendf("float dfdx ="
                                    "2.0 * %s.x * dklmdx.x - %s.y * dklmdx.z - %s.z * dklmdx.y;",
-                                   fsName, fsName, fsName);
+                                   v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppendf("float dfdy ="
                                    "2.0 * %s.x * dklmdy.x - %s.y * dklmdy.z - %s.z * dklmdy.y;",
-                                   fsName, fsName, fsName);
+                                   v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppend("vec2 gF = vec2(dfdx, dfdy);");
             fsBuilder->codeAppend("float gFM = sqrt(dot(gF, gF));");
-            fsBuilder->codeAppendf("float func = %s.x * %s.x - %s.y * %s.z;", fsName, fsName,
-                                   fsName, fsName);
+            fsBuilder->codeAppendf("float func = %s.x * %s.x - %s.y * %s.z;", v.fsIn(), v.fsIn(),
+                                   v.fsIn(), v.fsIn());
             fsBuilder->codeAppend("edgeAlpha = func / gFM;");
             fsBuilder->codeAppend("edgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);");
             // Add line below for smooth cubic ramp
@@ -93,8 +92,8 @@
             break;
         }
         case kFillBW_GrProcessorEdgeType: {
-            fsBuilder->codeAppendf("edgeAlpha = %s.x * %s.x - %s.y * %s.z;", fsName, fsName,
-                                   fsName, fsName);
+            fsBuilder->codeAppendf("edgeAlpha = %s.x * %s.x - %s.y * %s.z;", v.fsIn(), v.fsIn(),
+                                   v.fsIn(), v.fsIn());
             fsBuilder->codeAppend("edgeAlpha = float(edgeAlpha < 0.0);");
             break;
         }
@@ -178,12 +177,12 @@
 }
 
 void GrGLQuadEffect::emitCode(const EmitArgs& args) {
-    const char *vsName, *fsName;
-    args.fPB->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName);
+    GrGLVertToFrag v(kVec4f_GrSLType);
+    args.fPB->addVarying("HairQuadEdge", &v);
 
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
     const GrShaderVar& inHairQuadEdge = args.fGP.cast<GrQuadEffect>().inHairQuadEdge();
-    vsBuilder->codeAppendf("%s = %s;", vsName, inHairQuadEdge.c_str());
+    vsBuilder->codeAppendf("%s = %s;", v.vsOut(), inHairQuadEdge.c_str());
 
     GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
     fsBuilder->codeAppendf("float edgeAlpha;");
@@ -192,12 +191,12 @@
         case kHairlineAA_GrProcessorEdgeType: {
             SkAssertResult(fsBuilder->enableFeature(
                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
-            fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", fsName);
-            fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", fsName);
+            fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn());
+            fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn());
             fsBuilder->codeAppendf("vec2 gF = vec2(2.0 * %s.x * duvdx.x - duvdx.y,"
                                    "               2.0 * %s.x * duvdy.x - duvdy.y);",
-                                   fsName, fsName);
-            fsBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", fsName, fsName, fsName);
+                                   v.fsIn(), v.fsIn());
+            fsBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppend("edgeAlpha = sqrt(edgeAlpha * edgeAlpha / dot(gF, gF));");
             fsBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);");
             // Add line below for smooth cubic ramp
@@ -207,12 +206,12 @@
         case kFillAA_GrProcessorEdgeType: {
             SkAssertResult(fsBuilder->enableFeature(
                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
-            fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", fsName);
-            fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", fsName);
+            fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn());
+            fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn());
             fsBuilder->codeAppendf("vec2 gF = vec2(2.0 * %s.x * duvdx.x - duvdx.y,"
                                    "               2.0 * %s.x * duvdy.x - duvdy.y);",
-                                   fsName, fsName);
-            fsBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", fsName, fsName, fsName);
+                                   v.fsIn(), v.fsIn());
+            fsBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppend("edgeAlpha = edgeAlpha / sqrt(dot(gF, gF));");
             fsBuilder->codeAppend("edgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);");
             // Add line below for smooth cubic ramp
@@ -220,7 +219,7 @@
             break;
         }
         case kFillBW_GrProcessorEdgeType: {
-            fsBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", fsName, fsName, fsName);
+            fsBuilder->codeAppendf("edgeAlpha = (%s.x * %s.x - %s.y);", v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppend("edgeAlpha = float(edgeAlpha < 0.0);");
             break;
         }
@@ -304,14 +303,12 @@
 }
 
 void GrGLCubicEffect::emitCode(const EmitArgs& args) {
-    const char *vsName, *fsName;
-
-    args.fPB->addVarying(kVec4f_GrSLType, "CubicCoeffs",
-                         &vsName, &fsName, GrGLShaderVar::kHigh_Precision);
+    GrGLVertToFrag v(kVec4f_GrSLType);
+    args.fPB->addVarying("CubicCoeffs", &v, GrGLShaderVar::kHigh_Precision);
 
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
     const GrShaderVar& inCubicCoeffs = args.fGP.cast<GrCubicEffect>().inCubicCoeffs();
-    vsBuilder->codeAppendf("%s = %s;", vsName, inCubicCoeffs.c_str());
+    vsBuilder->codeAppendf("%s = %s;", v.vsOut(), inCubicCoeffs.c_str());
 
     GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
 
@@ -337,18 +334,18 @@
         case kHairlineAA_GrProcessorEdgeType: {
             SkAssertResult(fsBuilder->enableFeature(
                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
-            fsBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), fsName);
-            fsBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), fsName);
+            fsBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn());
+            fsBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn());
             fsBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
-                                   dfdx.c_str(), fsName, fsName, dklmdx.c_str(), fsName,
-                                   dklmdx.c_str(), fsName, dklmdx.c_str());
+                                   dfdx.c_str(), v.fsIn(), v.fsIn(), dklmdx.c_str(), v.fsIn(),
+                                   dklmdx.c_str(), v.fsIn(), dklmdx.c_str());
             fsBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
-                                   dfdy.c_str(), fsName, fsName, dklmdy.c_str(), fsName,
-                                   dklmdy.c_str(), fsName, dklmdy.c_str());
+                                   dfdy.c_str(), v.fsIn(), v.fsIn(), dklmdy.c_str(), v.fsIn(),
+                                   dklmdy.c_str(), v.fsIn(), dklmdy.c_str());
             fsBuilder->codeAppendf("%s = vec2(%s, %s);", gF.c_str(), dfdx.c_str(), dfdy.c_str());
             fsBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", gFM.c_str(), gF.c_str(), gF.c_str());
             fsBuilder->codeAppendf("%s = %s.x * %s.x * %s.x - %s.y * %s.z;",
-                                   func.c_str(), fsName, fsName, fsName, fsName, fsName);
+                                   func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppendf("%s = abs(%s);", func.c_str(), func.c_str());
             fsBuilder->codeAppendf("%s = %s / %s;",
                                    edgeAlpha.c_str(), func.c_str(), gFM.c_str());
@@ -363,19 +360,19 @@
         case kFillAA_GrProcessorEdgeType: {
             SkAssertResult(fsBuilder->enableFeature(
                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
-            fsBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), fsName);
-            fsBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), fsName);
+            fsBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn());
+            fsBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn());
             fsBuilder->codeAppendf("%s ="
                                    "3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
-                                   dfdx.c_str(), fsName, fsName, dklmdx.c_str(), fsName,
-                                   dklmdx.c_str(), fsName, dklmdx.c_str());
+                                   dfdx.c_str(), v.fsIn(), v.fsIn(), dklmdx.c_str(), v.fsIn(),
+                                   dklmdx.c_str(), v.fsIn(), dklmdx.c_str());
             fsBuilder->codeAppendf("%s = 3.0 * %s.x * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;",
-                                   dfdy.c_str(), fsName, fsName, dklmdy.c_str(), fsName,
-                                   dklmdy.c_str(), fsName, dklmdy.c_str());
+                                   dfdy.c_str(), v.fsIn(), v.fsIn(), dklmdy.c_str(), v.fsIn(),
+                                   dklmdy.c_str(), v.fsIn(), dklmdy.c_str());
             fsBuilder->codeAppendf("%s = vec2(%s, %s);", gF.c_str(), dfdx.c_str(), dfdy.c_str());
             fsBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", gFM.c_str(), gF.c_str(), gF.c_str());
             fsBuilder->codeAppendf("%s = %s.x * %s.x * %s.x - %s.y * %s.z;",
-                                   func.c_str(), fsName, fsName, fsName, fsName, fsName);
+                                   func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppendf("%s = %s / %s;",
                                    edgeAlpha.c_str(), func.c_str(), gFM.c_str());
             fsBuilder->codeAppendf("%s = clamp(1.0 - %s, 0.0, 1.0);",
@@ -388,7 +385,7 @@
         }
         case kFillBW_GrProcessorEdgeType: {
             fsBuilder->codeAppendf("%s = %s.x * %s.x * %s.x - %s.y * %s.z;",
-                                   edgeAlpha.c_str(), fsName, fsName, fsName, fsName, fsName);
+                                   edgeAlpha.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn());
             fsBuilder->codeAppendf("%s = float(%s < 0.0);", edgeAlpha.c_str(), edgeAlpha.c_str());
             break;
         }
diff --git a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
index 84f6b43..afa0754 100644
--- a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
+++ b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
@@ -24,23 +24,20 @@
                 args.fGP.cast<GrCustomCoordsTextureEffect>();
         SkASSERT(1 == customCoordsTextureEffect.getVertexAttribs().count());
 
-        SkString fsCoordName;
-        const char* vsVaryingName;
-        const char* fsVaryingNamePtr;
-        args.fPB->addVarying(kVec2f_GrSLType, "textureCoords", &vsVaryingName, &fsVaryingNamePtr);
-        fsCoordName = fsVaryingNamePtr;
+        GrGLVertToFrag v(kVec2f_GrSLType);
+        args.fPB->addVarying("TextureCoords", &v);
 
         GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
         const GrShaderVar& inTextureCoords = customCoordsTextureEffect.inTextureCoords();
-        vsBuilder->codeAppendf("\t%s = %s;\n", vsVaryingName, inTextureCoords.c_str());
+        vsBuilder->codeAppendf("%s = %s;", v.vsOut(), inTextureCoords.c_str());
 
         GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
-        fsBuilder->codeAppendf("\t%s = ", args.fOutput);
+        fsBuilder->codeAppendf("%s = ", args.fOutput);
         fsBuilder->appendTextureLookupAndModulate(args.fInput,
                                                   args.fSamplers[0],
-                                                  fsCoordName.c_str(),
+                                                  v.fsIn(),
                                                   kVec2f_GrSLType);
-        fsBuilder->codeAppend(";\n");
+        fsBuilder->codeAppend(";");
     }
 
     virtual void setData(const GrGLProgramDataManager&,
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index 4f6eef1..e15ffbe 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -514,17 +514,17 @@
                                          "params",
                                          &paramName);
 
-    const char *vsCoordName, *fsCoordName;
-    args.fPB->addVarying(kVec2f_GrSLType, "Coord", &vsCoordName, &fsCoordName);
+    GrGLVertToFrag v(kVec2f_GrSLType);
+    args.fPB->addVarying("Coord", &v);
 
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-    vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dce.inCoord().c_str());
+    vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), dce.inCoord().c_str());
 
     // transforms all points so that we can compare them to our test circle
     GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
     fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s.z) * %s.z;\n",
-                           fsCoordName, fsCoordName, paramName, paramName);
-    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", fsCoordName);
+                           v.fsIn(), v.fsIn(), paramName, paramName);
+    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", v.fsIn());
     fsBuilder->codeAppendf("\t\tvec2 center = vec2(%s.y, 0.0);\n", paramName);
     fsBuilder->codeAppend("\t\tfloat dist = length(center - fragPosShifted);\n");
     if (GrProcessorEdgeTypeIsAA(dce.getEdgeType())) {
@@ -718,16 +718,16 @@
                                             "interval",
                                             &intervalName);
 
-    const char *vsCoordName, *fsCoordName;
-    args.fPB->addVarying(kVec2f_GrSLType, "Coord", &vsCoordName, &fsCoordName);
+    GrGLVertToFrag v(kVec2f_GrSLType);
+    args.fPB->addVarying("Coord", &v);
     GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-    vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, de.inCoord().c_str());
+    vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), de.inCoord().c_str());
 
     // transforms all points so that we can compare them to our test rect
     GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
     fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s) * %s;\n",
-                           fsCoordName, fsCoordName, intervalName, intervalName);
-    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", fsCoordName);
+                           v.fsIn(), v.fsIn(), intervalName, intervalName);
+    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", v.fsIn());
     if (GrProcessorEdgeTypeIsAA(de.getEdgeType())) {
         // The amount of coverage removed in x and y by the edges is computed as a pair of negative
         // numbers, xSub and ySub.
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
index ca38e84..e90ebfb 100755
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
@@ -49,14 +49,11 @@
         SkAssertResult(fsBuilder->enableFeature(
                 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
 
-        SkString fsCoordName;
-        const char* vsCoordName;
-        const char* fsCoordNamePtr;
-        args.fPB->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
-        fsCoordName = fsCoordNamePtr;
+        GrGLVertToFrag v(kVec2f_GrSLType);
+        args.fPB->addVarying("TextureCoords", &v);
 
         GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-        vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
+        vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), dfTexEffect.inTextureCoords().c_str());
 
         const char* textureSizeUniName = NULL;
         fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
@@ -65,7 +62,7 @@
 
         fsBuilder->codeAppend("\tvec4 texColor = ");
         fsBuilder->appendTextureLookup(args.fSamplers[0],
-                                       fsCoordName.c_str(),
+                                       v.fsIn(),
                                        kVec2f_GrSLType);
         fsBuilder->codeAppend(";\n");
         fsBuilder->codeAppend("\tfloat distance = "
@@ -75,7 +72,7 @@
         // we adjust for the effect of the transformation on the distance by using
         // the length of the gradient of the texture coordinates. We use st coordinates
         // to ensure we're mapping 1:1 from texel space to pixel space.
-        fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
+        fsBuilder->codeAppendf("\tvec2 uv = %s;\n", v.fsIn());
         fsBuilder->codeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName);
         fsBuilder->codeAppend("\tfloat afwidth;\n");
         if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
@@ -264,14 +261,11 @@
         SkAssertResult(fsBuilder->enableFeature(
                                      GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
 
-        SkString fsCoordName;
-        const char* vsCoordName;
-        const char* fsCoordNamePtr;
-        args.fPB->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
-        fsCoordName = fsCoordNamePtr;
+        GrGLVertToFrag v(kVec2f_GrSLType);
+        args.fPB->addVarying("TextureCoords", &v);
 
         GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-        vsBuilder->codeAppendf("%s = %s;", vsCoordName, dfTexEffect.inTextureCoords().c_str());
+        vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords().c_str());
 
         const char* textureSizeUniName = NULL;
         fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
@@ -280,7 +274,7 @@
 
         fsBuilder->codeAppend("vec4 texColor = ");
         fsBuilder->appendTextureLookup(args.fSamplers[0],
-                                       fsCoordName.c_str(),
+                                       v.fsIn(),
                                        kVec2f_GrSLType);
         fsBuilder->codeAppend(";");
         fsBuilder->codeAppend("float distance = "
@@ -289,7 +283,7 @@
         // we adjust for the effect of the transformation on the distance by using
         // the length of the gradient of the texture coordinates. We use st coordinates
         // to ensure we're mapping 1:1 from texel space to pixel space.
-        fsBuilder->codeAppendf("vec2 uv = %s;", fsCoordName.c_str());
+        fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
         fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
         fsBuilder->codeAppend("float afwidth;");
         if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
@@ -421,14 +415,11 @@
                 args.fGP.cast<GrDistanceFieldLCDTextureEffect>();
         SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
 
-        SkString fsCoordName;
-        const char* vsCoordName;
-        const char* fsCoordNamePtr;
-        args.fPB->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
-        fsCoordName = fsCoordNamePtr;
+        GrGLVertToFrag v(kVec2f_GrSLType);
+        args.fPB->addVarying("TextureCoords", &v);
 
         GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
-        vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
+        vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), dfTexEffect.inTextureCoords().c_str());
 
         const char* textureSizeUniName = NULL;
         // width, height, 1/(3*width)
@@ -442,7 +433,7 @@
                 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
 
         // create LCD offset adjusted by inverse of transform
-        fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
+        fsBuilder->codeAppendf("\tvec2 uv = %s;\n", v.fsIn());
         fsBuilder->codeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName);
         bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
         if (isUniformScale) {
diff --git a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
index 76558d8..ff3989b 100644
--- a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
@@ -346,12 +346,10 @@
     }
 }
 
-void GrGLFragmentShaderBuilder::addVarying(GrSLType type,
-               const char* name,
-               const char** fsInName,
-               GrGLShaderVar::Precision fsPrecision) {
-    fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name, fsPrecision);
-    if (fsInName) {
-        *fsInName = name;
+void GrGLFragmentShaderBuilder::addVarying(GrGLVarying* v, GrGLShaderVar::Precision fsPrec) {
+    v->fFsIn = v->fVsOut;
+    if (v->fGsOut) {
+        v->fFsIn = v->fGsOut;
     }
+    fInputs.push_back().set(v->fType, GrGLShaderVar::kVaryingIn_TypeModifier, v->fFsIn, fsPrec);
 }
diff --git a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h
index 1637d25..67dfbe3 100644
--- a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h
+++ b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h
@@ -10,6 +10,8 @@
 
 #include "GrGLShaderBuilder.h"
 
+class GrGLVarying;
+
 /*
  * This base class encapsulates the functionality which the GP uses to build fragment shaders
  */
@@ -91,6 +93,7 @@
     virtual const char* fragmentPosition() SK_OVERRIDE;
     virtual const char* dstColor() SK_OVERRIDE;
 
+private:
     // Private public interface, used by GrGLProgramBuilder to build a fragment shader
     void emitCodeToReadDstTexture();
     void enableCustomOutput();
@@ -102,14 +105,6 @@
     bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
     void bindFragmentShaderLocations(GrGLuint programID);
 
-    /*
-     * An internal call for GrGLProgramBuilder to use to add varyings to the vertex shader
-     */
-    void addVarying(GrSLType type,
-                   const char* name,
-                   const char** fsInName,
-                   GrGLShaderVar::Precision fsPrecision = GrGLShaderVar::kDefault_Precision);
-
     // As GLProcessors emit code, there are some conditions we need to verify.  We use the below
     // state to track this.  The reset call is called per processor emitted.
     bool hasReadDstColor() const { return fHasReadDstColor; }
@@ -119,7 +114,12 @@
         fHasReadFragmentPosition = false;
     }
 
-private:
+    /*
+     * An internal call for GrGLProgramBuilder to use to add varyings to the vertex shader
+     */
+    void addVarying(GrGLVarying* v,
+                    GrGLShaderVar::Precision fsPrec = GrGLShaderVar::kDefault_Precision);
+
     /**
      * Features that should only be enabled by GrGLFragmentShaderBuilder itself.
      */
diff --git a/src/gpu/gl/builders/GrGLGeometryShaderBuilder.cpp b/src/gpu/gl/builders/GrGLGeometryShaderBuilder.cpp
index 8a3b1f4..af95f56 100644
--- a/src/gpu/gl/builders/GrGLGeometryShaderBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLGeometryShaderBuilder.cpp
@@ -15,26 +15,27 @@
 
 }
 
-void GrGLGeometryBuilder::addVarying(GrSLType type,
-               const char* name,
-               const char** gsOutName) {
+void GrGLGeometryBuilder::addVarying(const char* name, GrGLVarying* v) {
     // if we have a GS take each varying in as an array
     // and output as non-array.
-    fInputs.push_back();
-    fInputs.back().setType(type);
-    fInputs.back().setTypeModifier(GrGLShaderVar::kVaryingIn_TypeModifier);
-    fInputs.back().setUnsizedArray();
-    *fInputs.back().accessName() = name;
-    fOutputs.push_back();
-    fOutputs.back().setType(type);
-    fOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
-    fProgramBuilder->nameVariable(fOutputs.back().accessName(), 'g', name);
-    if (gsOutName) {
-        *gsOutName = fOutputs.back().getName().c_str();
+    if (v->vsVarying()) {
+        fInputs.push_back();
+        fInputs.back().setType(v->fType);
+        fInputs.back().setTypeModifier(GrGLShaderVar::kVaryingIn_TypeModifier);
+        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(GrGLShaderVar::kVaryingOut_TypeModifier);
+        fProgramBuilder->nameVariable(fOutputs.back().accessName(), 'g', name);
+        v->fGsOut = fOutputs.back().getName().c_str();
     }
 }
 
-
 bool GrGLGeometryBuilder::compileAndAttachShaders(GrGLuint programId,
         SkTDArray<GrGLuint>* shaderIds) const {
     const GrGLContext& glCtx = fProgramBuilder->gpu()->glContext();
diff --git a/src/gpu/gl/builders/GrGLGeometryShaderBuilder.h b/src/gpu/gl/builders/GrGLGeometryShaderBuilder.h
index aa27f23..88fa298 100644
--- a/src/gpu/gl/builders/GrGLGeometryShaderBuilder.h
+++ b/src/gpu/gl/builders/GrGLGeometryShaderBuilder.h
@@ -10,18 +10,22 @@
 
 #include "GrGLShaderBuilder.h"
 
+class GrGLVarying;
+
 class GrGLGeometryBuilder : public GrGLShaderBuilder {
 public:
     GrGLGeometryBuilder(GrGLProgramBuilder* program);
+
+private:
     /*
      * an internal call for GrGLFullProgramBuilder to add varyings
      */
-    void addVarying(GrSLType type,
-                   const char* name,
-                   const char** gsOutName);
+    void addVarying(const char* name, GrGLVarying*);
 
     bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
 
+    friend class GrGLProgramBuilder;
+
     typedef GrGLShaderBuilder INHERITED;
 };
 
diff --git a/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp b/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp
index a20b0d6..86b1d7f 100644
--- a/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp
@@ -55,7 +55,6 @@
                                             const char* name,
                                             const char** vsOutName,
                                             const char** fsInName) {
-    addVarying(type, name, vsOutName, fsInName);
     SeparableVaryingInfo& varying = fSeparableVaryingInfos.push_back();
     varying.fVariable = fFS.fInputs.back();
     return GrGLInstalledFragProc::ShaderVarHandle(fSeparableVaryingInfos.count() - 1);
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index a628feb..4a95f33 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -126,13 +126,19 @@
     , fUniforms(kVarsPerBlock) {
 }
 
-void GrGLProgramBuilder::addVarying(GrSLType type,
-                                    const char* name,
-                                    const char** vsOutName,
-                                    const char** fsInName,
+void GrGLProgramBuilder::addVarying(const char* name,
+                                    GrGLVarying* varying,
                                     GrGLShaderVar::Precision fsPrecision) {
-    SkString* fsInputName = fVS.addVarying(type, name, vsOutName);
-    fFS.addVarying(type, fsInputName->c_str(), fsInName, fsPrecision);
+    SkASSERT(varying);
+    if (varying->vsVarying()) {
+        fVS.addVarying(name, varying);
+    }
+    if (fOptState.hasGeometryProcessor() && fOptState.getGeometryProcessor()->willUseGeoShader()) {
+        fGS.addVarying(name, varying);
+    }
+    if (varying->fsVarying()) {
+        fFS.addVarying(varying);
+    }
 }
 
 void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name) {
@@ -362,9 +368,8 @@
             suffixedVaryingName.appendf("_%i", t);
             varyingName = suffixedVaryingName.c_str();
         }
-        const char* vsVaryingName;
-        const char* fsVaryingName;
-        this->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
+        GrGLVertToFrag v(varyingType);
+        this->addVarying(varyingName, &v);
 
         const GrGLShaderVar& coords =
                 kPosition_GrCoordSet == effect->coordTransform(t).sourceCoords() ?
@@ -375,13 +380,13 @@
         SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
         if (kVec2f_GrSLType == varyingType) {
             fVS.codeAppendf("%s = (%s * vec3(%s, 1)).xy;",
-                            vsVaryingName, uniName, coords.c_str());
+                            v.vsOut(), uniName, coords.c_str());
         } else {
             fVS.codeAppendf("%s = %s * vec3(%s, 1);",
-                            vsVaryingName, uniName, coords.c_str());
+                            v.vsOut(), uniName, coords.c_str());
         }
         SkNEW_APPEND_TO_TARRAY(outCoords, GrGLProcessor::TransformedCoords,
-                               (SkString(fsVaryingName), varyingType));
+                               (SkString(v.fsIn()), varyingType));
     }
 }
 
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index 2afdd09..9d8e7e0 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -69,13 +69,63 @@
      */
 };
 
+// TODO move this into GrGLGPBuilder and move them both out of this file
+class GrGLVarying {
+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; }
+
+protected:
+    enum Varying {
+        kVertToFrag_Varying,
+        kVertToGeo_Varying,
+        kGeoToFrag_Varying,
+    };
+
+    GrGLVarying(GrSLType type, Varying varying)
+        : fVarying(varying), fType(type), fVsOut(NULL), fGsIn(NULL), fGsOut(NULL),
+          fFsIn(NULL) {}
+
+    Varying fVarying;
+
+private:
+    GrSLType fType;
+    const char* fVsOut;
+    const char* fGsIn;
+    const char* fGsOut;
+    const char* fFsIn;
+
+    friend class GrGLVertexBuilder;
+    friend class GrGLGeometryBuilder;
+    friend class GrGLFragmentShaderBuilder;
+};
+
+struct GrGLVertToFrag : public GrGLVarying {
+    GrGLVertToFrag(GrSLType type)
+        : GrGLVarying(type, kVertToFrag_Varying) {}
+};
+
+struct GrGLVertToGeo : public GrGLVarying {
+    GrGLVertToGeo(GrSLType type)
+        : GrGLVarying(type, kVertToGeo_Varying) {}
+};
+
+struct GrGLGeoToFrag : public GrGLVarying {
+    GrGLGeoToFrag(GrSLType type)
+        : GrGLVarying(type, kGeoToFrag_Varying) {}
+};
+
 /* a specialization of the above for GPs.  Lets the user add uniforms, varyings, and VS / FS code */
 class GrGLGPBuilder : public virtual GrGLUniformBuilder {
 public:
-    virtual void addVarying(GrSLType type,
-                            const char* name,
-                            const char** vsOutName = NULL,
-                            const char** fsInName = NULL,
+    virtual void addVarying(const char* name,
+                            GrGLVarying*,
                             GrGLShaderVar::Precision fsPrecision=GrGLShaderVar::kDefault_Precision) = 0;
 
     // TODO rename getFragmentBuilder
@@ -152,10 +202,8 @@
     virtual GrGLVertexBuilder* getVertexShaderBuilder() SK_OVERRIDE { return &fVS; }
 
     virtual void addVarying(
-            GrSLType type,
             const char* name,
-            const char** vsOutName = NULL,
-            const char** fsInName = NULL,
+            GrGLVarying*,
             GrGLShaderVar::Precision fsPrecision=GrGLShaderVar::kDefault_Precision) SK_OVERRIDE;
 
     // Handles for program uniforms (other than per-effect uniforms)
diff --git a/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp b/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
index 76026b7..1fa9467 100644
--- a/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
@@ -23,17 +23,12 @@
     , fEffectAttribOffset(0) {
 }
 
-SkString* GrGLVertexBuilder::addVarying(GrSLType type, const char* name,
-                                              const char** vsOutName) {
+void GrGLVertexBuilder::addVarying(const char* name, GrGLVarying* v) {
     fOutputs.push_back();
-    fOutputs.back().setType(type);
+    fOutputs.back().setType(v->fType);
     fOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
     fProgramBuilder->nameVariable(fOutputs.back().accessName(), 'v', name);
-
-    if (vsOutName) {
-        *vsOutName = fOutputs.back().getName().c_str();
-    }
-    return fOutputs.back().accessName();
+    v->fVsOut = fOutputs.back().getName().c_str();
 }
 
 void GrGLVertexBuilder::setupLocalCoords() {
@@ -63,15 +58,15 @@
 }
 
 void GrGLVertexBuilder::setupBuiltinVertexAttribute(const char* inName, GrGLSLExpr4* out) {
+    GrGLVertToFrag v(kVec4f_GrSLType);
+    fProgramBuilder->addVarying(inName, &v);
     SkString name(inName);
-    const char *vsName, *fsName;
-    fProgramBuilder->addVarying(kVec4f_GrSLType, name.c_str(), &vsName, &fsName);
     name.prepend("in");
     this->addAttribute(GrShaderVar(name.c_str(),
                                    kVec4f_GrSLType,
                                    GrShaderVar::kAttribute_TypeModifier));
-    this->codeAppendf("%s = %s;", vsName, name.c_str());
-    *out = fsName;
+    this->codeAppendf("%s = %s;", v.vsOut(), name.c_str());
+    *out = v.fsIn();
     fEffectAttribOffset++;
 }
 
diff --git a/src/gpu/gl/builders/GrGLVertexShaderBuilder.h b/src/gpu/gl/builders/GrGLVertexShaderBuilder.h
index 6e1495a..31b4ad4 100644
--- a/src/gpu/gl/builders/GrGLVertexShaderBuilder.h
+++ b/src/gpu/gl/builders/GrGLVertexShaderBuilder.h
@@ -10,10 +10,8 @@
 
 #include "GrGLShaderBuilder.h"
 
-class GrGLProgramBuilder;
+class GrGLVarying;
 
-// TODO we only actually ever need to return a GrGLShaderBuilder for this guy, none of the below
-// functions need to be part of VertexShaderBuilder's public interface
 class GrGLVertexBuilder : public GrGLShaderBuilder {
 public:
     GrGLVertexBuilder(GrGLProgramBuilder* program);
@@ -33,10 +31,11 @@
       */
     const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
 
+private:
     /*
      * Internal call for GrGLProgramBuilder.addVarying
      */
-    SkString* addVarying(GrSLType type, const char* name, const char** vsOutName);
+    void addVarying(const char* name, GrGLVarying*);
 
     /*
      * private helpers for compilation by GrGLProgramBuilder
@@ -49,7 +48,6 @@
     void bindVertexAttributes(GrGLuint programID);
     bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
 
-private:
     // an internal call which checks for uniquness of a var before adding it to the list of inputs
     bool addAttribute(const GrShaderVar& var);
     struct AttributePair {
@@ -64,6 +62,8 @@
     GrGLShaderVar*                      fLocalCoordsVar;
     int                                 fEffectAttribOffset;
 
+    friend class GrGLProgramBuilder;
+
     typedef GrGLShaderBuilder INHERITED;
 };