Make GrGLEffects use an interface to append their code.

A small step towards encapsulating GrGLShaderBuilder.
Review URL: https://codereview.chromium.org/12547012

git-svn-id: http://skia.googlecode.com/svn/trunk@8018 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index 1dd51c8..f2c5d09 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -31,31 +31,34 @@
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
         const char* coords;
         GrSLType coordsType = fEffectMatrix.emitCode(builder, key, vertexCoords, &coords);
-        builder->fFSCode.appendf("\t\t%s = ", outputColor);
-        builder->appendTextureLookup(&builder->fFSCode, samplers[0], coords, coordsType);
-        builder->fFSCode.append(";\n");
+        builder->fsCodeAppendf("\t\t%s = ", outputColor);
+        builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType,
+                                     samplers[0],
+                                     coords,
+                                     coordsType);
+        builder->fsCodeAppend(";\n");
         if (GrConfigConversionEffect::kNone_PMConversion == fPMConversion) {
             GrAssert(fSwapRedAndBlue);
-            builder->fFSCode.appendf("\t%s = %s.bgra;\n", outputColor, outputColor);
+            builder->fsCodeAppendf("\t%s = %s.bgra;\n", outputColor, outputColor);
         } else {
             const char* swiz = fSwapRedAndBlue ? "bgr" : "rgb";
             switch (fPMConversion) {
                 case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
-                    builder->fFSCode.appendf(
+                    builder->fsCodeAppendf(
                         "\t\t%s = vec4(ceil(%s.%s * %s.a * 255.0) / 255.0, %s.a);\n",
                         outputColor, outputColor, swiz, outputColor, outputColor);
                     break;
                 case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion:
-                    builder->fFSCode.appendf(
+                    builder->fsCodeAppendf(
                         "\t\t%s = vec4(floor(%s.%s * %s.a * 255.0) / 255.0, %s.a);\n",
                         outputColor, outputColor, swiz, outputColor, outputColor);
                     break;
                 case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
-                    builder->fFSCode.appendf("\t\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);\n",
+                    builder->fsCodeAppendf("\t\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);\n",
                         outputColor, outputColor, outputColor, swiz, outputColor, outputColor);
                     break;
                 case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
-                    builder->fFSCode.appendf("\t\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);\n",
+                    builder->fsCodeAppendf("\t\t%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);\n",
                         outputColor, outputColor, outputColor, swiz, outputColor, outputColor);
                     break;
                 default:
@@ -63,7 +66,9 @@
                     break;
             }
         }
-        GrGLSLMulVarBy4f(&builder->fFSCode, 2, outputColor, inputColor);
+        SkString modulate;
+        GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
+        builder->fsCodeAppend(modulate.c_str());
     }
 
     void setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index 12c32f0..1c0e8f5 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -65,15 +65,14 @@
                                              kVec2f_GrSLType, "ImageIncrement");
     fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_ShaderType,
                                           kFloat_GrSLType, "Kernel", this->width());
-    SkString* code = &builder->fFSCode;
 
-    code->appendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
+    builder->fsCodeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
 
     int width = this ->width();
     const GrGLShaderVar& kernel = builder->getUniformVariable(fKernelUni);
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
 
-    code->appendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
+    builder->fsCodeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords, fRadius, imgInc);
 
     // Manually unroll loop because some drivers don't; yields 20-30% speedup.
     for (int i = 0; i < width; i++) {
@@ -81,12 +80,14 @@
         SkString kernelIndex;
         index.appendS32(i);
         kernel.appendArrayAccess(index.c_str(), &kernelIndex);
-        code->appendf("\t\t%s += ", outputColor);
-        builder->appendTextureLookup(&builder->fFSCode, samplers[0], "coord");
-        code->appendf(" * %s;\n", kernelIndex.c_str());
-        code->appendf("\t\tcoord += %s;\n", imgInc);
+        builder->fsCodeAppendf("\t\t%s += ", outputColor);
+        builder->appendTextureLookup(GrGLShaderBuilder::kFragment_ShaderType, samplers[0], "coord");
+        builder->fsCodeAppendf(" * %s;\n", kernelIndex.c_str());
+        builder->fsCodeAppendf("\t\tcoord += %s;\n", imgInc);
     }
-    GrGLSLMulVarBy4f(&builder->fFSCode, 2, outputColor, inputColor);
+    SkString modulate;
+    GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
+    builder->fsCodeAppend(modulate.c_str());
 }
 
 void GrGLConvolutionEffect::setData(const GrGLUniformManager& uman, const GrEffectStage& stage) {
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index 0fe083b..58ac3c0 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -27,13 +27,13 @@
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
         const char* coordName;
         GrSLType coordType = fEffectMatrix.emitCode(builder, key, vertexCoords, &coordName);
-        builder->fFSCode.appendf("\t%s = ", outputColor);
-        builder->appendTextureLookupAndModulate(&builder->fFSCode,
+        builder->fsCodeAppendf("\t%s = ", outputColor);
+        builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
                                                 inputColor,
                                                 samplers[0],
                                                 coordName,
                                                 coordType);
-        builder->fFSCode.append(";\n");
+        builder->fsCodeAppend(";\n");
     }
 
     static inline EffectKey GenKey(const GrEffectStage& stage, const GrGLCaps&) {
diff --git a/src/gpu/effects/GrTextureDomainEffect.cpp b/src/gpu/effects/GrTextureDomainEffect.cpp
index 3c70951..851bdcc 100644
--- a/src/gpu/effects/GrTextureDomainEffect.cpp
+++ b/src/gpu/effects/GrTextureDomainEffect.cpp
@@ -59,15 +59,15 @@
                                     kVec4f_GrSLType, "TexDom", &domain);
     if (GrTextureDomainEffect::kClamp_WrapMode == effect.wrapMode()) {
 
-        builder->fFSCode.appendf("\tvec2 clampCoord = clamp(%s, %s.xy, %s.zw);\n",
-                               coords, domain, domain);
+        builder->fsCodeAppendf("\tvec2 clampCoord = clamp(%s, %s.xy, %s.zw);\n",
+                                coords, domain, domain);
 
-        builder->fFSCode.appendf("\t%s = ", outputColor);
-        builder->appendTextureLookupAndModulate(&builder->fFSCode,
+        builder->fsCodeAppendf("\t%s = ", outputColor);
+        builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
                                                 inputColor,
                                                 samplers[0],
                                                 "clampCoord");
-        builder->fFSCode.append(";\n");
+        builder->fsCodeAppend(";\n");
     } else {
         GrAssert(GrTextureDomainEffect::kDecal_WrapMode == effect.wrapMode());
 
@@ -78,24 +78,30 @@
             // may return undefined results". This appears to be an issue with
             // the 'any' call since even the simple "result=black; if (any())
             // result=white;" code fails to compile.
-            builder->fFSCode.appendf("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n");
-            builder->fFSCode.appendf("\tvec4 inside = ");
-            builder->appendTextureLookupAndModulate(&builder->fFSCode, inputColor, samplers[0], coords);
-            builder->fFSCode.appendf(";\n");
+            builder->fsCodeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n");
+            builder->fsCodeAppend("\tvec4 inside = ");
+            builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
+                                                    inputColor,
+                                                    samplers[0],
+                                                    coords);
+            builder->fsCodeAppend(";\n");
 
-            builder->fFSCode.appendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n",
-                                     coords, domain, domain, domain);
-            builder->fFSCode.appendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n",
-                                     coords, domain, domain, domain);
-            builder->fFSCode.appendf("\tfloat blend = step(1.0, max(x, y));\n");
-            builder->fFSCode.appendf("\t%s = mix(inside, outside, blend);\n", outputColor);
+            builder->fsCodeAppendf("\tfloat x = abs(2.0*(%s.x - %s.x)/(%s.z - %s.x) - 1.0);\n",
+                                   coords, domain, domain, domain);
+            builder->fsCodeAppendf("\tfloat y = abs(2.0*(%s.y - %s.y)/(%s.w - %s.y) - 1.0);\n",
+                                   coords, domain, domain, domain);
+            builder->fsCodeAppend("\tfloat blend = step(1.0, max(x, y));\n");
+            builder->fsCodeAppendf("\t%s = mix(inside, outside, blend);\n", outputColor);
         } else {
-            builder->fFSCode.append("\tbvec4 outside;\n");
-            builder->fFSCode.appendf("\toutside.xy = lessThan(%s, %s.xy);\n", coords, domain);
-            builder->fFSCode.appendf("\toutside.zw = greaterThan(%s, %s.zw);\n", coords, domain);
-            builder->fFSCode.appendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outputColor);
-            builder->appendTextureLookupAndModulate(&builder->fFSCode, inputColor, samplers[0], coords);
-            builder->fFSCode.append(";\n");
+            builder->fsCodeAppend("\tbvec4 outside;\n");
+            builder->fsCodeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", coords, domain);
+            builder->fsCodeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", coords, domain);
+            builder->fsCodeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ", outputColor);
+            builder->appendTextureLookupAndModulate(GrGLShaderBuilder::kFragment_ShaderType,
+                                                    inputColor,
+                                                    samplers[0],
+                                                    coords);
+            builder->fsCodeAppend(";\n");
         }
     }
 }
diff --git a/src/gpu/gl/GrGLEffectMatrix.cpp b/src/gpu/gl/GrGLEffectMatrix.cpp
index 5fdde2c..c37098e 100644
--- a/src/gpu/gl/GrGLEffectMatrix.cpp
+++ b/src/gpu/gl/GrGLEffectMatrix.cpp
@@ -93,20 +93,20 @@
     switch (fUniType) {
         case kVoid_GrSLType:
             GrAssert(kVec2f_GrSLType == varyingType);
-            builder->fVSCode.appendf("\t%s = %s;\n", vsVaryingName, vertexCoords);
+            builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, vertexCoords);
             break;
         case kVec2f_GrSLType:
             GrAssert(kVec2f_GrSLType == varyingType);
-            builder->fVSCode.appendf("\t%s = %s + %s;\n", vsVaryingName, uniName, vertexCoords);
+            builder->vsCodeAppendf("\t%s = %s + %s;\n", vsVaryingName, uniName, vertexCoords);
             break;
         case kMat33f_GrSLType: {
             GrAssert(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
             if (kVec2f_GrSLType == varyingType) {
-                builder->fVSCode.appendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
-                                         vsVaryingName, uniName, vertexCoords);
+                builder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
+                                       vsVaryingName, uniName, vertexCoords);
             } else {
-                builder->fVSCode.appendf("\t%s = %s * vec3(%s, 1);\n",
-                                         vsVaryingName, uniName, vertexCoords);
+                builder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n",
+                                       vsVaryingName, uniName, vertexCoords);
             }
             break;
         }
@@ -150,8 +150,8 @@
             suffixedCoordName.append(suffix);
             coordName = suffixedCoordName.c_str();
         }
-        builder->fFSCode.appendf("\tvec2 %s = %s.xy / %s.z;",
-                                    coordName, fsVaryingName, fsVaryingName);
+        builder->fsCodeAppendf("\tvec2 %s = %s.xy / %s.z;",
+                               coordName, fsVaryingName, fsVaryingName);
         if (NULL != fsCoordName) {
             *fsCoordName = coordName;
         }
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 5c88441..2b6ccbd 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -398,7 +398,8 @@
  * Adds a line to the fragment shader code which modifies the color by
  * the specified color filter.
  */
-void add_color_filter(SkString* fsCode, const char * outputVar,
+void add_color_filter(GrGLShaderBuilder* builder,
+                      const char * outputVar,
                       SkXfermode::Coeff uniformCoeff,
                       SkXfermode::Coeff colorCoeff,
                       const char* filterColor,
@@ -407,9 +408,9 @@
     blend_term_string(&colorStr, colorCoeff, filterColor, inColor, inColor);
     blend_term_string(&constStr, uniformCoeff, filterColor, inColor, filterColor);
 
-    fsCode->appendf("\t%s = ", outputVar);
-    GrGLSLAdd4f(fsCode, colorStr.c_str(), constStr.c_str());
-    fsCode->append(";\n");
+    SkString sum;
+    GrGLSLAdd4f(&sum, colorStr.c_str(), constStr.c_str());
+    builder->fsCodeAppendf("\t%s = %s;\n", outputVar, sum.c_str());
 }
 }
 
@@ -421,64 +422,64 @@
         builder->fVSAttrs.push_back().set(kVec4f_GrSLType,
                                           GrGLShaderVar::kAttribute_TypeModifier,
                                           EDGE_ATTR_NAME);
-        builder->fVSCode.appendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
+        builder->vsCodeAppendf("\t%s = " EDGE_ATTR_NAME ";\n", vsName);
         switch (fDesc.fVertexEdgeType) {
         case GrDrawState::kHairLine_EdgeType:
-            builder->fFSCode.appendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n", builder->fragmentPosition(), fsName);
-            builder->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            builder->fsCodeAppendf("\tfloat edgeAlpha = abs(dot(vec3(%s.xy,1), %s.xyz));\n", builder->fragmentPosition(), fsName);
+            builder->fsCodeAppendf("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
             break;
         case GrDrawState::kQuad_EdgeType:
-            builder->fFSCode.append("\tfloat edgeAlpha;\n");
+            builder->fsCodeAppendf("\tfloat edgeAlpha;\n");
             // keep the derivative instructions outside the conditional
-            builder->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            builder->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            builder->fFSCode.appendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
+            builder->fsCodeAppendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
             // today we know z and w are in device space. We could use derivatives
-            builder->fFSCode.appendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
-            builder->fFSCode.append ("\t} else {\n");
-            builder->fFSCode.appendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
-                                     "\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
-                                     fsName, fsName);
-            builder->fFSCode.appendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
-            builder->fFSCode.append("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n"
-                                    "\t}\n");
+            builder->fsCodeAppendf("\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName, fsName);
+            builder->fsCodeAppendf ("\t} else {\n");
+            builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+                                   "\t\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
+                                    fsName, fsName);
+            builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
+            builder->fsCodeAppendf("\t\tedgeAlpha = clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n"
+                                   "\t}\n");
             if (kES2_GrGLBinding == fContext.info().binding()) {
-                builder->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
+                builder->fHeader.append("#extension GL_OES_standard_derivatives: enable\n");
             }
             break;
         case GrDrawState::kHairQuad_EdgeType:
-            builder->fFSCode.appendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            builder->fFSCode.appendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            builder->fFSCode.appendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
-                                     "\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
-                                     fsName, fsName);
-            builder->fFSCode.appendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
-            builder->fFSCode.append("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
-            builder->fFSCode.append("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            builder->fsCodeAppendf("\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            builder->fsCodeAppendf("\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+                                   "\t               2.0*%s.x*duvdy.x - duvdy.y);\n",
+                                   fsName, fsName);
+            builder->fsCodeAppendf("\tfloat edgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName, fsName);
+            builder->fsCodeAppend("\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
+            builder->fsCodeAppend("\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
             if (kES2_GrGLBinding == fContext.info().binding()) {
                 builder->fHeader.printf("#extension GL_OES_standard_derivatives: enable\n");
             }
             break;
         case GrDrawState::kCircle_EdgeType:
-            builder->fFSCode.append("\tfloat edgeAlpha;\n");
-            builder->fFSCode.appendf("\tfloat d = distance(%s.xy, %s.xy);\n", builder->fragmentPosition(), fsName);
-            builder->fFSCode.appendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
-            builder->fFSCode.appendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
-            builder->fFSCode.append("\tedgeAlpha = outerAlpha * innerAlpha;\n");
+            builder->fsCodeAppend("\tfloat edgeAlpha;\n");
+            builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n", builder->fragmentPosition(), fsName);
+            builder->fsCodeAppendf("\tfloat outerAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
+            builder->fsCodeAppendf("\tfloat innerAlpha = %s.w == 0.0 ? 1.0 : smoothstep(%s.w - 0.5, %s.w + 0.5, d);\n", fsName, fsName, fsName);
+            builder->fsCodeAppend("\tedgeAlpha = outerAlpha * innerAlpha;\n");
             break;
         case GrDrawState::kEllipse_EdgeType:
-            builder->fFSCode.append("\tfloat edgeAlpha;\n");
-            builder->fFSCode.appendf("\tvec2 offset = (%s.xy - %s.xy);\n", builder->fragmentPosition(), fsName);
-            builder->fFSCode.appendf("\toffset.y *= %s.w;\n", fsName);
-            builder->fFSCode.append("\tfloat d = length(offset);\n");
-            builder->fFSCode.appendf("\tedgeAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
+            builder->fsCodeAppend("\tfloat edgeAlpha;\n");
+            builder->fsCodeAppendf("\tvec2 offset = (%s.xy - %s.xy);\n", builder->fragmentPosition(), fsName);
+            builder->fsCodeAppendf("\toffset.y *= %s.w;\n", fsName);
+            builder->fsCodeAppend("\tfloat d = length(offset);\n");
+            builder->fsCodeAppendf("\tedgeAlpha = smoothstep(d - 0.5, d + 0.5, %s.z);\n", fsName);
             break;
         default:
             GrCrash("Unknown Edge Type!");
             break;
         }
         if (fDesc.fDiscardIfOutsideEdge) {
-            builder->fFSCode.appendf("\tif (edgeAlpha <= 0.0) {\n\t\tdiscard;\n\t}\n");
+            builder->fsCodeAppend("\tif (edgeAlpha <= 0.0) {\n\t\tdiscard;\n\t}\n");
         }
         *coverageVar = "edgeAlpha";
         return true;
@@ -496,7 +497,7 @@
                 COL_ATTR_NAME);
             const char *vsName, *fsName;
             builder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
-            builder->fVSCode.appendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
+            builder->vsCodeAppendf("\t%s = " COL_ATTR_NAME ";\n", vsName);
             *inColor = fsName;
             } break;
         case GrGLProgram::Desc::kUniform_ColorInput: {
@@ -522,8 +523,8 @@
     fUniformHandles.fCoverageUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                                        kVec4f_GrSLType, "Coverage", &covUniName);
     if (inOutCoverage->size()) {
-        builder->fFSCode.appendf("\tvec4 uniCoverage = %s * %s;\n",
-                                  covUniName, inOutCoverage->c_str());
+        builder->fsCodeAppendf("\tvec4 uniCoverage = %s * %s;\n",
+                               covUniName, inOutCoverage->c_str());
         *inOutCoverage = "uniCoverage";
     } else {
         *inOutCoverage = covUniName;
@@ -531,17 +532,16 @@
 }
 
 namespace {
-void gen_attribute_coverage(GrGLShaderBuilder* segments,
+void gen_attribute_coverage(GrGLShaderBuilder* builder,
                             SkString* inOutCoverage) {
-    segments->fVSAttrs.push_back().set(kVec4f_GrSLType,
-                                       GrGLShaderVar::kAttribute_TypeModifier,
-                                       COV_ATTR_NAME);
+    builder->fVSAttrs.push_back().set(kVec4f_GrSLType,
+                                      GrGLShaderVar::kAttribute_TypeModifier,
+                                      COV_ATTR_NAME);
     const char *vsName, *fsName;
-    segments->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
-    segments->fVSCode.appendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
+    builder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
+    builder->vsCodeAppendf("\t%s = " COV_ATTR_NAME ";\n", vsName);
     if (inOutCoverage->size()) {
-        segments->fFSCode.appendf("\tvec4 attrCoverage = %s * %s;\n",
-                                  fsName, inOutCoverage->c_str());
+        builder->fsCodeAppendf("\tvec4 attrCoverage = %s * %s;\n", fsName, inOutCoverage->c_str());
         *inOutCoverage = "attrCoverage";
     } else {
         *inOutCoverage = fsName;
@@ -549,27 +549,28 @@
 }
 }
 
-void GrGLProgram::genGeometryShader(GrGLShaderBuilder* segments) const {
+void GrGLProgram::genGeometryShader(GrGLShaderBuilder* builder) const {
 #if GR_GL_EXPERIMENTAL_GS
+    // TODO: The builder should add all this glue code.
     if (fDesc.fExperimentalGS) {
         GrAssert(fContext.info().glslGeneration() >= k150_GrGLSLGeneration);
-        segments->fGSHeader.append("layout(triangles) in;\n"
+        builder->fGSHeader.append("layout(triangles) in;\n"
                                    "layout(triangle_strip, max_vertices = 6) out;\n");
-        segments->fGSCode.append("\tfor (int i = 0; i < 3; ++i) {\n"
-                                 "\t\tgl_Position = gl_in[i].gl_Position;\n");
+        builder->gsCodeAppend("\tfor (int i = 0; i < 3; ++i) {\n"
+                              "\t\tgl_Position = gl_in[i].gl_Position;\n");
         if (fDesc.fEmitsPointSize) {
-            segments->fGSCode.append("\t\tgl_PointSize = 1.0;\n");
+            builder->gsCodeAppend("\t\tgl_PointSize = 1.0;\n");
         }
-        GrAssert(segments->fGSInputs.count() == segments->fGSOutputs.count());
-        int count = segments->fGSInputs.count();
+        GrAssert(builder->fGSInputs.count() == builder->fGSOutputs.count());
+        int count = builder->fGSInputs.count();
         for (int i = 0; i < count; ++i) {
-            segments->fGSCode.appendf("\t\t%s = %s[i];\n",
-                                      segments->fGSOutputs[i].getName().c_str(),
-                                      segments->fGSInputs[i].getName().c_str());
+            builder->gsCodeAppendf("\t\t%s = %s[i];\n",
+                                   builder->fGSOutputs[i].getName().c_str(),
+                                   builder->fGSInputs[i].getName().c_str());
         }
-        segments->fGSCode.append("\t\tEmitVertex();\n"
-                                 "\t}\n"
-                                 "\tEndPrimitive();\n");
+        builder->gsCodeAppend("\t\tEmitVertex();\n"
+                              "\t}\n"
+                              "\tEndPrimitive();\n");
     }
 #endif
 }
@@ -758,9 +759,9 @@
                                                         kMat33f_GrSLType, "ViewM", &viewMName);
 
 
-    builder.fVSCode.appendf("\tvec3 pos3 = %s * vec3(%s, 1);\n"
-                            "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n",
-                            viewMName, builder.positionAttribute().getName().c_str());
+    builder.vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n"
+                          "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n",
+                          viewMName, builder.positionAttribute().getName().c_str());
 
     // incoming color to current stage being processed.
     SkString inColor;
@@ -771,7 +772,7 @@
 
     // we output point size in the GS if present
     if (fDesc.fEmitsPointSize && !builder.fUsesGS){
-        builder.fVSCode.append("\tgl_PointSize = 1.0;\n");
+        builder.vsCodeAppend("\tgl_PointSize = 1.0;\n");
     }
 
     // add texture coordinates that are used to the list of vertex attr decls
@@ -793,7 +794,7 @@
                 // create var to hold stage result
                 outColor = "color";
                 outColor.appendS32(s);
-                builder.fFSCode.appendf("\tvec4 %s;\n", outColor.c_str());
+                builder.fsCodeAppendf("\tvec4 %s;\n", outColor.c_str());
 
                 const char* inCoords;
                 // figure out what our input coords are
@@ -840,15 +841,13 @@
     bool wroteFragColorZero = false;
     if (SkXfermode::kZero_Coeff == uniformCoeff &&
         SkXfermode::kZero_Coeff == colorCoeff) {
-        builder.fFSCode.appendf("\t%s = %s;\n",
-                                colorOutput.getName().c_str(),
-                                GrGLSLZerosVecf(4));
+        builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), GrGLSLZerosVecf(4));
         wroteFragColorZero = true;
     } else if (SkXfermode::kDst_Mode != fDesc.fColorFilterXfermode) {
-        builder.fFSCode.append("\tvec4 filteredColor;\n");
+        builder.fsCodeAppend("\tvec4 filteredColor;\n");
         const char* color = adjustInColor(inColor);
-        add_color_filter(&builder.fFSCode, "filteredColor", uniformCoeff,
-                       colorCoeff, colorFilterColorUniName, color);
+        add_color_filter(&builder, "filteredColor", uniformCoeff,
+                         colorCoeff, colorFilterColorUniName, color);
         inColor = "filteredColor";
     }
 
@@ -887,7 +886,7 @@
                     // create var to hold stage output
                     outCoverage = "coverage";
                     outCoverage.appendS32(s);
-                    builder.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
+                    builder.fsCodeAppendf("\tvec4 %s;\n", outCoverage.c_str());
 
                     const char* inCoords;
                     // figure out what our input coords are
@@ -902,8 +901,8 @@
                     // stages don't know how to deal with a scalar input. (Maybe they should. We
                     // could pass a GrGLShaderVar)
                     if (inCoverageIsScalar) {
-                        builder.fFSCode.appendf("\tvec4 %s4 = vec4(%s);\n",
-                                                inCoverage.c_str(), inCoverage.c_str());
+                        builder.fsCodeAppendf("\tvec4 %s4 = vec4(%s);\n",
+                                              inCoverage.c_str(), inCoverage.c_str());
                         inCoverage.append("4");
                     }
                     builder.setCurrentStage(s);
@@ -939,13 +938,11 @@
                 }
             }
             if (outputIsZero) {
-                builder.fFSCode.appendf("\t%s = %s;\n",
-                                        dual_source_output_name(),
-                                        GrGLSLZerosVecf(4));
+                builder.fsCodeAppendf("\t%s = %s;\n", dual_source_output_name(), GrGLSLZerosVecf(4));
             } else {
-                builder.fFSCode.appendf("\t%s =", dual_source_output_name());
-                GrGLSLModulate4f(&builder.fFSCode, coeff.c_str(), inCoverage.c_str());
-                builder.fFSCode.append(";\n");
+                SkString modulate;
+                GrGLSLModulate4f(&modulate, coeff.c_str(), inCoverage.c_str());
+                builder.fsCodeAppendf("\t%s = %s;\n", dual_source_output_name(), modulate.c_str());
             }
             dualSourceOutputWritten = true;
         }
@@ -956,13 +953,11 @@
 
     if (!wroteFragColorZero) {
         if (coverageIsZero) {
-            builder.fFSCode.appendf("\t%s = %s;\n",
-                                    colorOutput.getName().c_str(),
-                                    GrGLSLZerosVecf(4));
+            builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), GrGLSLZerosVecf(4));
         } else {
-            builder.fFSCode.appendf("\t%s = ", colorOutput.getName().c_str());
-            GrGLSLModulate4f(&builder.fFSCode, inColor.c_str(), inCoverage.c_str());
-            builder.fFSCode.append(";\n");
+            SkString modulate;
+            GrGLSLModulate4f(&modulate, inColor.c_str(), inCoverage.c_str());
+            builder.fsCodeAppendf("\t%s = %s;\n", colorOutput.getName().c_str(), modulate.c_str());
         }
     }
 
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 021f56d..08ef28e 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -101,6 +101,42 @@
     fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
 }
 
+void GrGLShaderBuilder::codeAppendf(ShaderType type, const char format[], va_list args) {
+    SkString* string;
+    switch (type) {
+        case kVertex_ShaderType:
+            string = &fVSCode;
+            break;
+        case kGeometry_ShaderType:
+            string = &fGSCode;
+            break;
+        case kFragment_ShaderType:
+            string = &fFSCode;
+            break;
+        default:
+            GrCrash("Invalid shader type");
+    }
+    string->appendf(format, args);
+}
+
+void GrGLShaderBuilder::codeAppend(ShaderType type, const char* str) {
+    SkString* string;
+    switch (type) {
+        case kVertex_ShaderType:
+            string = &fVSCode;
+            break;
+        case kGeometry_ShaderType:
+            string = &fGSCode;
+            break;
+        case kFragment_ShaderType:
+            string = &fFSCode;
+            break;
+        default:
+            GrCrash("Invalid shader type");
+    }
+    string->append(str);
+}
+
 void GrGLShaderBuilder::appendTextureLookup(SkString* out,
                                             const GrGLShaderBuilder::TextureSampler& sampler,
                                             const char* coordName,
@@ -115,16 +151,24 @@
     append_swizzle(out, *sampler.textureAccess(), fCtxInfo.caps());
 }
 
+void GrGLShaderBuilder::appendTextureLookup(ShaderType type,
+                                            const GrGLShaderBuilder::TextureSampler& sampler,
+                                            const char* coordName,
+                                            GrSLType varyingType) {
+    GrAssert(kFragment_ShaderType == type);
+    this->appendTextureLookup(&fFSCode, sampler, coordName, varyingType);
+}
+
 void GrGLShaderBuilder::appendTextureLookupAndModulate(
-                                            SkString* out,
+                                            ShaderType type,
                                             const char* modulation,
                                             const GrGLShaderBuilder::TextureSampler& sampler,
                                             const char* coordName,
-                                            GrSLType varyingType) const {
-    GrAssert(NULL != out);
+                                            GrSLType varyingType) {
+    GrAssert(kFragment_ShaderType == type);
     SkString lookup;
     this->appendTextureLookup(&lookup, sampler, coordName, varyingType);
-    GrGLSLModulate4f(out, modulation, lookup.c_str());
+    GrGLSLModulate4f(&fFSCode, modulation, lookup.c_str());
 }
 
 GrBackendEffectFactory::EffectKey GrGLShaderBuilder::KeyForTextureAccess(
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index ce1e6d1..08b3ef5 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -14,6 +14,8 @@
 #include "gl/GrGLSL.h"
 #include "gl/GrGLUniformManager.h"
 
+#include <stdarg.h>
+
 class GrGLContextInfo;
 
 /**
@@ -80,6 +82,34 @@
 
     GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&);
 
+    /**
+     * Called by GrGLEffects to add code to one of the shaders.
+     */
+    void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
+        va_list args;
+        va_start(args, format);
+        this->codeAppendf(kVertex_ShaderType, format, args);
+        va_end(args);
+    }
+
+    void gsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
+        va_list args;
+        va_start(args, format);
+        this->codeAppendf(kGeometry_ShaderType, format, args);
+        va_end(args);
+    }
+
+    void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
+        va_list args;
+        va_start(args, format);
+        this->codeAppendf(kFragment_ShaderType, format, args);
+        va_end(args);
+    }
+
+    void vsCodeAppend(const char* str) { this->codeAppend(kVertex_ShaderType, str); }
+    void gsCodeAppend(const char* str) { this->codeAppend(kGeometry_ShaderType, str); }
+    void fsCodeAppend(const char* str) { this->codeAppend(kFragment_ShaderType, str); }
+
     /** Appends a 2D texture sample with projection if necessary. coordType must either be Vec2f or
         Vec3f. The latter is interpreted as projective texture coords. The vec length and swizzle
         order of the result depends on the GrTextureAccess associated with the TextureSampler. */
@@ -88,15 +118,23 @@
                              const char* coordName,
                              GrSLType coordType = kVec2f_GrSLType) const;
 
+    /** Version of above that appends the result to the shader code rather than an SkString.
+        Currently the shader type must be kFragment */
+    void appendTextureLookup(ShaderType,
+                             const TextureSampler&,
+                             const char* coordName,
+                             GrSLType coordType = kVec2f_GrSLType);
+
+
     /** Does the work of appendTextureLookup and modulates the result by modulation. The result is
         always a vec4. modulation and the swizzle specified by TextureSampler must both be vec4 or
         float. If modulation is "" or NULL it this function acts as though appendTextureLookup were
         called. */
-    void appendTextureLookupAndModulate(SkString* out,
+    void appendTextureLookupAndModulate(ShaderType,
                                         const char* modulation,
                                         const TextureSampler&,
                                         const char* coordName,
-                                        GrSLType coordType = kVec2f_GrSLType) const;
+                                        GrSLType coordType = kVec2f_GrSLType);
 
     /** Emits a helper function outside of main(). Currently ShaderType must be
         kFragment_ShaderType. */
@@ -190,6 +228,9 @@
     const GrGLContextInfo& ctxInfo() const { return fCtxInfo; }
 
 private:
+    void codeAppendf(ShaderType type, const char format[], va_list args);
+    void codeAppend(ShaderType type, const char* str);
+
     typedef GrTAllocator<GrGLShaderVar> VarArray;
 
     void appendDecls(const VarArray&, SkString*) const;
@@ -209,9 +250,6 @@
     VarArray    fFSInputs;
     SkString    fGSHeader; // layout qualifiers specific to GS
     VarArray    fFSOutputs;
-    SkString    fVSCode;
-    SkString    fGSCode;
-    SkString    fFSCode;
     bool        fUsesGS;
 
 private:
@@ -225,6 +263,10 @@
     SkString                            fFSFunctions;
     SkString                            fFSHeader;
 
+    SkString                            fFSCode;
+    SkString                            fVSCode;
+    SkString                            fGSCode;
+
     bool                                fSetupFragPosition;
     GrGLUniformManager::UniformHandle   fRTHeightUniform;