Initial refactor of shaderbuilder to prepare for geometry shaders

gitignore for eclipse

BUG=skia:
R=bsalomon@google.com, bsalomon@chromium.org

Author: joshualitt@chromium.org

Review URL: https://codereview.chromium.org/491673002
diff --git a/.gitignore b/.gitignore
index 27ddb22..cedd0ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@
 .android_config
 .gclient*
 .gm-actuals
+.cproject
+.project
+.settings/
 TAGS
 common
 gyp/build
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 56ef4b5..f00cfac 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -208,7 +208,6 @@
       '<(skia_src_path)/gpu/gl/GrGLPathRange.h',
       '<(skia_src_path)/gpu/gl/GrGLPathRendering.cpp',
       '<(skia_src_path)/gpu/gl/GrGLPathRendering.h',
-      '<(skia_src_path)/gpu/gl/GrGLSLPrettyPrint.cpp',
       '<(skia_src_path)/gpu/gl/GrGLProgram.cpp',
       '<(skia_src_path)/gpu/gl/GrGLProgram.h',
       '<(skia_src_path)/gpu/gl/GrGLProgramDesc.cpp',
@@ -219,8 +218,6 @@
       '<(skia_src_path)/gpu/gl/GrGLProgramDataManager.h',
       '<(skia_src_path)/gpu/gl/GrGLRenderTarget.cpp',
       '<(skia_src_path)/gpu/gl/GrGLRenderTarget.h',
-      '<(skia_src_path)/gpu/gl/GrGLShaderBuilder.cpp',
-      '<(skia_src_path)/gpu/gl/GrGLShaderBuilder.h',
       '<(skia_src_path)/gpu/gl/GrGLShaderVar.h',
       '<(skia_src_path)/gpu/gl/GrGLSL.cpp',
       '<(skia_src_path)/gpu/gl/GrGLSL.h',
@@ -240,6 +237,21 @@
       '<(skia_src_path)/gpu/gl/GrGpuGL.h',
       '<(skia_src_path)/gpu/gl/GrGpuGL_program.cpp',
 
+      # Files for building GLSL shaders
+      '<(skia_src_path)/gpu/gl/builders/GrGLSLPrettyPrint.cpp',
+      '<(skia_src_path)/gpu/gl/builders/GrGLShaderBuilder.cpp',
+      '<(skia_src_path)/gpu/gl/builders/GrGLShaderBuilder.h',
+      '<(skia_src_path)/gpu/gl/builders/GrGLProgramBuilder.cpp',
+      '<(skia_src_path)/gpu/gl/builders/GrGLProgramBuilder.h',
+      '<(skia_src_path)/gpu/gl/builders/GrGLShaderStringBuilder.cpp',
+      '<(skia_src_path)/gpu/gl/builders/GrGLShaderStringBuilder.h',
+      '<(skia_src_path)/gpu/gl/builders/GrGLVertexShaderBuilder.cpp',
+      '<(skia_src_path)/gpu/gl/builders/GrGLVertexShaderBuilder.h',
+      '<(skia_src_path)/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp',
+      '<(skia_src_path)/gpu/gl/builders/GrGLFragmentShaderBuilder.h',
+      '<(skia_src_path)/gpu/gl/builders/GrGLGeometryShaderBuilder.cpp',
+      '<(skia_src_path)/gpu/gl/builders/GrGLGeometryShaderBuilder.h',
+
       # Sk files
       '<(skia_include_path)/gpu/SkGpuDevice.h',
       '<(skia_include_path)/gpu/SkGr.h',
diff --git a/include/core/SkString.h b/include/core/SkString.h
index bc06cb0..8a962ae 100644
--- a/include/core/SkString.h
+++ b/include/core/SkString.h
@@ -195,6 +195,7 @@
     void appendf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
     void appendVAList(const char format[], va_list);
     void prependf(const char format[], ...) SK_PRINTF_LIKE(2, 3);
+    void prependVAList(const char format[], va_list);
 
     void remove(size_t offset, size_t length);
 
diff --git a/include/gpu/GrEffect.h b/include/gpu/GrEffect.h
index 8cb870e..4734c7c 100644
--- a/include/gpu/GrEffect.h
+++ b/include/gpu/GrEffect.h
@@ -113,7 +113,7 @@
     bool willReadFragmentPosition() const { return fWillReadFragmentPosition; }
 
     /** Will this effect emit custom vertex shader code?
-        (To set this value the effect must inherit from GrVertexEffect.) */
+        (To set this value the effect must inherit from GrEffect.) */
     bool hasVertexCode() const { return fHasVertexCode; }
 
     int numVertexAttribs() const {
diff --git a/src/core/SkString.cpp b/src/core/SkString.cpp
index 1e29dc7..48459db 100644
--- a/src/core/SkString.cpp
+++ b/src/core/SkString.cpp
@@ -583,6 +583,14 @@
     this->prepend(buffer, strlen(buffer));
 }
 
+void SkString::prependVAList(const char format[], va_list args) {
+    char    buffer[kBufferSize];
+    VSNPRINTF(buffer, kBufferSize, format, args);
+
+    this->prepend(buffer, strlen(buffer));
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 
 void SkString::remove(size_t offset, size_t length) {
diff --git a/src/core/SkXfermode.cpp b/src/core/SkXfermode.cpp
index 7608b79..b10b5e1 100644
--- a/src/core/SkXfermode.cpp
+++ b/src/core/SkXfermode.cpp
@@ -783,7 +783,7 @@
 #include "GrEffectUnitTest.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 
 /**
  * GrEffect that implements the all the separable xfer modes that cannot be expressed as Coeffs.
@@ -821,7 +821,7 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
             : GrGLEffect(factory) {
         }
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -830,82 +830,83 @@
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
             SkXfermode::Mode mode = drawEffect.castEffect<XferEffect>().mode();
             const GrTexture* backgroundTex = drawEffect.castEffect<XferEffect>().backgroundAccess().getTexture();
+            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
             const char* dstColor;
             if (backgroundTex) {
                 dstColor = "bgColor";
-                builder->fsCodeAppendf("\t\tvec4 %s = ", dstColor);
-                builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
-                builder->fsCodeAppendf(";\n");
+                fsBuilder->codeAppendf("\t\tvec4 %s = ", dstColor);
+                fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
+                fsBuilder->codeAppendf(";\n");
             } else {
-                dstColor = builder->dstColor();
+                dstColor = fsBuilder->dstColor();
             }
             SkASSERT(NULL != dstColor);
 
             // We don't try to optimize for this case at all
             if (NULL == inputColor) {
-                builder->fsCodeAppendf("\t\tconst vec4 ones = vec4(1);\n");
+                fsBuilder->codeAppendf("\t\tconst vec4 ones = vec4(1);\n");
                 inputColor = "ones";
             }
-            builder->fsCodeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
+            fsBuilder->codeAppendf("\t\t// SkXfermode::Mode: %s\n", SkXfermode::ModeName(mode));
 
             // These all perform src-over on the alpha channel.
-            builder->fsCodeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n",
+            fsBuilder->codeAppendf("\t\t%s.a = %s.a + (1.0 - %s.a) * %s.a;\n",
                                     outputColor, inputColor, inputColor, dstColor);
 
             switch (mode) {
                 case SkXfermode::kOverlay_Mode:
                     // Overlay is Hard-Light with the src and dst reversed
-                    HardLight(builder, outputColor, dstColor, inputColor);
+                    HardLight(fsBuilder, outputColor, dstColor, inputColor);
                     break;
                 case SkXfermode::kDarken_Mode:
-                    builder->fsCodeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
+                    fsBuilder->codeAppendf("\t\t%s.rgb = min((1.0 - %s.a) * %s.rgb + %s.rgb, "
                                                             "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
                                             outputColor,
                                             inputColor, dstColor, inputColor,
                                             dstColor, inputColor, dstColor);
                     break;
                 case SkXfermode::kLighten_Mode:
-                    builder->fsCodeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
+                    fsBuilder->codeAppendf("\t\t%s.rgb = max((1.0 - %s.a) * %s.rgb + %s.rgb, "
                                                             "(1.0 - %s.a) * %s.rgb + %s.rgb);\n",
                                             outputColor,
                                             inputColor, dstColor, inputColor,
                                             dstColor, inputColor, dstColor);
                     break;
                 case SkXfermode::kColorDodge_Mode:
-                    ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'r');
-                    ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'g');
-                    ColorDodgeComponent(builder, outputColor, inputColor, dstColor, 'b');
+                    ColorDodgeComponent(fsBuilder, outputColor, inputColor, dstColor, 'r');
+                    ColorDodgeComponent(fsBuilder, outputColor, inputColor, dstColor, 'g');
+                    ColorDodgeComponent(fsBuilder, outputColor, inputColor, dstColor, 'b');
                     break;
                 case SkXfermode::kColorBurn_Mode:
-                    ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'r');
-                    ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'g');
-                    ColorBurnComponent(builder, outputColor, inputColor, dstColor, 'b');
+                    ColorBurnComponent(fsBuilder, outputColor, inputColor, dstColor, 'r');
+                    ColorBurnComponent(fsBuilder, outputColor, inputColor, dstColor, 'g');
+                    ColorBurnComponent(fsBuilder, outputColor, inputColor, dstColor, 'b');
                     break;
                 case SkXfermode::kHardLight_Mode:
-                    HardLight(builder, outputColor, inputColor, dstColor);
+                    HardLight(fsBuilder, outputColor, inputColor, dstColor);
                     break;
                 case SkXfermode::kSoftLight_Mode:
-                    builder->fsCodeAppendf("\t\tif (0.0 == %s.a) {\n", dstColor);
-                    builder->fsCodeAppendf("\t\t\t%s.rgba = %s;\n", outputColor, inputColor);
-                    builder->fsCodeAppendf("\t\t} else {\n");
-                    SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'r');
-                    SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'g');
-                    SoftLightComponentPosDstAlpha(builder, outputColor, inputColor, dstColor, 'b');
-                    builder->fsCodeAppendf("\t\t}\n");
+                    fsBuilder->codeAppendf("\t\tif (0.0 == %s.a) {\n", dstColor);
+                    fsBuilder->codeAppendf("\t\t\t%s.rgba = %s;\n", outputColor, inputColor);
+                    fsBuilder->codeAppendf("\t\t} else {\n");
+                    SoftLightComponentPosDstAlpha(fsBuilder, outputColor, inputColor, dstColor, 'r');
+                    SoftLightComponentPosDstAlpha(fsBuilder, outputColor, inputColor, dstColor, 'g');
+                    SoftLightComponentPosDstAlpha(fsBuilder, outputColor, inputColor, dstColor, 'b');
+                    fsBuilder->codeAppendf("\t\t}\n");
                     break;
                 case SkXfermode::kDifference_Mode:
-                    builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb -"
+                    fsBuilder->codeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb -"
                                                        "2.0 * min(%s.rgb * %s.a, %s.rgb * %s.a);\n",
                                            outputColor, inputColor, dstColor, inputColor, dstColor,
                                            dstColor, inputColor);
                     break;
                 case SkXfermode::kExclusion_Mode:
-                    builder->fsCodeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - "
+                    fsBuilder->codeAppendf("\t\t%s.rgb = %s.rgb + %s.rgb - "
                                                         "2.0 * %s.rgb * %s.rgb;\n",
                                            outputColor, dstColor, inputColor, dstColor, inputColor);
                     break;
                 case SkXfermode::kMultiply_Mode:
-                    builder->fsCodeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + "
+                    fsBuilder->codeAppendf("\t\t%s.rgb = (1.0 - %s.a) * %s.rgb + "
                                                         "(1.0 - %s.a) * %s.rgb + "
                                                          "%s.rgb * %s.rgb;\n",
                                            outputColor, inputColor, dstColor, dstColor, inputColor,
@@ -914,52 +915,52 @@
                 case SkXfermode::kHue_Mode: {
                     //  SetLum(SetSat(S * Da, Sat(D * Sa)), Sa*Da, D*Sa) + (1 - Sa) * D + (1 - Da) * S
                     SkString setSat, setLum;
-                    AddSatFunction(builder, &setSat);
-                    AddLumFunction(builder, &setLum);
-                    builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
+                    AddSatFunction(fsBuilder, &setSat);
+                    AddLumFunction(fsBuilder, &setLum);
+                    fsBuilder->codeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
                                            dstColor, inputColor);
-                    builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
+                    fsBuilder->codeAppendf("\t\t%s.rgb = %s(%s(%s.rgb * %s.a, dstSrcAlpha.rgb), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
                                            outputColor, setLum.c_str(), setSat.c_str(), inputColor,
                                            dstColor);
-                    builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
+                    fsBuilder->codeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
                                            outputColor, inputColor, dstColor, dstColor, inputColor);
                     break;
                 }
                 case SkXfermode::kSaturation_Mode: {
                     // SetLum(SetSat(D * Sa, Sat(S * Da)), Sa*Da, D*Sa)) + (1 - Sa) * D + (1 - Da) * S
                     SkString setSat, setLum;
-                    AddSatFunction(builder, &setSat);
-                    AddLumFunction(builder, &setLum);
-                    builder->fsCodeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
+                    AddSatFunction(fsBuilder, &setSat);
+                    AddLumFunction(fsBuilder, &setLum);
+                    fsBuilder->codeAppendf("\t\tvec4 dstSrcAlpha = %s * %s.a;\n",
                                            dstColor, inputColor);
-                    builder->fsCodeAppendf("\t\t%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
+                    fsBuilder->codeAppendf("\t\t%s.rgb = %s(%s(dstSrcAlpha.rgb, %s.rgb * %s.a), dstSrcAlpha.a, dstSrcAlpha.rgb);\n",
                                            outputColor, setLum.c_str(), setSat.c_str(), inputColor,
                                            dstColor);
-                    builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
+                    fsBuilder->codeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
                                            outputColor, inputColor, dstColor, dstColor, inputColor);
                     break;
                 }
                 case SkXfermode::kColor_Mode: {
                     //  SetLum(S * Da, Sa* Da, D * Sa) + (1 - Sa) * D + (1 - Da) * S
                     SkString setLum;
-                    AddLumFunction(builder, &setLum);
-                    builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
+                    AddLumFunction(fsBuilder, &setLum);
+                    fsBuilder->codeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
                                            inputColor, dstColor);
-                    builder->fsCodeAppendf("\t\t%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);\n",
+                    fsBuilder->codeAppendf("\t\t%s.rgb = %s(srcDstAlpha.rgb, srcDstAlpha.a, %s.rgb * %s.a);\n",
                                            outputColor, setLum.c_str(), dstColor, inputColor);
-                    builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
+                    fsBuilder->codeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
                                            outputColor, inputColor, dstColor, dstColor, inputColor);
                     break;
                 }
                 case SkXfermode::kLuminosity_Mode: {
                     //  SetLum(D * Sa, Sa* Da, S * Da) + (1 - Sa) * D + (1 - Da) * S
                     SkString setLum;
-                    AddLumFunction(builder, &setLum);
-                    builder->fsCodeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
+                    AddLumFunction(fsBuilder, &setLum);
+                    fsBuilder->codeAppendf("\t\tvec4 srcDstAlpha = %s * %s.a;\n",
                                            inputColor, dstColor);
-                    builder->fsCodeAppendf("\t\t%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);\n",
+                    fsBuilder->codeAppendf("\t\t%s.rgb = %s(%s.rgb * %s.a, srcDstAlpha.a, srcDstAlpha.rgb);\n",
                                            outputColor, setLum.c_str(), dstColor, inputColor);
-                    builder->fsCodeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
+                    fsBuilder->codeAppendf("\t\t%s.rgb += (1.0 - %s.a) * %s.rgb + (1.0 - %s.a) * %s.rgb;\n",
                                            outputColor, inputColor, dstColor, dstColor, inputColor);
                     break;
                 }
@@ -979,116 +980,116 @@
         }
 
     private:
-        static void HardLight(GrGLShaderBuilder* builder,
+        static void HardLight(GrGLFragmentShaderBuilder* fsBuilder,
                               const char* final,
                               const char* src,
                               const char* dst) {
             static const char kComponents[] = {'r', 'g', 'b'};
             for (size_t i = 0; i < SK_ARRAY_COUNT(kComponents); ++i) {
                 char component = kComponents[i];
-                builder->fsCodeAppendf("\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
-                builder->fsCodeAppendf("\t\t\t%s.%c = 2.0 * %s.%c * %s.%c;\n", final, component, src, component, dst, component);
-                builder->fsCodeAppend("\t\t} else {\n");
-                builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);\n",
+                fsBuilder->codeAppendf("\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
+                fsBuilder->codeAppendf("\t\t\t%s.%c = 2.0 * %s.%c * %s.%c;\n", final, component, src, component, dst, component);
+                fsBuilder->codeAppend("\t\t} else {\n");
+                fsBuilder->codeAppendf("\t\t\t%s.%c = %s.a * %s.a - 2.0 * (%s.a - %s.%c) * (%s.a - %s.%c);\n",
                                        final, component, src, dst, dst, dst, component, src, src, component);
-                builder->fsCodeAppend("\t\t}\n");
+                fsBuilder->codeAppend("\t\t}\n");
             }
-            builder->fsCodeAppendf("\t\t%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);\n",
+            fsBuilder->codeAppendf("\t\t%s.rgb += %s.rgb * (1.0 - %s.a) + %s.rgb * (1.0 - %s.a);\n",
                                    final, src, dst, dst, src);
         }
 
         // Does one component of color-dodge
-        static void ColorDodgeComponent(GrGLShaderBuilder* builder,
+        static void ColorDodgeComponent(GrGLFragmentShaderBuilder* fsBuilder,
                                         const char* final,
                                         const char* src,
                                         const char* dst,
                                         const char component) {
-            builder->fsCodeAppendf("\t\tif (0.0 == %s.%c) {\n", dst, component);
-            builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
+            fsBuilder->codeAppendf("\t\tif (0.0 == %s.%c) {\n", dst, component);
+            fsBuilder->codeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
                                    final, component, src, component, dst);
-            builder->fsCodeAppend("\t\t} else {\n");
-            builder->fsCodeAppendf("\t\t\tfloat d = %s.a - %s.%c;\n", src, src, component);
-            builder->fsCodeAppend("\t\t\tif (0.0 == d) {\n");
-            builder->fsCodeAppendf("\t\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
+            fsBuilder->codeAppend("\t\t} else {\n");
+            fsBuilder->codeAppendf("\t\t\tfloat d = %s.a - %s.%c;\n", src, src, component);
+            fsBuilder->codeAppend("\t\t\tif (0.0 == d) {\n");
+            fsBuilder->codeAppendf("\t\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
                                    final, component, src, dst, src, component, dst, dst, component,
                                    src);
-            builder->fsCodeAppend("\t\t\t} else {\n");
-            builder->fsCodeAppendf("\t\t\t\td = min(%s.a, %s.%c * %s.a / d);\n",
+            fsBuilder->codeAppend("\t\t\t} else {\n");
+            fsBuilder->codeAppendf("\t\t\t\td = min(%s.a, %s.%c * %s.a / d);\n",
                                    dst, dst, component, src);
-            builder->fsCodeAppendf("\t\t\t\t%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
+            fsBuilder->codeAppendf("\t\t\t\t%s.%c = d * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
                                    final, component, src, src, component, dst, dst, component, src);
-            builder->fsCodeAppend("\t\t\t}\n");
-            builder->fsCodeAppend("\t\t}\n");
+            fsBuilder->codeAppend("\t\t\t}\n");
+            fsBuilder->codeAppend("\t\t}\n");
         }
 
         // Does one component of color-burn
-        static void ColorBurnComponent(GrGLShaderBuilder* builder,
+        static void ColorBurnComponent(GrGLFragmentShaderBuilder* fsBuilder,
                                        const char* final,
                                        const char* src,
                                        const char* dst,
                                        const char component) {
-            builder->fsCodeAppendf("\t\tif (%s.a == %s.%c) {\n", dst, dst, component);
-            builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
+            fsBuilder->codeAppendf("\t\tif (%s.a == %s.%c) {\n", dst, dst, component);
+            fsBuilder->codeAppendf("\t\t\t%s.%c = %s.a * %s.a + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
                                    final, component, src, dst, src, component, dst, dst, component,
                                    src);
-            builder->fsCodeAppendf("\t\t} else if (0.0 == %s.%c) {\n", src, component);
-            builder->fsCodeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
+            fsBuilder->codeAppendf("\t\t} else if (0.0 == %s.%c) {\n", src, component);
+            fsBuilder->codeAppendf("\t\t\t%s.%c = %s.%c * (1.0 - %s.a);\n",
                                    final, component, dst, component, src);
-            builder->fsCodeAppend("\t\t} else {\n");
-            builder->fsCodeAppendf("\t\t\tfloat d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);\n",
+            fsBuilder->codeAppend("\t\t} else {\n");
+            fsBuilder->codeAppendf("\t\t\tfloat d = max(0.0, %s.a - (%s.a - %s.%c) * %s.a / %s.%c);\n",
                                    dst, dst, dst, component, src, src, component);
-            builder->fsCodeAppendf("\t\t\t%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
+            fsBuilder->codeAppendf("\t\t\t%s.%c = %s.a * d + %s.%c * (1.0 - %s.a) + %s.%c * (1.0 - %s.a);\n",
                                    final, component, src, src, component, dst, dst, component, src);
-            builder->fsCodeAppend("\t\t}\n");
+            fsBuilder->codeAppend("\t\t}\n");
         }
 
         // Does one component of soft-light. Caller should have already checked that dst alpha > 0.
-        static void SoftLightComponentPosDstAlpha(GrGLShaderBuilder* builder,
+        static void SoftLightComponentPosDstAlpha(GrGLFragmentShaderBuilder* fsBuilder,
                                                   const char* final,
                                                   const char* src,
                                                   const char* dst,
                                                   const char component) {
             // if (2S < Sa)
-            builder->fsCodeAppendf("\t\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
+            fsBuilder->codeAppendf("\t\t\tif (2.0 * %s.%c <= %s.a) {\n", src, component, src);
             // (D^2 (Sa-2 S))/Da+(1-Da) S+D (-Sa+2 S+1)
-            builder->fsCodeAppendf("\t\t\t\t%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a + (1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);\n",
+            fsBuilder->codeAppendf("\t\t\t\t%s.%c = (%s.%c*%s.%c*(%s.a - 2.0*%s.%c)) / %s.a + (1.0 - %s.a) * %s.%c + %s.%c*(-%s.a + 2.0*%s.%c + 1.0);\n",
                                    final, component, dst, component, dst, component, src, src,
                                    component, dst, dst, src, component, dst, component, src, src,
                                    component);
             // else if (4D < Da)
-            builder->fsCodeAppendf("\t\t\t} else if (4.0 * %s.%c <= %s.a) {\n",
+            fsBuilder->codeAppendf("\t\t\t} else if (4.0 * %s.%c <= %s.a) {\n",
                                    dst, component, dst);
-            builder->fsCodeAppendf("\t\t\t\tfloat DSqd = %s.%c * %s.%c;\n",
+            fsBuilder->codeAppendf("\t\t\t\tfloat DSqd = %s.%c * %s.%c;\n",
                                    dst, component, dst, component);
-            builder->fsCodeAppendf("\t\t\t\tfloat DCub = DSqd * %s.%c;\n", dst, component);
-            builder->fsCodeAppendf("\t\t\t\tfloat DaSqd = %s.a * %s.a;\n", dst, dst);
-            builder->fsCodeAppendf("\t\t\t\tfloat DaCub = DaSqd * %s.a;\n", dst);
+            fsBuilder->codeAppendf("\t\t\t\tfloat DCub = DSqd * %s.%c;\n", dst, component);
+            fsBuilder->codeAppendf("\t\t\t\tfloat DaSqd = %s.a * %s.a;\n", dst, dst);
+            fsBuilder->codeAppendf("\t\t\t\tfloat DaCub = DaSqd * %s.a;\n", dst);
             // (Da^3 (-S)+Da^2 (S-D (3 Sa-6 S-1))+12 Da D^2 (Sa-2 S)-16 D^3 (Sa-2 S))/Da^2
-            builder->fsCodeAppendf("\t\t\t\t%s.%c = (-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) + 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) / DaSqd;\n",
+            fsBuilder->codeAppendf("\t\t\t\t%s.%c = (-DaCub*%s.%c + DaSqd*(%s.%c - %s.%c * (3.0*%s.a - 6.0*%s.%c - 1.0)) + 12.0*%s.a*DSqd*(%s.a - 2.0*%s.%c) - 16.0*DCub * (%s.a - 2.0*%s.%c)) / DaSqd;\n",
                                    final, component, src, component, src, component, dst, component,
                                    src, src, component, dst, src, src, component, src, src,
                                    component);
-            builder->fsCodeAppendf("\t\t\t} else {\n");
+            fsBuilder->codeAppendf("\t\t\t} else {\n");
             // -sqrt(Da * D) (Sa-2 S)-Da S+D (Sa-2 S+1)+S
-            builder->fsCodeAppendf("\t\t\t\t%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c + %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;\n",
+            fsBuilder->codeAppendf("\t\t\t\t%s.%c = -sqrt(%s.a*%s.%c)*(%s.a - 2.0*%s.%c) - %s.a*%s.%c + %s.%c*(%s.a - 2.0*%s.%c + 1.0) + %s.%c;\n",
                                     final, component, dst, dst, component, src, src, component, dst,
                                     src, component, dst, component, src, src, component, src,
                                     component);
-            builder->fsCodeAppendf("\t\t\t}\n");
+            fsBuilder->codeAppendf("\t\t\t}\n");
         }
 
         // Adds a function that takes two colors and an alpha as input. It produces a color with the
         // hue and saturation of the first color, the luminosity of the second color, and the input
         // alpha. It has this signature:
         //      vec3 set_luminance(vec3 hueSatColor, float alpha, vec3 lumColor).
-        static void AddLumFunction(GrGLShaderBuilder* builder, SkString* setLumFunction) {
+        static void AddLumFunction(GrGLFragmentShaderBuilder* fsBuilder, SkString* setLumFunction) {
             // Emit a helper that gets the luminance of a color.
             SkString getFunction;
             GrGLShaderVar getLumArgs[] = {
                 GrGLShaderVar("color", kVec3f_GrSLType),
             };
             SkString getLumBody("\treturn dot(vec3(0.3, 0.59, 0.11), color);\n");
-            builder->fsEmitFunction(kFloat_GrSLType,
+            fsBuilder->emitFunction(kFloat_GrSLType,
                                     "luminance",
                                     SK_ARRAY_COUNT(getLumArgs), getLumArgs,
                                     getLumBody.c_str(),
@@ -1113,7 +1114,7 @@
                               "\t\toutColor = outLum + ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) / (maxComp - outLum);\n"
                               "\t}\n"
                               "\treturn outColor;\n");
-            builder->fsEmitFunction(kVec3f_GrSLType,
+            fsBuilder->emitFunction(kVec3f_GrSLType,
                                     "set_luminance",
                                     SK_ARRAY_COUNT(setLumArgs), setLumArgs,
                                     setLumBody.c_str(),
@@ -1123,14 +1124,14 @@
         // Adds a function that creates a color with the hue and luminosity of one input color and
         // the saturation of another color. It will have this signature:
         //      float set_saturation(vec3 hueLumColor, vec3 satColor)
-        static void AddSatFunction(GrGLShaderBuilder* builder, SkString* setSatFunction) {
+        static void AddSatFunction(GrGLFragmentShaderBuilder* fsBuilder, SkString* setSatFunction) {
             // Emit a helper that gets the saturation of a color
             SkString getFunction;
             GrGLShaderVar getSatArgs[] = { GrGLShaderVar("color", kVec3f_GrSLType) };
             SkString getSatBody;
             getSatBody.printf("\treturn max(max(color.r, color.g), color.b) - "
                               "min(min(color.r, color.g), color.b);\n");
-            builder->fsEmitFunction(kFloat_GrSLType,
+            fsBuilder->emitFunction(kFloat_GrSLType,
                                     "saturation",
                                     SK_ARRAY_COUNT(getSatArgs), getSatArgs,
                                     getSatBody.c_str(),
@@ -1156,7 +1157,7 @@
                                               "\t} else {\n"
                                               "\t\treturn vec3(0, 0, 0);\n"
                                               "\t}\n";
-            builder->fsEmitFunction(kVec3f_GrSLType,
+            fsBuilder->emitFunction(kVec3f_GrSLType,
                                     "set_saturation_helper",
                                     SK_ARRAY_COUNT(helperArgs), helperArgs,
                                     kHelperBody,
@@ -1187,7 +1188,7 @@
                                "\treturn hueLumColor;\n",
                                getFunction.c_str(), helpFunc, helpFunc, helpFunc, helpFunc,
                                helpFunc, helpFunc);
-            builder->fsEmitFunction(kVec3f_GrSLType,
+            fsBuilder->emitFunction(kVec3f_GrSLType,
                                     "set_saturation",
                                     SK_ARRAY_COUNT(setSatArgs), setSatArgs,
                                     setSatBody.c_str(),
diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp
index 9c59347..8022724 100644
--- a/src/effects/SkAlphaThresholdFilter.cpp
+++ b/src/effects/SkAlphaThresholdFilter.cpp
@@ -50,7 +50,7 @@
 #include "GrCoordTransform.h"
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrTBackendEffectFactory.h"
 #include "GrTextureAccess.h"
 
@@ -118,7 +118,7 @@
 public:
     GrGLAlphaThresholdEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -140,39 +140,41 @@
     : INHERITED(factory) {
 }
 
-void GrGLAlphaThresholdEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLAlphaThresholdEffect::emitCode(GrGLProgramBuilder* builder,
                                         const GrDrawEffect&,
                                         const GrEffectKey& key,
                                         const char* outputColor,
                                         const char* inputColor,
                                         const TransformedCoordsArray& coords,
                                         const TextureSamplerArray& samplers) {
-    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
-    SkString maskCoords2D = builder->ensureFSCoords2D(coords, 1);
     fInnerThresholdVar = builder->addUniform(
-        GrGLShaderBuilder::kFragment_Visibility,
+        GrGLProgramBuilder::kFragment_Visibility,
         kFloat_GrSLType, "inner_threshold");
     fOuterThresholdVar = builder->addUniform(
-        GrGLShaderBuilder::kFragment_Visibility,
+        GrGLProgramBuilder::kFragment_Visibility,
         kFloat_GrSLType, "outer_threshold");
 
-    builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
-    builder->fsCodeAppendf("\t\tvec2 mask_coord = %s;\n", maskCoords2D.c_str());
-    builder->fsCodeAppend("\t\tvec4 input_color = ");
-    builder->fsAppendTextureLookup(samplers[0], "coord");
-    builder->fsCodeAppend(";\n");
-    builder->fsCodeAppend("\t\tvec4 mask_color = ");
-    builder->fsAppendTextureLookup(samplers[1], "mask_coord");
-    builder->fsCodeAppend(";\n");
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
+    SkString maskCoords2D = fsBuilder->ensureFSCoords2D(coords, 1);
 
-    builder->fsCodeAppendf("\t\tfloat inner_thresh = %s;\n",
+    fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
+    fsBuilder->codeAppendf("\t\tvec2 mask_coord = %s;\n", maskCoords2D.c_str());
+    fsBuilder->codeAppend("\t\tvec4 input_color = ");
+    fsBuilder->appendTextureLookup(samplers[0], "coord");
+    fsBuilder->codeAppend(";\n");
+    fsBuilder->codeAppend("\t\tvec4 mask_color = ");
+    fsBuilder->appendTextureLookup(samplers[1], "mask_coord");
+    fsBuilder->codeAppend(";\n");
+
+    fsBuilder->codeAppendf("\t\tfloat inner_thresh = %s;\n",
                            builder->getUniformCStr(fInnerThresholdVar));
-    builder->fsCodeAppendf("\t\tfloat outer_thresh = %s;\n",
+    fsBuilder->codeAppendf("\t\tfloat outer_thresh = %s;\n",
                            builder->getUniformCStr(fOuterThresholdVar));
-    builder->fsCodeAppend("\t\tfloat mask = mask_color.a;\n");
+    fsBuilder->codeAppend("\t\tfloat mask = mask_color.a;\n");
 
-    builder->fsCodeAppend("vec4 color = input_color;\n");
-    builder->fsCodeAppend("\t\tif (mask < 0.5) {\n"
+    fsBuilder->codeAppend("vec4 color = input_color;\n");
+    fsBuilder->codeAppend("\t\tif (mask < 0.5) {\n"
                           "\t\t\tif (color.a > outer_thresh) {\n"
                           "\t\t\t\tfloat scale = outer_thresh / color.a;\n"
                           "\t\t\t\tcolor.rgb *= scale;\n"
@@ -184,7 +186,7 @@
                           "\t\t\tcolor.a = inner_thresh;\n"
                           "\t\t}\n");
 
-    builder->fsCodeAppendf("%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr4("color")).c_str());
 }
 
diff --git a/src/effects/SkArithmeticMode.cpp b/src/effects/SkArithmeticMode.cpp
index d3be826..be636c5 100644
--- a/src/effects/SkArithmeticMode.cpp
+++ b/src/effects/SkArithmeticMode.cpp
@@ -15,7 +15,7 @@
 #include "GrContext.h"
 #include "GrCoordTransform.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrTBackendEffectFactory.h"
 #endif
 
@@ -252,7 +252,7 @@
     GrGLArithmeticEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
     virtual ~GrGLArithmeticEffect();
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -359,7 +359,7 @@
 GrGLArithmeticEffect::~GrGLArithmeticEffect() {
 }
 
-void GrGLArithmeticEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLArithmeticEffect::emitCode(GrGLProgramBuilder* builder,
                                     const GrDrawEffect& drawEffect,
                                     const GrEffectKey& key,
                                     const char* outputColor,
@@ -368,42 +368,43 @@
                                     const TextureSamplerArray& samplers) {
 
     GrTexture* backgroundTex = drawEffect.castEffect<GrArithmeticEffect>().backgroundTexture();
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     const char* dstColor;
     if (backgroundTex) {
-        builder->fsCodeAppend("\t\tvec4 bgColor = ");
-        builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
-        builder->fsCodeAppendf(";\n");
+        fsBuilder->codeAppend("\t\tvec4 bgColor = ");
+        fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
+        fsBuilder->codeAppendf(";\n");
         dstColor = "bgColor";
     } else {
-        dstColor = builder->dstColor();
+        dstColor = fsBuilder->dstColor();
     }
 
     SkASSERT(NULL != dstColor);
-    fKUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fKUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                 kVec4f_GrSLType, "k");
     const char* kUni = builder->getUniformCStr(fKUni);
 
     // We don't try to optimize for this case at all
     if (NULL == inputColor) {
-        builder->fsCodeAppendf("\t\tconst vec4 src = vec4(1);\n");
+        fsBuilder->codeAppendf("\t\tconst vec4 src = vec4(1);\n");
     } else {
-        builder->fsCodeAppendf("\t\tvec4 src = %s;\n", inputColor);
+        fsBuilder->codeAppendf("\t\tvec4 src = %s;\n", inputColor);
         if (gUseUnpremul) {
-            builder->fsCodeAppendf("\t\tsrc.rgb = clamp(src.rgb / src.a, 0.0, 1.0);\n");
+            fsBuilder->codeAppendf("\t\tsrc.rgb = clamp(src.rgb / src.a, 0.0, 1.0);\n");
         }
     }
 
-    builder->fsCodeAppendf("\t\tvec4 dst = %s;\n", dstColor);
+    fsBuilder->codeAppendf("\t\tvec4 dst = %s;\n", dstColor);
     if (gUseUnpremul) {
-        builder->fsCodeAppendf("\t\tdst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);\n");
+        fsBuilder->codeAppendf("\t\tdst.rgb = clamp(dst.rgb / dst.a, 0.0, 1.0);\n");
     }
 
-    builder->fsCodeAppendf("\t\t%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;\n", outputColor, kUni, kUni, kUni, kUni);
-    builder->fsCodeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
+    fsBuilder->codeAppendf("\t\t%s = %s.x * src * dst + %s.y * src + %s.z * dst + %s.w;\n", outputColor, kUni, kUni, kUni, kUni);
+    fsBuilder->codeAppendf("\t\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
     if (gUseUnpremul) {
-        builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
+        fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
     } else if (fEnforcePMColor) {
-        builder->fsCodeAppendf("\t\t%s.rgb = min(%s.rgb, %s.a);\n", outputColor, outputColor, outputColor);
+        fsBuilder->codeAppendf("\t\t%s.rgb = min(%s.rgb, %s.a);\n", outputColor, outputColor, outputColor);
     }
 }
 
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index 4e469bc..e4133a8 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -22,7 +22,7 @@
 #include "GrTexture.h"
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "effects/GrSimpleTextureEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "SkGrPixelRef.h"
@@ -610,7 +610,7 @@
 public:
     GrGLRectBlurEffect(const GrBackendEffectFactory& factory,
                       const GrDrawEffect&);
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -635,23 +635,23 @@
     : INHERITED(factory) {
 }
 
-void OutputRectBlurProfileLookup(GrGLShaderBuilder* builder,
+void OutputRectBlurProfileLookup(GrGLFragmentShaderBuilder* fsBuilder,
                                  const GrGLShaderBuilder::TextureSampler& sampler,
                                  const char *output,
                                  const char *profileSize, const char *loc,
                                  const char *blurred_width,
                                  const char *sharp_width) {
-    builder->fsCodeAppendf("\tfloat %s;\n", output);
-    builder->fsCodeAppendf("\t\t{\n");
-    builder->fsCodeAppendf("\t\t\tfloat coord = (0.5 * (abs(2.0*%s - %s) - %s))/%s;\n",
+    fsBuilder->codeAppendf("\tfloat %s;\n", output);
+    fsBuilder->codeAppendf("\t\t{\n");
+    fsBuilder->codeAppendf("\t\t\tfloat coord = (0.5 * (abs(2.0*%s - %s) - %s))/%s;\n",
                            loc, blurred_width, sharp_width, profileSize);
-    builder->fsCodeAppendf("\t\t\t%s = ", output);
-    builder->fsAppendTextureLookup(sampler, "vec2(coord,0.5)");
-    builder->fsCodeAppend(".a;\n");
-    builder->fsCodeAppendf("\t\t}\n");
+    fsBuilder->codeAppendf("\t\t\t%s = ", output);
+    fsBuilder->appendTextureLookup(sampler, "vec2(coord,0.5)");
+    fsBuilder->codeAppend(".a;\n");
+    fsBuilder->codeAppendf("\t\t}\n");
 }
 
-void GrGLRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLRectBlurEffect::emitCode(GrGLProgramBuilder* builder,
                                  const GrDrawEffect&,
                                  const GrEffectKey& key,
                                  const char* outputColor,
@@ -662,36 +662,37 @@
     const char *rectName;
     const char *profileSizeName;
 
-    fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fProxyRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                             kVec4f_GrSLType,
                                             "proxyRect",
                                             &rectName);
-    fProfileSizeUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fProfileSizeUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                             kFloat_GrSLType,
                                             "profileSize",
                                             &profileSizeName);
 
-    const char *fragmentPos = builder->fragmentPosition();
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    const char *fragmentPos = fsBuilder->fragmentPosition();
 
     if (inputColor) {
-        builder->fsCodeAppendf("\tvec4 src=%s;\n", inputColor);
+        fsBuilder->codeAppendf("\tvec4 src=%s;\n", inputColor);
     } else {
-        builder->fsCodeAppendf("\tvec4 src=vec4(1)\n;");
+        fsBuilder->codeAppendf("\tvec4 src=vec4(1)\n;");
     }
 
-    builder->fsCodeAppendf("\tvec2 translatedPos = %s.xy - %s.xy;\n", fragmentPos, rectName );
-    builder->fsCodeAppendf("\tfloat width = %s.z - %s.x;\n", rectName, rectName);
-    builder->fsCodeAppendf("\tfloat height = %s.w - %s.y;\n", rectName, rectName);
+    fsBuilder->codeAppendf("\tvec2 translatedPos = %s.xy - %s.xy;\n", fragmentPos, rectName );
+    fsBuilder->codeAppendf("\tfloat width = %s.z - %s.x;\n", rectName, rectName);
+    fsBuilder->codeAppendf("\tfloat height = %s.w - %s.y;\n", rectName, rectName);
 
-    builder->fsCodeAppendf("\tvec2 smallDims = vec2(width - %s, height-%s);\n", profileSizeName, profileSizeName);
-    builder->fsCodeAppendf("\tfloat center = 2.0 * floor(%s/2.0 + .25) - 1.0;\n", profileSizeName);
-    builder->fsCodeAppendf("\tvec2 wh = smallDims - vec2(center,center);\n");
+    fsBuilder->codeAppendf("\tvec2 smallDims = vec2(width - %s, height-%s);\n", profileSizeName, profileSizeName);
+    fsBuilder->codeAppendf("\tfloat center = 2.0 * floor(%s/2.0 + .25) - 1.0;\n", profileSizeName);
+    fsBuilder->codeAppendf("\tvec2 wh = smallDims - vec2(center,center);\n");
 
-    OutputRectBlurProfileLookup(builder, samplers[0], "horiz_lookup", profileSizeName, "translatedPos.x", "width", "wh.x");
-    OutputRectBlurProfileLookup(builder, samplers[0], "vert_lookup", profileSizeName, "translatedPos.y", "height", "wh.y");
+    OutputRectBlurProfileLookup(fsBuilder, samplers[0], "horiz_lookup", profileSizeName, "translatedPos.x", "width", "wh.x");
+    OutputRectBlurProfileLookup(fsBuilder, samplers[0], "vert_lookup", profileSizeName, "translatedPos.y", "height", "wh.y");
 
-    builder->fsCodeAppendf("\tfloat final = horiz_lookup * vert_lookup;\n");
-    builder->fsCodeAppendf("\t%s = src * vec4(final);\n", outputColor );
+    fsBuilder->codeAppendf("\tfloat final = horiz_lookup * vert_lookup;\n");
+    fsBuilder->codeAppendf("\t%s = src * vec4(final);\n", outputColor );
 }
 
 void GrGLRectBlurEffect::setData(const GrGLProgramDataManager& pdman,
@@ -971,7 +972,7 @@
 public:
     GrGLRRectBlurEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -993,7 +994,7 @@
     : INHERITED (factory) {
 }
 
-void GrGLRRectBlurEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLRRectBlurEffect::emitCode(GrGLProgramBuilder* builder,
                              const GrDrawEffect& drawEffect,
                              const GrEffectKey& key,
                              const char* outputColor,
@@ -1007,45 +1008,47 @@
     // The proxy rect has left, top, right, and bottom edges correspond to
     // components x, y, z, and w, respectively.
 
-    fProxyRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fProxyRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                             kVec4f_GrSLType,
                                             "proxyRect",
                                             &rectName);
-    fCornerRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fCornerRadiusUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                  kFloat_GrSLType,
                                                  "cornerRadius",
                                                  &cornerRadiusName);
-    fBlurRadiusUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fBlurRadiusUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                  kFloat_GrSLType,
                                                  "blurRadius",
                                                  &blurRadiusName);
-    const char* fragmentPos = builder->fragmentPosition();
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    const char* fragmentPos = fsBuilder->fragmentPosition();
 
     // warp the fragment position to the appropriate part of the 9patch blur texture
 
-    builder->fsCodeAppendf("\t\tvec2 rectCenter = (%s.xy + %s.zw)/2.0;\n", rectName, rectName);
-    builder->fsCodeAppendf("\t\tvec2 translatedFragPos = %s.xy - %s.xy;\n", fragmentPos, rectName);
-    builder->fsCodeAppendf("\t\tfloat threshold = %s + 2.0*%s;\n", cornerRadiusName, blurRadiusName );
-    builder->fsCodeAppendf("\t\tvec2 middle = %s.zw - %s.xy - 2.0*threshold;\n", rectName, rectName );
+    fsBuilder->codeAppendf("\t\tvec2 rectCenter = (%s.xy + %s.zw)/2.0;\n", rectName, rectName);
+    fsBuilder->codeAppendf("\t\tvec2 translatedFragPos = %s.xy - %s.xy;\n", fragmentPos, rectName);
+    fsBuilder->codeAppendf("\t\tfloat threshold = %s + 2.0*%s;\n", cornerRadiusName, blurRadiusName );
+    fsBuilder->codeAppendf("\t\tvec2 middle = %s.zw - %s.xy - 2.0*threshold;\n", rectName, rectName );
 
-    builder->fsCodeAppendf("\t\tif (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {\n" );
-    builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x = threshold;\n");
-    builder->fsCodeAppendf("\t\t} else if (translatedFragPos.x >= (middle.x + threshold)) {\n");
-    builder->fsCodeAppendf("\t\t\ttranslatedFragPos.x -= middle.x - 1.0;\n");
-    builder->fsCodeAppendf("\t\t}\n");
+    fsBuilder->codeAppendf("\t\tif (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) {\n" );
+    fsBuilder->codeAppendf("\t\t\ttranslatedFragPos.x = threshold;\n");
+    fsBuilder->codeAppendf("\t\t} else if (translatedFragPos.x >= (middle.x + threshold)) {\n");
+    fsBuilder->codeAppendf("\t\t\ttranslatedFragPos.x -= middle.x - 1.0;\n");
+    fsBuilder->codeAppendf("\t\t}\n");
 
-    builder->fsCodeAppendf("\t\tif (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {\n" );
-    builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y = threshold;\n");
-    builder->fsCodeAppendf("\t\t} else if (translatedFragPos.y >= (middle.y + threshold)) {\n");
-    builder->fsCodeAppendf("\t\t\ttranslatedFragPos.y -= middle.y - 1.0;\n");
-    builder->fsCodeAppendf("\t\t}\n");
+    fsBuilder->codeAppendf("\t\tif (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) {\n" );
+    fsBuilder->codeAppendf("\t\t\ttranslatedFragPos.y = threshold;\n");
+    fsBuilder->codeAppendf("\t\t} else if (translatedFragPos.y >= (middle.y + threshold)) {\n");
+    fsBuilder->codeAppendf("\t\t\ttranslatedFragPos.y -= middle.y - 1.0;\n");
+    fsBuilder->codeAppendf("\t\t}\n");
 
-    builder->fsCodeAppendf("\t\tvec2 proxyDims = vec2(2.0*threshold+1.0);\n");
-    builder->fsCodeAppendf("\t\tvec2 texCoord = translatedFragPos / proxyDims;\n");
+    fsBuilder->codeAppendf("\t\tvec2 proxyDims = vec2(2.0*threshold+1.0);\n");
+    fsBuilder->codeAppendf("\t\tvec2 texCoord = translatedFragPos / proxyDims;\n");
 
-    builder->fsCodeAppendf("\t%s = ", outputColor);
-    builder->fsAppendTextureLookupAndModulate(inputColor, samplers[0], "texCoord");
-    builder->fsCodeAppend(";\n");
+    fsBuilder->codeAppendf("\t%s = ", outputColor);
+    fsBuilder->appendTextureLookupAndModulate(inputColor, samplers[0], "texCoord");
+    fsBuilder->codeAppend(";\n");
 }
 
 void GrGLRRectBlurEffect::setData(const GrGLProgramDataManager& pdman,
diff --git a/src/effects/SkColorFilters.cpp b/src/effects/SkColorFilters.cpp
index bcaabf6..e825695 100644
--- a/src/effects/SkColorFilters.cpp
+++ b/src/effects/SkColorFilters.cpp
@@ -127,7 +127,7 @@
 #include "GrEffectUnitTest.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "SkGr.h"
 
 namespace {
@@ -222,7 +222,7 @@
             : INHERITED(factory) {
         }
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -234,7 +234,7 @@
             SkASSERT(SkXfermode::kDst_Mode != mode);
             const char* colorFilterColorUniName = NULL;
             if (drawEffect.castEffect<ModeColorFilterEffect>().willUseFilterColor()) {
-                fFilterColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+                fFilterColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                       kVec4f_GrSLType, "FilterColor",
                                                       &colorFilterColorUniName);
             }
@@ -242,7 +242,8 @@
             GrGLSLExpr4 filter =
                 color_filter_expression(mode, GrGLSLExpr4(colorFilterColorUniName), GrGLSLExpr4(inputColor));
 
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor, filter.c_str());
+            builder->getFragmentShaderBuilder()->
+                    codeAppendf("\t%s = %s;\n", outputColor, filter.c_str());
         }
 
         static void GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&,
diff --git a/src/effects/SkColorMatrixFilter.cpp b/src/effects/SkColorMatrixFilter.cpp
index f62e0f1..beed67e 100644
--- a/src/effects/SkColorMatrixFilter.cpp
+++ b/src/effects/SkColorMatrixFilter.cpp
@@ -335,7 +335,7 @@
 #include "GrEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 
 class ColorMatrixEffect : public GrEffect {
 public:
@@ -406,17 +406,17 @@
         : INHERITED(factory) {
         }
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLProgramBuilder* builder,
                               const GrDrawEffect&,
                               const GrEffectKey&,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray&,
                               const TextureSamplerArray&) SK_OVERRIDE {
-            fMatrixHandle = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+            fMatrixHandle = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                 kMat44f_GrSLType,
                                                 "ColorMatrix");
-            fVectorHandle = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+            fVectorHandle = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                 kVec4f_GrSLType,
                                                 "ColorMatrixVector");
 
@@ -424,16 +424,17 @@
                 // could optimize this case, but we aren't for now.
                 inputColor = "vec4(1)";
             }
+            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
             // The max() is to guard against 0 / 0 during unpremul when the incoming color is
             // transparent black.
-            builder->fsCodeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor);
-            builder->fsCodeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n",
+            fsBuilder->codeAppendf("\tfloat nonZeroAlpha = max(%s.a, 0.00001);\n", inputColor);
+            fsBuilder->codeAppendf("\t%s = %s * vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha) + %s;\n",
                                    outputColor,
                                    builder->getUniformCStr(fMatrixHandle),
                                    inputColor,
                                    builder->getUniformCStr(fVectorHandle));
-            builder->fsCodeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
-            builder->fsCodeAppendf("\t%s.rgb *= %s.a;\n", outputColor, outputColor);
+            fsBuilder->codeAppendf("\t%s = clamp(%s, 0.0, 1.0);\n", outputColor, outputColor);
+            fsBuilder->codeAppendf("\t%s.rgb *= %s.a;\n", outputColor, outputColor);
         }
 
         virtual void setData(const GrGLProgramDataManager& uniManager,
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index 27fc0d3..a1d29bf 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -14,7 +14,7 @@
 #include "GrContext.h"
 #include "GrCoordTransform.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrTBackendEffectFactory.h"
 #endif
 
@@ -302,7 +302,7 @@
                               const GrDrawEffect& drawEffect);
     virtual ~GrGLDisplacementMapEffect();
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -540,7 +540,7 @@
 GrGLDisplacementMapEffect::~GrGLDisplacementMapEffect() {
 }
 
-void GrGLDisplacementMapEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLDisplacementMapEffect::emitCode(GrGLProgramBuilder* builder,
                                          const GrDrawEffect&,
                                          const GrEffectKey& key,
                                          const char* outputColor,
@@ -549,7 +549,7 @@
                                          const TextureSamplerArray& samplers) {
     sk_ignore_unused_variable(inputColor);
 
-    fScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                     kVec2f_GrSLType, "Scale");
     const char* scaleUni = builder->getUniformCStr(fScaleUni);
     const char* dColor = "dColor";
@@ -559,29 +559,30 @@
                                    // a number smaller than that to approximate 0, but
                                    // leave room for 32-bit float GPU rounding errors.
 
-    builder->fsCodeAppendf("\t\tvec4 %s = ", dColor);
-    builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
-    builder->fsCodeAppend(";\n");
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->codeAppendf("\t\tvec4 %s = ", dColor);
+    fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
+    fsBuilder->codeAppend(";\n");
 
     // Unpremultiply the displacement
-    builder->fsCodeAppendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
+    fsBuilder->codeAppendf("\t\t%s.rgb = (%s.a < %s) ? vec3(0.0) : clamp(%s.rgb / %s.a, 0.0, 1.0);",
                            dColor, dColor, nearZero, dColor, dColor);
 
-    builder->fsCodeAppendf("\t\tvec2 %s = %s + %s*(%s.",
+    fsBuilder->codeAppendf("\t\tvec2 %s = %s + %s*(%s.",
                            cCoords, coords[1].c_str(), scaleUni, dColor);
 
     switch (fXChannelSelector) {
       case SkDisplacementMapEffect::kR_ChannelSelectorType:
-        builder->fsCodeAppend("r");
+        fsBuilder->codeAppend("r");
         break;
       case SkDisplacementMapEffect::kG_ChannelSelectorType:
-        builder->fsCodeAppend("g");
+        fsBuilder->codeAppend("g");
         break;
       case SkDisplacementMapEffect::kB_ChannelSelectorType:
-        builder->fsCodeAppend("b");
+        fsBuilder->codeAppend("b");
         break;
       case SkDisplacementMapEffect::kA_ChannelSelectorType:
-        builder->fsCodeAppend("a");
+        fsBuilder->codeAppend("a");
         break;
       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
       default:
@@ -590,31 +591,31 @@
 
     switch (fYChannelSelector) {
       case SkDisplacementMapEffect::kR_ChannelSelectorType:
-        builder->fsCodeAppend("r");
+        fsBuilder->codeAppend("r");
         break;
       case SkDisplacementMapEffect::kG_ChannelSelectorType:
-        builder->fsCodeAppend("g");
+        fsBuilder->codeAppend("g");
         break;
       case SkDisplacementMapEffect::kB_ChannelSelectorType:
-        builder->fsCodeAppend("b");
+        fsBuilder->codeAppend("b");
         break;
       case SkDisplacementMapEffect::kA_ChannelSelectorType:
-        builder->fsCodeAppend("a");
+        fsBuilder->codeAppend("a");
         break;
       case SkDisplacementMapEffect::kUnknown_ChannelSelectorType:
       default:
         SkDEBUGFAIL("Unknown Y channel selector");
     }
-    builder->fsCodeAppend("-vec2(0.5));\t\t");
+    fsBuilder->codeAppend("-vec2(0.5));\t\t");
 
     // FIXME : This can be achieved with a "clamp to border" texture repeat mode and
     //         a 0 border color instead of computing if cCoords is out of bounds here.
-    builder->fsCodeAppendf(
+    fsBuilder->codeAppendf(
         "bool %s = (%s.x < 0.0) || (%s.y < 0.0) || (%s.x > 1.0) || (%s.y > 1.0);\t\t",
         outOfBounds, cCoords, cCoords, cCoords, cCoords);
-    builder->fsCodeAppendf("%s = %s ? vec4(0.0) : ", outputColor, outOfBounds);
-    builder->fsAppendTextureLookup(samplers[1], cCoords, coords[1].type());
-    builder->fsCodeAppend(";\n");
+    fsBuilder->codeAppendf("%s = %s ? vec4(0.0) : ", outputColor, outOfBounds);
+    fsBuilder->appendTextureLookup(samplers[1], cCoords, coords[1].type());
+    fsBuilder->codeAppend(";\n");
 }
 
 void GrGLDisplacementMapEffect::setData(const GrGLProgramDataManager& pdman,
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index d93f4cc..c3834c6 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -17,7 +17,7 @@
 #if SK_SUPPORT_GPU
 #include "effects/GrSingleTextureEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrEffect.h"
 #include "GrTBackendEffectFactory.h"
 
@@ -432,7 +432,7 @@
      * This is called by GrGLLightingEffect::emitCode() before either of the two virtual functions
      * below. It adds a vec3f uniform visible in the FS that represents the constant light color.
      */
-    void emitLightColorUniform(GrGLShaderBuilder*);
+    void emitLightColorUniform(GrGLProgramBuilder*);
 
     /**
      * These two functions are called from GrGLLightingEffect's emitCode() function.
@@ -442,8 +442,8 @@
      * the FS. The default of emitLightColor appends the name of the constant light color uniform
      * and so this function only needs to be overridden if the light color varies spatially.
      */
-    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) = 0;
-    virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight);
+    virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) = 0;
+    virtual void emitLightColor(GrGLProgramBuilder*, const char *surfaceToLight);
 
     // This is called from GrGLLightingEffect's setData(). Subclasses of GrGLLight must call
     // INHERITED::setData().
@@ -470,7 +470,7 @@
     virtual ~GrGLDistantLight() {}
     virtual void setData(const GrGLProgramDataManager&,
                          const SkLight* light) const SK_OVERRIDE;
-    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
+    virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
 
 private:
     typedef GrGLLight INHERITED;
@@ -484,7 +484,7 @@
     virtual ~GrGLPointLight() {}
     virtual void setData(const GrGLProgramDataManager&,
                          const SkLight* light) const SK_OVERRIDE;
-    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
+    virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
 
 private:
     typedef GrGLLight INHERITED;
@@ -498,8 +498,8 @@
     virtual ~GrGLSpotLight() {}
     virtual void setData(const GrGLProgramDataManager&,
                          const SkLight* light) const SK_OVERRIDE;
-    virtual void emitSurfaceToLight(GrGLShaderBuilder*, const char* z) SK_OVERRIDE;
-    virtual void emitLightColor(GrGLShaderBuilder*, const char *surfaceToLight) SK_OVERRIDE;
+    virtual void emitSurfaceToLight(GrGLProgramBuilder*, const char* z) SK_OVERRIDE;
+    virtual void emitLightColor(GrGLProgramBuilder*, const char *surfaceToLight) SK_OVERRIDE;
 
 private:
     typedef GrGLLight INHERITED;
@@ -1206,7 +1206,7 @@
                        const GrDrawEffect& effect);
     virtual ~GrGLLightingEffect();
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -1222,7 +1222,7 @@
     virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 protected:
-    virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) = 0;
+    virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) = 0;
 
 private:
     typedef GrGLEffect INHERITED;
@@ -1238,7 +1238,7 @@
 public:
     GrGLDiffuseLightingEffect(const GrBackendEffectFactory& factory,
                               const GrDrawEffect& drawEffect);
-    virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
+    virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) SK_OVERRIDE;
     virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 private:
@@ -1253,7 +1253,7 @@
 public:
     GrGLSpecularLightingEffect(const GrBackendEffectFactory& factory,
                                const GrDrawEffect& effect);
-    virtual void emitLightFunc(GrGLShaderBuilder*, SkString* funcName) SK_OVERRIDE;
+    virtual void emitLightFunc(GrGLProgramBuilder*, SkString* funcName) SK_OVERRIDE;
     virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
 
 private:
@@ -1341,19 +1341,17 @@
     delete fLight;
 }
 
-void GrGLLightingEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLLightingEffect::emitCode(GrGLProgramBuilder* builder,
                                   const GrDrawEffect&,
                                   const GrEffectKey& key,
                                   const char* outputColor,
                                   const char* inputColor,
                                   const TransformedCoordsArray& coords,
                                   const TextureSamplerArray& samplers) {
-    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
-
-    fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                               kVec2f_GrSLType,
                                              "ImageIncrement");
-    fSurfaceScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fSurfaceScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                            kFloat_GrSLType,
                                            "SurfaceScale");
     fLight->emitLightColorUniform(builder);
@@ -1369,7 +1367,10 @@
         GrGLShaderVar("scale", kFloat_GrSLType),
     };
     SkString sobelFuncName;
-    builder->fsEmitFunction(kFloat_GrSLType,
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
+
+    fsBuilder->emitFunction(kFloat_GrSLType,
                             "sobel",
                             SK_ARRAY_COUNT(gSobelArgs),
                             gSobelArgs,
@@ -1381,7 +1382,7 @@
         GrGLShaderVar("scale", kFloat_GrSLType),
     };
     SkString pointToNormalName;
-    builder->fsEmitFunction(kVec3f_GrSLType,
+    fsBuilder->emitFunction(kVec3f_GrSLType,
                             "pointToNormal",
                             SK_ARRAY_COUNT(gPointToNormalArgs),
                             gPointToNormalArgs,
@@ -1400,15 +1401,15 @@
                                 sobelFuncName.c_str(),
                                 sobelFuncName.c_str());
     SkString interiorNormalName;
-    builder->fsEmitFunction(kVec3f_GrSLType,
+    fsBuilder->emitFunction(kVec3f_GrSLType,
                             "interiorNormal",
                             SK_ARRAY_COUNT(gInteriorNormalArgs),
                             gInteriorNormalArgs,
                             interiorNormalBody.c_str(),
                             &interiorNormalName);
 
-    builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
-    builder->fsCodeAppend("\t\tfloat m[9];\n");
+    fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
+    fsBuilder->codeAppend("\t\tfloat m[9];\n");
 
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
     const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
@@ -1418,23 +1419,23 @@
         for (int dx = -1; dx <= 1; dx++) {
             SkString texCoords;
             texCoords.appendf("coord + vec2(%d, %d) * %s", dx, dy, imgInc);
-            builder->fsCodeAppendf("\t\tm[%d] = ", index++);
-            builder->fsAppendTextureLookup(samplers[0], texCoords.c_str());
-            builder->fsCodeAppend(".a;\n");
+            fsBuilder->codeAppendf("\t\tm[%d] = ", index++);
+            fsBuilder->appendTextureLookup(samplers[0], texCoords.c_str());
+            fsBuilder->codeAppend(".a;\n");
         }
     }
-    builder->fsCodeAppend("\t\tvec3 surfaceToLight = ");
+    fsBuilder->codeAppend("\t\tvec3 surfaceToLight = ");
     SkString arg;
     arg.appendf("%s * m[4]", surfScale);
     fLight->emitSurfaceToLight(builder, arg.c_str());
-    builder->fsCodeAppend(";\n");
-    builder->fsCodeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
+    fsBuilder->codeAppend(";\n");
+    fsBuilder->codeAppendf("\t\t%s = %s(%s(m, %s), surfaceToLight, ",
                            outputColor, lightFunc.c_str(), interiorNormalName.c_str(), surfScale);
     fLight->emitLightColor(builder, "surfaceToLight");
-    builder->fsCodeAppend(");\n");
+    fsBuilder->codeAppend(");\n");
     SkString modulate;
     GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
-    builder->fsCodeAppend(modulate.c_str());
+    fsBuilder->codeAppend(modulate.c_str());
 }
 
 void GrGLLightingEffect::GenKey(const GrDrawEffect& drawEffect,
@@ -1462,9 +1463,9 @@
     : INHERITED(factory, drawEffect) {
 }
 
-void GrGLDiffuseLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
+void GrGLDiffuseLightingEffect::emitLightFunc(GrGLProgramBuilder* builder, SkString* funcName) {
     const char* kd;
-    fKDUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fKDUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                  kFloat_GrSLType,
                                  "KD",
                                  &kd);
@@ -1477,12 +1478,12 @@
     SkString lightBody;
     lightBody.appendf("\tfloat colorScale = %s * dot(normal, surfaceToLight);\n", kd);
     lightBody.appendf("\treturn vec4(lightColor * clamp(colorScale, 0.0, 1.0), 1.0);\n");
-    builder->fsEmitFunction(kVec4f_GrSLType,
-                            "light",
-                            SK_ARRAY_COUNT(gLightArgs),
-                            gLightArgs,
-                            lightBody.c_str(),
-                            funcName);
+    builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
+                                                      "light",
+                                                      SK_ARRAY_COUNT(gLightArgs),
+                                                      gLightArgs,
+                                                      lightBody.c_str(),
+                                                      funcName);
 }
 
 void GrGLDiffuseLightingEffect::setData(const GrGLProgramDataManager& pdman,
@@ -1541,13 +1542,13 @@
     : INHERITED(factory, drawEffect) {
 }
 
-void GrGLSpecularLightingEffect::emitLightFunc(GrGLShaderBuilder* builder, SkString* funcName) {
+void GrGLSpecularLightingEffect::emitLightFunc(GrGLProgramBuilder* builder, SkString* funcName) {
     const char* ks;
     const char* shininess;
 
-    fKSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fKSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                  kFloat_GrSLType, "KS", &ks);
-    fShininessUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fShininessUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                         kFloat_GrSLType, "Shininess", &shininess);
 
     static const GrGLShaderVar gLightArgs[] = {
@@ -1560,12 +1561,12 @@
     lightBody.appendf("\tfloat colorScale = %s * pow(dot(normal, halfDir), %s);\n", ks, shininess);
     lightBody.appendf("\tvec3 color = lightColor * clamp(colorScale, 0.0, 1.0);\n");
     lightBody.appendf("\treturn vec4(color, max(max(color.r, color.g), color.b));\n");
-    builder->fsEmitFunction(kVec4f_GrSLType,
-                            "light",
-                            SK_ARRAY_COUNT(gLightArgs),
-                            gLightArgs,
-                            lightBody.c_str(),
-                            funcName);
+    builder->getFragmentShaderBuilder()->emitFunction(kVec4f_GrSLType,
+                                                      "light",
+                                                      SK_ARRAY_COUNT(gLightArgs),
+                                                      gLightArgs,
+                                                      lightBody.c_str(),
+                                                      funcName);
 }
 
 void GrGLSpecularLightingEffect::setData(const GrGLProgramDataManager& pdman,
@@ -1577,14 +1578,15 @@
 }
 
 ///////////////////////////////////////////////////////////////////////////////
-void GrGLLight::emitLightColorUniform(GrGLShaderBuilder* builder) {
-    fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+void GrGLLight::emitLightColorUniform(GrGLProgramBuilder* builder) {
+    fColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                     kVec3f_GrSLType, "LightColor");
 }
 
-void GrGLLight::emitLightColor(GrGLShaderBuilder* builder,
+void GrGLLight::emitLightColor(GrGLProgramBuilder* builder,
                                const char *surfaceToLight) {
-    builder->fsCodeAppend(builder->getUniformCStr(this->lightColorUni()));
+    builder->getFragmentShaderBuilder()->
+            codeAppend(builder->getUniformCStr(this->lightColorUni()));
 }
 
 void GrGLLight::setData(const GrGLProgramDataManager& pdman,
@@ -1602,11 +1604,11 @@
     setUniformNormal3(pdman, fDirectionUni, distantLight->direction());
 }
 
-void GrGLDistantLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
+void GrGLDistantLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
     const char* dir;
-    fDirectionUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
+    fDirectionUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
                                         "LightDirection", &dir);
-    builder->fsCodeAppend(dir);
+    builder->getFragmentShaderBuilder()->codeAppend(dir);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1619,11 +1621,13 @@
     setUniformPoint3(pdman, fLocationUni, pointLight->location());
 }
 
-void GrGLPointLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
+void GrGLPointLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
     const char* loc;
-    fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec3f_GrSLType,
+    fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec3f_GrSLType,
                                        "LightLocation", &loc);
-    builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))", loc, builder->fragmentPosition(), z);
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
+            loc, fsBuilder->fragmentPosition(), z);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1641,15 +1645,17 @@
     setUniformNormal3(pdman, fSUni, spotLight->s());
 }
 
-void GrGLSpotLight::emitSurfaceToLight(GrGLShaderBuilder* builder, const char* z) {
+void GrGLSpotLight::emitSurfaceToLight(GrGLProgramBuilder* builder, const char* z) {
     const char* location;
-    fLocationUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fLocationUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                        kVec3f_GrSLType, "LightLocation", &location);
-    builder->fsCodeAppendf("normalize(%s - vec3(%s.xy, %s))",
-                           location, builder->fragmentPosition(), z);
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->codeAppendf("normalize(%s - vec3(%s.xy, %s))",
+            location, fsBuilder->fragmentPosition(), z);
 }
 
-void GrGLSpotLight::emitLightColor(GrGLShaderBuilder* builder,
+void GrGLSpotLight::emitLightColor(GrGLProgramBuilder* builder,
                                    const char *surfaceToLight) {
 
     const char* color = builder->getUniformCStr(this->lightColorUni()); // created by parent class.
@@ -1659,15 +1665,15 @@
     const char* cosOuter;
     const char* coneScale;
     const char* s;
-    fExponentUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fExponentUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                        kFloat_GrSLType, "Exponent", &exponent);
-    fCosInnerConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fCosInnerConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                 kFloat_GrSLType, "CosInnerConeAngle", &cosInner);
-    fCosOuterConeAngleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fCosOuterConeAngleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                 kFloat_GrSLType, "CosOuterConeAngle", &cosOuter);
-    fConeScaleUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fConeScaleUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                         kFloat_GrSLType, "ConeScale", &coneScale);
-    fSUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fSUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                 kVec3f_GrSLType, "S", &s);
 
     static const GrGLShaderVar gLightColorArgs[] = {
@@ -1684,14 +1690,15 @@
                            color, cosOuter, coneScale);
     lightColorBody.appendf("\t}\n");
     lightColorBody.appendf("\treturn %s;\n", color);
-    builder->fsEmitFunction(kVec3f_GrSLType,
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->emitFunction(kVec3f_GrSLType,
                             "lightColor",
                             SK_ARRAY_COUNT(gLightColorArgs),
                             gLightColorArgs,
                             lightColorBody.c_str(),
                             &fLightColorFunc);
 
-    builder->fsCodeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
+    fsBuilder->codeAppendf("%s(%s)", fLightColorFunc.c_str(), surfaceToLight);
 }
 
 #endif
diff --git a/src/effects/SkLumaColorFilter.cpp b/src/effects/SkLumaColorFilter.cpp
index 26621bb..c1ce05c 100644
--- a/src/effects/SkLumaColorFilter.cpp
+++ b/src/effects/SkLumaColorFilter.cpp
@@ -12,7 +12,7 @@
 
 #if SK_SUPPORT_GPU
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrContext.h"
 #include "GrTBackendEffectFactory.h"
 #endif
@@ -89,7 +89,7 @@
 
         static void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder* b) {}
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLProgramBuilder* builder,
                               const GrDrawEffect&,
                               const GrEffectKey&,
                               const char* outputColor,
@@ -100,12 +100,13 @@
                 inputColor = "vec4(1)";
             }
 
-            builder->fsCodeAppendf("\tfloat luma = dot(vec3(%f, %f, %f), %s.rgb);\n",
+            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+            fsBuilder->codeAppendf("\tfloat luma = dot(vec3(%f, %f, %f), %s.rgb);\n",
                                    SK_ITU_BT709_LUM_COEFF_R,
                                    SK_ITU_BT709_LUM_COEFF_G,
                                    SK_ITU_BT709_LUM_COEFF_B,
                                    inputColor);
-            builder->fsCodeAppendf("\t%s = vec4(0, 0, 0, luma);\n",
+            fsBuilder->codeAppendf("\t%s = vec4(0, 0, 0, luma);\n",
                                    outputColor);
 
         }
diff --git a/src/effects/SkMagnifierImageFilter.cpp b/src/effects/SkMagnifierImageFilter.cpp
index cb0fc24..bf6f4a7 100644
--- a/src/effects/SkMagnifierImageFilter.cpp
+++ b/src/effects/SkMagnifierImageFilter.cpp
@@ -16,7 +16,7 @@
 #if SK_SUPPORT_GPU
 #include "effects/GrSingleTextureEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "GrTBackendEffectFactory.h"
@@ -95,7 +95,7 @@
 public:
     GrGLMagnifierEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -117,57 +117,58 @@
     : INHERITED(factory) {
 }
 
-void GrGLMagnifierEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLMagnifierEffect::emitCode(GrGLProgramBuilder* builder,
                                    const GrDrawEffect&,
                                    const GrEffectKey& key,
                                    const char* outputColor,
                                    const char* inputColor,
                                    const TransformedCoordsArray& coords,
                                    const TextureSamplerArray& samplers) {
-    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
     fOffsetVar = builder->addUniform(
-        GrGLShaderBuilder::kFragment_Visibility |
-        GrGLShaderBuilder::kVertex_Visibility,
+        GrGLProgramBuilder::kFragment_Visibility |
+        GrGLProgramBuilder::kVertex_Visibility,
         kVec2f_GrSLType, "Offset");
     fInvZoomVar = builder->addUniform(
-        GrGLShaderBuilder::kFragment_Visibility |
-        GrGLShaderBuilder::kVertex_Visibility,
+        GrGLProgramBuilder::kFragment_Visibility |
+        GrGLProgramBuilder::kVertex_Visibility,
         kVec2f_GrSLType, "InvZoom");
     fInvInsetVar = builder->addUniform(
-        GrGLShaderBuilder::kFragment_Visibility |
-        GrGLShaderBuilder::kVertex_Visibility,
+        GrGLProgramBuilder::kFragment_Visibility |
+        GrGLProgramBuilder::kVertex_Visibility,
         kVec2f_GrSLType, "InvInset");
 
-    builder->fsCodeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
-    builder->fsCodeAppendf("\t\tvec2 zoom_coord = %s + %s * %s;\n",
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
+    fsBuilder->codeAppendf("\t\tvec2 coord = %s;\n", coords2D.c_str());
+    fsBuilder->codeAppendf("\t\tvec2 zoom_coord = %s + %s * %s;\n",
                            builder->getUniformCStr(fOffsetVar),
                            coords2D.c_str(),
                            builder->getUniformCStr(fInvZoomVar));
 
-    builder->fsCodeAppend("\t\tvec2 delta = min(coord, vec2(1.0, 1.0) - coord);\n");
+    fsBuilder->codeAppend("\t\tvec2 delta = min(coord, vec2(1.0, 1.0) - coord);\n");
 
-    builder->fsCodeAppendf("\t\tdelta = delta * %s;\n", builder->getUniformCStr(fInvInsetVar));
+    fsBuilder->codeAppendf("\t\tdelta = delta * %s;\n", builder->getUniformCStr(fInvInsetVar));
 
-    builder->fsCodeAppend("\t\tfloat weight = 0.0;\n");
-    builder->fsCodeAppend("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n");
-    builder->fsCodeAppend("\t\t\tdelta = vec2(2.0, 2.0) - delta;\n");
-    builder->fsCodeAppend("\t\t\tfloat dist = length(delta);\n");
-    builder->fsCodeAppend("\t\t\tdist = max(2.0 - dist, 0.0);\n");
-    builder->fsCodeAppend("\t\t\tweight = min(dist * dist, 1.0);\n");
-    builder->fsCodeAppend("\t\t} else {\n");
-    builder->fsCodeAppend("\t\t\tvec2 delta_squared = delta * delta;\n");
-    builder->fsCodeAppend("\t\t\tweight = min(min(delta_squared.x, delta_squared.y), 1.0);\n");
-    builder->fsCodeAppend("\t\t}\n");
+    fsBuilder->codeAppend("\t\tfloat weight = 0.0;\n");
+    fsBuilder->codeAppend("\t\tif (delta.s < 2.0 && delta.t < 2.0) {\n");
+    fsBuilder->codeAppend("\t\t\tdelta = vec2(2.0, 2.0) - delta;\n");
+    fsBuilder->codeAppend("\t\t\tfloat dist = length(delta);\n");
+    fsBuilder->codeAppend("\t\t\tdist = max(2.0 - dist, 0.0);\n");
+    fsBuilder->codeAppend("\t\t\tweight = min(dist * dist, 1.0);\n");
+    fsBuilder->codeAppend("\t\t} else {\n");
+    fsBuilder->codeAppend("\t\t\tvec2 delta_squared = delta * delta;\n");
+    fsBuilder->codeAppend("\t\t\tweight = min(min(delta_squared.x, delta_squared.y), 1.0);\n");
+    fsBuilder->codeAppend("\t\t}\n");
 
-    builder->fsCodeAppend("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n");
-    builder->fsCodeAppend("\t\tvec4 output_color = ");
-    builder->fsAppendTextureLookup(samplers[0], "mix_coord");
-    builder->fsCodeAppend(";\n");
+    fsBuilder->codeAppend("\t\tvec2 mix_coord = mix(coord, zoom_coord, weight);\n");
+    fsBuilder->codeAppend("\t\tvec4 output_color = ");
+    fsBuilder->appendTextureLookup(samplers[0], "mix_coord");
+    fsBuilder->codeAppend(";\n");
 
-    builder->fsCodeAppendf("\t\t%s = output_color;", outputColor);
+    fsBuilder->codeAppendf("\t\t%s = output_color;", outputColor);
     SkString modulate;
     GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
-    builder->fsCodeAppend(modulate.c_str());
+    fsBuilder->codeAppend(modulate.c_str());
 }
 
 void GrGLMagnifierEffect::setData(const GrGLProgramDataManager& pdman,
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index bb8478c..eef2a7d 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -17,7 +17,7 @@
 #include "GrTexture.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "effects/Gr1DKernelEffect.h"
 #endif
 
@@ -329,7 +329,7 @@
 public:
     GrGLMorphologyEffect (const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -359,25 +359,26 @@
     fType = m.type();
 }
 
-void GrGLMorphologyEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLMorphologyEffect::emitCode(GrGLProgramBuilder* builder,
                                     const GrDrawEffect&,
                                     const GrEffectKey& key,
                                     const char* outputColor,
                                     const char* inputColor,
                                     const TransformedCoordsArray& coords,
                                     const TextureSamplerArray& samplers) {
-    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
-    fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec2f_GrSLType, "ImageIncrement");
 
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
     const char* func;
     switch (fType) {
         case GrMorphologyEffect::kErode_MorphologyType:
-            builder->fsCodeAppendf("\t\t%s = vec4(1, 1, 1, 1);\n", outputColor);
+            fsBuilder->codeAppendf("\t\t%s = vec4(1, 1, 1, 1);\n", outputColor);
             func = "min";
             break;
         case GrMorphologyEffect::kDilate_MorphologyType:
-            builder->fsCodeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
+            fsBuilder->codeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
             func = "max";
             break;
         default:
@@ -387,16 +388,16 @@
     }
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
 
-    builder->fsCodeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str(), fRadius, imgInc);
-    builder->fsCodeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
-    builder->fsCodeAppendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
-    builder->fsAppendTextureLookup(samplers[0], "coord");
-    builder->fsCodeAppend(");\n");
-    builder->fsCodeAppendf("\t\t\tcoord += %s;\n", imgInc);
-    builder->fsCodeAppend("\t\t}\n");
+    fsBuilder->codeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str(), fRadius, imgInc);
+    fsBuilder->codeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", this->width());
+    fsBuilder->codeAppendf("\t\t\t%s = %s(%s, ", outputColor, func, outputColor);
+    fsBuilder->appendTextureLookup(samplers[0], "coord");
+    fsBuilder->codeAppend(");\n");
+    fsBuilder->codeAppendf("\t\t\tcoord += %s;\n", imgInc);
+    fsBuilder->codeAppend("\t\t}\n");
     SkString modulate;
     GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
-    builder->fsCodeAppend(modulate.c_str());
+    fsBuilder->codeAppend(modulate.c_str());
 }
 
 void GrGLMorphologyEffect::GenKey(const GrDrawEffect& drawEffect,
diff --git a/src/effects/SkPerlinNoiseShader.cpp b/src/effects/SkPerlinNoiseShader.cpp
index 427b451..b0ebb39 100644
--- a/src/effects/SkPerlinNoiseShader.cpp
+++ b/src/effects/SkPerlinNoiseShader.cpp
@@ -18,7 +18,7 @@
 #include "GrContext.h"
 #include "GrCoordTransform.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrTBackendEffectFactory.h"
 #include "SkGr.h"
 #endif
@@ -515,7 +515,7 @@
                     const GrDrawEffect& drawEffect);
     virtual ~GrGLPerlinNoise() {}
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -663,7 +663,7 @@
   , fNumOctaves(drawEffect.castEffect<GrPerlinNoiseEffect>().numOctaves()) {
 }
 
-void GrGLPerlinNoise::emitCode(GrGLShaderBuilder* builder,
+void GrGLPerlinNoise::emitCode(GrGLProgramBuilder* builder,
                                const GrDrawEffect&,
                                const GrEffectKey& key,
                                const char* outputColor,
@@ -672,18 +672,19 @@
                                const TextureSamplerArray& samplers) {
     sk_ignore_unused_variable(inputColor);
 
-    SkString vCoords = builder->ensureFSCoords2D(coords, 0);
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString vCoords = fsBuilder->ensureFSCoords2D(coords, 0);
 
-    fBaseFrequencyUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fBaseFrequencyUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                             kVec2f_GrSLType, "baseFrequency");
     const char* baseFrequencyUni = builder->getUniformCStr(fBaseFrequencyUni);
-    fAlphaUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fAlphaUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                     kFloat_GrSLType, "alpha");
     const char* alphaUni = builder->getUniformCStr(fAlphaUni);
 
     const char* stitchDataUni = NULL;
     if (fStitchTiles) {
-        fStitchDataUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fStitchDataUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec2f_GrSLType, "stitchData");
         stitchDataUni = builder->getUniformCStr(fStitchDataUni);
     }
@@ -755,7 +756,7 @@
         xCoords.appendf("vec2(%s.x, 0.5)", floorVal);
 
         noiseCode.appendf("\n\tvec2 %s;\n\t%s.x = ", latticeIdx, latticeIdx);
-        builder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType);
+        fsBuilder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType);
         noiseCode.append(".r;");
     }
 
@@ -765,7 +766,7 @@
         xCoords.appendf("vec2(%s.z, 0.5)", floorVal);
 
         noiseCode.appendf("\n\t%s.y = ", latticeIdx);
-        builder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType);
+        fsBuilder->appendTextureLookup(&noiseCode, samplers[0], xCoords.c_str(), kVec2f_GrSLType);
         noiseCode.append(".r;");
     }
 
@@ -789,7 +790,7 @@
         SkString latticeCoords("");
         latticeCoords.appendf("vec2(%s.x, %s)", bcoords, chanCoord);
         noiseCode.appendf("\n\tvec4 %s = ", lattice);
-        builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
+        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
             kVec2f_GrSLType);
         noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
         noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
@@ -801,7 +802,7 @@
         SkString latticeCoords("");
         latticeCoords.appendf("vec2(%s.y, %s)", bcoords, chanCoord);
         noiseCode.append("\n\tlattice = ");
-        builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
+        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
             kVec2f_GrSLType);
         noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
         noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
@@ -817,7 +818,7 @@
         SkString latticeCoords("");
         latticeCoords.appendf("vec2(%s.w, %s)", bcoords, chanCoord);
         noiseCode.append("\n\tlattice = ");
-        builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
+        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
             kVec2f_GrSLType);
         noiseCode.appendf(".bgra;\n\t%s.y = ", uv);
         noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
@@ -829,7 +830,7 @@
         SkString latticeCoords("");
         latticeCoords.appendf("vec2(%s.z, %s)", bcoords, chanCoord);
         noiseCode.append("\n\tlattice = ");
-        builder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
+        fsBuilder->appendTextureLookup(&noiseCode, samplers[1], latticeCoords.c_str(),
             kVec2f_GrSLType);
         noiseCode.appendf(".bgra;\n\t%s.x = ", uv);
         noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal);
@@ -842,38 +843,38 @@
 
     SkString noiseFuncName;
     if (fStitchTiles) {
-        builder->fsEmitFunction(kFloat_GrSLType,
+        fsBuilder->emitFunction(kFloat_GrSLType,
                                 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseStitchArgs),
                                 gPerlinNoiseStitchArgs, noiseCode.c_str(), &noiseFuncName);
     } else {
-        builder->fsEmitFunction(kFloat_GrSLType,
+        fsBuilder->emitFunction(kFloat_GrSLType,
                                 "perlinnoise", SK_ARRAY_COUNT(gPerlinNoiseArgs),
                                 gPerlinNoiseArgs, noiseCode.c_str(), &noiseFuncName);
     }
 
     // There are rounding errors if the floor operation is not performed here
-    builder->fsCodeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;",
+    fsBuilder->codeAppendf("\n\t\tvec2 %s = floor(%s.xy) * %s;",
                            noiseVec, vCoords.c_str(), baseFrequencyUni);
 
     // Clear the color accumulator
-    builder->fsCodeAppendf("\n\t\t%s = vec4(0.0);", outputColor);
+    fsBuilder->codeAppendf("\n\t\t%s = vec4(0.0);", outputColor);
 
     if (fStitchTiles) {
         // Set up TurbulenceInitial stitch values.
-        builder->fsCodeAppendf("\n\t\tvec2 %s = %s;", stitchData, stitchDataUni);
+        fsBuilder->codeAppendf("\n\t\tvec2 %s = %s;", stitchData, stitchDataUni);
     }
 
-    builder->fsCodeAppendf("\n\t\tfloat %s = 1.0;", ratio);
+    fsBuilder->codeAppendf("\n\t\tfloat %s = 1.0;", ratio);
 
     // Loop over all octaves
-    builder->fsCodeAppendf("\n\t\tfor (int octave = 0; octave < %d; ++octave) {", fNumOctaves);
+    fsBuilder->codeAppendf("\n\t\tfor (int octave = 0; octave < %d; ++octave) {", fNumOctaves);
 
-    builder->fsCodeAppendf("\n\t\t\t%s += ", outputColor);
+    fsBuilder->codeAppendf("\n\t\t\t%s += ", outputColor);
     if (fType != SkPerlinNoiseShader::kFractalNoise_Type) {
-        builder->fsCodeAppend("abs(");
+        fsBuilder->codeAppend("abs(");
     }
     if (fStitchTiles) {
-        builder->fsCodeAppendf(
+        fsBuilder->codeAppendf(
             "vec4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s),"
                  "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))",
             noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData,
@@ -881,7 +882,7 @@
             noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData,
             noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData);
     } else {
-        builder->fsCodeAppendf(
+        fsBuilder->codeAppendf(
             "vec4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s),"
                  "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))",
             noiseFuncName.c_str(), chanCoordR, noiseVec,
@@ -890,31 +891,31 @@
             noiseFuncName.c_str(), chanCoordA, noiseVec);
     }
     if (fType != SkPerlinNoiseShader::kFractalNoise_Type) {
-        builder->fsCodeAppendf(")"); // end of "abs("
+        fsBuilder->codeAppendf(")"); // end of "abs("
     }
-    builder->fsCodeAppendf(" * %s;", ratio);
+    fsBuilder->codeAppendf(" * %s;", ratio);
 
-    builder->fsCodeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec);
-    builder->fsCodeAppendf("\n\t\t\t%s *= 0.5;", ratio);
+    fsBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", noiseVec);
+    fsBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio);
 
     if (fStitchTiles) {
-        builder->fsCodeAppendf("\n\t\t\t%s *= vec2(2.0);", stitchData);
+        fsBuilder->codeAppendf("\n\t\t\t%s *= vec2(2.0);", stitchData);
     }
-    builder->fsCodeAppend("\n\t\t}"); // end of the for loop on octaves
+    fsBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves
 
     if (fType == SkPerlinNoiseShader::kFractalNoise_Type) {
         // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2
         // by fractalNoise and (turbulenceFunctionResult) by turbulence.
-        builder->fsCodeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);", outputColor, outputColor);
+        fsBuilder->codeAppendf("\n\t\t%s = %s * vec4(0.5) + vec4(0.5);", outputColor, outputColor);
     }
 
-    builder->fsCodeAppendf("\n\t\t%s.a *= %s;", outputColor, alphaUni);
+    fsBuilder->codeAppendf("\n\t\t%s.a *= %s;", outputColor, alphaUni);
 
     // Clamp values
-    builder->fsCodeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", outputColor, outputColor);
+    fsBuilder->codeAppendf("\n\t\t%s = clamp(%s, 0.0, 1.0);", outputColor, outputColor);
 
     // Pre-multiply the result
-    builder->fsCodeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n",
+    fsBuilder->codeAppendf("\n\t\t%s = vec4(%s.rgb * %s.aaa, %s.a);\n",
                   outputColor, outputColor, outputColor, outputColor);
 }
 
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index 54e1efe..8b391ee 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -278,7 +278,7 @@
 #include "GrEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "SkGr.h"
 
 class GLColorTableEffect;
@@ -316,7 +316,7 @@
 public:
     GLColorTableEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -337,7 +337,7 @@
     : INHERITED(factory) {
  }
 
-void GLColorTableEffect::emitCode(GrGLShaderBuilder* builder,
+void GLColorTableEffect::emitCode(GrGLProgramBuilder* builder,
                                   const GrDrawEffect&,
                                   const GrEffectKey&,
                                   const char* outputColor,
@@ -347,38 +347,39 @@
 
     static const float kColorScaleFactor = 255.0f / 256.0f;
     static const float kColorOffsetFactor = 1.0f / 512.0f;
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     if (NULL == inputColor) {
         // the input color is solid white (all ones).
         static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
-        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
+        fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
                                kMaxValue, kMaxValue, kMaxValue, kMaxValue);
 
     } else {
-        builder->fsCodeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
-        builder->fsCodeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
-        builder->fsCodeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
+        fsBuilder->codeAppendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
+        fsBuilder->codeAppendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
+        fsBuilder->codeAppendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
                               kColorScaleFactor,
                               kColorOffsetFactor, kColorOffsetFactor,
                               kColorOffsetFactor, kColorOffsetFactor);
     }
 
-    builder->fsCodeAppendf("\t\t%s.a = ", outputColor);
-    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.a, 0.125)");
-    builder->fsCodeAppend(";\n");
+    fsBuilder->codeAppendf("\t\t%s.a = ", outputColor);
+    fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.a, 0.125)");
+    fsBuilder->codeAppend(";\n");
 
-    builder->fsCodeAppendf("\t\t%s.r = ", outputColor);
-    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.r, 0.375)");
-    builder->fsCodeAppend(";\n");
+    fsBuilder->codeAppendf("\t\t%s.r = ", outputColor);
+    fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.r, 0.375)");
+    fsBuilder->codeAppend(";\n");
 
-    builder->fsCodeAppendf("\t\t%s.g = ", outputColor);
-    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.g, 0.625)");
-    builder->fsCodeAppend(";\n");
+    fsBuilder->codeAppendf("\t\t%s.g = ", outputColor);
+    fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.g, 0.625)");
+    fsBuilder->codeAppend(";\n");
 
-    builder->fsCodeAppendf("\t\t%s.b = ", outputColor);
-    builder->fsAppendTextureLookup(samplers[0], "vec2(coord.b, 0.875)");
-    builder->fsCodeAppend(";\n");
+    fsBuilder->codeAppendf("\t\t%s.b = ", outputColor);
+    fsBuilder->appendTextureLookup(samplers[0], "vec2(coord.b, 0.875)");
+    fsBuilder->codeAppend(";\n");
 
-    builder->fsCodeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
+    fsBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp
index b14a3f7..4f60cfe 100644
--- a/src/effects/gradients/SkGradientShader.cpp
+++ b/src/effects/gradients/SkGradientShader.cpp
@@ -927,7 +927,7 @@
 
 #include "effects/GrTextureStripAtlas.h"
 #include "GrTBackendEffectFactory.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "SkGr.h"
 
 GrGLGradientEffect::GrGLGradientEffect(const GrBackendEffectFactory& factory)
@@ -937,24 +937,24 @@
 
 GrGLGradientEffect::~GrGLGradientEffect() { }
 
-void GrGLGradientEffect::emitUniforms(GrGLShaderBuilder* builder, uint32_t baseKey) {
+void GrGLGradientEffect::emitUniforms(GrGLProgramBuilder* builder, uint32_t baseKey) {
 
     if (SkGradientShaderBase::kTwo_GpuColorType == ColorTypeFromKey(baseKey)) { // 2 Color case
-        fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fColorStartUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec4f_GrSLType, "GradientStartColor");
-        fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fColorEndUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                            kVec4f_GrSLType, "GradientEndColor");
 
     } else if (SkGradientShaderBase::kThree_GpuColorType == ColorTypeFromKey(baseKey)){ // 3 Color Case
-        fColorStartUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fColorStartUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec4f_GrSLType, "GradientStartColor");
-        fColorMidUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fColorMidUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                            kVec4f_GrSLType, "GradientMidColor");
-        fColorEndUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fColorEndUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec4f_GrSLType, "GradientEndColor");
 
     } else { // if not a fast case
-        fFSYUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fFSYUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                       kFloat_GrSLType, "GradientYCoordFS");
     }
 }
@@ -1037,14 +1037,15 @@
     return key;
 }
 
-void GrGLGradientEffect::emitColor(GrGLShaderBuilder* builder,
+void GrGLGradientEffect::emitColor(GrGLProgramBuilder* builder,
                                    const char* gradientTValue,
                                    uint32_t baseKey,
                                    const char* outputColor,
                                    const char* inputColor,
                                    const TextureSamplerArray& samplers) {
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     if (SkGradientShaderBase::kTwo_GpuColorType == ColorTypeFromKey(baseKey)){
-        builder->fsCodeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
+        fsBuilder->codeAppendf("\tvec4 colorTemp = mix(%s, %s, clamp(%s, 0.0, 1.0));\n",
                                builder->getUniformVariable(fColorStartUni).c_str(),
                                builder->getUniformVariable(fColorEndUni).c_str(),
                                gradientTValue);
@@ -1054,44 +1055,44 @@
         // case. Make sure the key reflects this optimization (and note that it can use the same
         // shader as thekBeforeIterp case). This same optimization applies to the 3 color case below.
         if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(baseKey)) {
-            builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
+            fsBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
         }
 
-        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+        fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
     } else if (SkGradientShaderBase::kThree_GpuColorType == ColorTypeFromKey(baseKey)){
-        builder->fsCodeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
+        fsBuilder->codeAppendf("\tfloat oneMinus2t = 1.0 - (2.0 * (%s));\n",
                                gradientTValue);
-        builder->fsCodeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n",
+        fsBuilder->codeAppendf("\tvec4 colorTemp = clamp(oneMinus2t, 0.0, 1.0) * %s;\n",
                                builder->getUniformVariable(fColorStartUni).c_str());
         if (kTegra3_GrGLRenderer == builder->ctxInfo().renderer()) {
             // The Tegra3 compiler will sometimes never return if we have
             // min(abs(oneMinus2t), 1.0), or do the abs first in a separate expression.
-            builder->fsCodeAppend("\tfloat minAbs = abs(oneMinus2t);\n");
-            builder->fsCodeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n");
-            builder->fsCodeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n",
+            fsBuilder->codeAppend("\tfloat minAbs = abs(oneMinus2t);\n");
+            fsBuilder->codeAppend("\tminAbs = minAbs > 1.0 ? 1.0 : minAbs;\n");
+            fsBuilder->codeAppendf("\tcolorTemp += (1.0 - minAbs) * %s;\n",
                                    builder->getUniformVariable(fColorMidUni).c_str());
         } else {
-            builder->fsCodeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n",
+            fsBuilder->codeAppendf("\tcolorTemp += (1.0 - min(abs(oneMinus2t), 1.0)) * %s;\n",
                                    builder->getUniformVariable(fColorMidUni).c_str());
         }
-        builder->fsCodeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
+        fsBuilder->codeAppendf("\tcolorTemp += clamp(-oneMinus2t, 0.0, 1.0) * %s;\n",
                                builder->getUniformVariable(fColorEndUni).c_str());
         if (GrGradientEffect::kAfterInterp_PremulType == PremulTypeFromKey(baseKey)) {
-            builder->fsCodeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
+            fsBuilder->codeAppend("\tcolorTemp.rgb *= colorTemp.a;\n");
         }
 
-        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+        fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                (GrGLSLExpr4(inputColor) * GrGLSLExpr4("colorTemp")).c_str());
     } else {
-        builder->fsCodeAppendf("\tvec2 coord = vec2(%s, %s);\n",
+        fsBuilder->codeAppendf("\tvec2 coord = vec2(%s, %s);\n",
                                gradientTValue,
                                builder->getUniformVariable(fFSYUni).c_str());
-        builder->fsCodeAppendf("\t%s = ", outputColor);
-        builder->fsAppendTextureLookupAndModulate(inputColor,
+        fsBuilder->codeAppendf("\t%s = ", outputColor);
+        fsBuilder->appendTextureLookupAndModulate(inputColor,
                                                   samplers[0],
                                                   "coord");
-        builder->fsCodeAppend(";\n");
+        fsBuilder->codeAppend(";\n");
     }
 }
 
diff --git a/src/effects/gradients/SkGradientShaderPriv.h b/src/effects/gradients/SkGradientShaderPriv.h
index 7c9d9c3..8f14bbf 100644
--- a/src/effects/gradients/SkGradientShaderPriv.h
+++ b/src/effects/gradients/SkGradientShaderPriv.h
@@ -413,13 +413,13 @@
 
     // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
     // should call this method from their emitCode().
-    void emitUniforms(GrGLShaderBuilder* builder, uint32_t baseKey);
+    void emitUniforms(GrGLProgramBuilder* builder, uint32_t baseKey);
 
 
     // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
     // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
     // native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
-    void emitColor(GrGLShaderBuilder* builder,
+    void emitColor(GrGLProgramBuilder* builder,
                    const char* gradientTValue,
                    uint32_t baseKey,
                    const char* outputColor,
diff --git a/src/effects/gradients/SkLinearGradient.cpp b/src/effects/gradients/SkLinearGradient.cpp
index 9d939bf..551afaa 100644
--- a/src/effects/gradients/SkLinearGradient.cpp
+++ b/src/effects/gradients/SkLinearGradient.cpp
@@ -460,7 +460,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrTBackendEffectFactory.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "SkGr.h"
 
 /////////////////////////////////////////////////////////////////////
@@ -473,7 +473,7 @@
 
     virtual ~GrGLLinearGradient() { }
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -550,7 +550,7 @@
 
 /////////////////////////////////////////////////////////////////////
 
-void GrGLLinearGradient::emitCode(GrGLShaderBuilder* builder,
+void GrGLLinearGradient::emitCode(GrGLProgramBuilder* builder,
                                   const GrDrawEffect&,
                                   const GrEffectKey& key,
                                   const char* outputColor,
@@ -559,7 +559,7 @@
                                   const TextureSamplerArray& samplers) {
     uint32_t baseKey = key.get32(0);
     this->emitUniforms(builder, baseKey);
-    SkString t = builder->ensureFSCoords2D(coords, 0);
+    SkString t = builder->getFragmentShaderBuilder()->ensureFSCoords2D(coords, 0);
     t.append(".x");
     this->emitColor(builder, t.c_str(), baseKey, outputColor, inputColor, samplers);
 }
diff --git a/src/effects/gradients/SkRadialGradient.cpp b/src/effects/gradients/SkRadialGradient.cpp
index fb1d40a..aeae24a 100644
--- a/src/effects/gradients/SkRadialGradient.cpp
+++ b/src/effects/gradients/SkRadialGradient.cpp
@@ -470,7 +470,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrTBackendEffectFactory.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "SkGr.h"
 
 class GrGLRadialGradient : public GrGLGradientEffect {
@@ -480,7 +480,7 @@
                        const GrDrawEffect&) : INHERITED (factory) { }
     virtual ~GrGLRadialGradient() { }
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -559,7 +559,7 @@
 
 /////////////////////////////////////////////////////////////////////
 
-void GrGLRadialGradient::emitCode(GrGLShaderBuilder* builder,
+void GrGLRadialGradient::emitCode(GrGLProgramBuilder* builder,
                                   const GrDrawEffect&,
                                   const GrEffectKey& key,
                                   const char* outputColor,
@@ -569,7 +569,7 @@
     uint32_t baseKey = key.get32(0);
     this->emitUniforms(builder, baseKey);
     SkString t("length(");
-    t.append(builder->ensureFSCoords2D(coords, 0));
+    t.append(builder->getFragmentShaderBuilder()->ensureFSCoords2D(coords, 0));
     t.append(")");
     this->emitColor(builder, t.c_str(), baseKey, outputColor, inputColor, samplers);
 }
diff --git a/src/effects/gradients/SkSweepGradient.cpp b/src/effects/gradients/SkSweepGradient.cpp
index 1bb595c..c56cf14 100644
--- a/src/effects/gradients/SkSweepGradient.cpp
+++ b/src/effects/gradients/SkSweepGradient.cpp
@@ -185,7 +185,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrTBackendEffectFactory.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "SkGr.h"
 
 class GrGLSweepGradient : public GrGLGradientEffect {
@@ -195,7 +195,7 @@
                       const GrDrawEffect&) : INHERITED (factory) { }
     virtual ~GrGLSweepGradient() { }
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -265,7 +265,7 @@
 
 /////////////////////////////////////////////////////////////////////
 
-void GrGLSweepGradient::emitCode(GrGLShaderBuilder* builder,
+void GrGLSweepGradient::emitCode(GrGLProgramBuilder* builder,
                                  const GrDrawEffect&,
                                  const GrEffectKey& key,
                                  const char* outputColor,
@@ -274,7 +274,7 @@
                                  const TextureSamplerArray& samplers) {
     uint32_t baseKey = key.get32(0);
     this->emitUniforms(builder, baseKey);
-    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
+    SkString coords2D = builder->getFragmentShaderBuilder()->ensureFSCoords2D(coords, 0);
     const GrGLContextInfo ctxInfo = builder->ctxInfo();
     SkString t;
     // 0.1591549430918 is 1/(2*pi), used since atan returns values [-pi, pi]
diff --git a/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp b/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
index 4298207..a3ba479 100644
--- a/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
+++ b/src/effects/gradients/SkTwoPointConicalGradient_gpu.cpp
@@ -12,7 +12,7 @@
 
 #if SK_SUPPORT_GPU
 #include "GrTBackendEffectFactory.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 // For brevity
 typedef GrGLProgramDataManager::UniformHandle UniformHandle;
 
@@ -137,7 +137,7 @@
     GLEdge2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
     virtual ~GLEdge2PtConicalEffect() { }
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -217,7 +217,7 @@
     , fCachedRadius(-SK_ScalarMax)
     , fCachedDiffRadius(-SK_ScalarMax) {}
 
-void GLEdge2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
+void GLEdge2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
                                       const GrDrawEffect&,
                                       const GrEffectKey& key,
                                       const char* outputColor,
@@ -226,7 +226,7 @@
                                       const TextureSamplerArray& samplers) {
     uint32_t baseKey = key.get32(0);
     this->emitUniforms(builder, baseKey);
-    fParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
+    fParamUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
                                          kFloat_GrSLType, "Conical2FSParams", 3);
 
     SkString cName("c");
@@ -243,8 +243,9 @@
     SkASSERT(coords[0].type() == coords[1].type());
     const char* coords2D;
     SkString bVar;
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     if (kVec3f_GrSLType == coords[0].type()) {
-        builder->fsCodeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
+        fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
                                coords[0].c_str(), coords[0].c_str(), coords[1].c_str(), coords[1].c_str());
         coords2D = "interpolants.xy";
         bVar = "interpolants.z";
@@ -255,22 +256,22 @@
 
     // output will default to transparent black (we simply won't write anything
     // else to it if invalid, instead of discarding or returning prematurely)
-    builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
+    fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
 
     // c = (x^2)+(y^2) - params[1]
-    builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
+    fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
                            cName.c_str(), coords2D, coords2D, p1.c_str());
 
     // linear case: t = -c/b
-    builder->fsCodeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
+    fsBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
                            cName.c_str(), bVar.c_str());
 
     // if r(t) > 0, then t will be the x coordinate
-    builder->fsCodeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
+    fsBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
                            p2.c_str(), p0.c_str());
-    builder->fsCodeAppend("\t");
+    fsBuilder->codeAppend("\t");
     this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
-    builder->fsCodeAppend("\t}\n");
+    fsBuilder->codeAppend("\t}\n");
 }
 
 void GLEdge2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
@@ -413,7 +414,7 @@
     GLFocalOutside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
     virtual ~GLFocalOutside2PtConicalEffect() { }
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -493,7 +494,7 @@
     fIsFlipped = data.isFlipped();
 }
 
-void GLFocalOutside2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
+void GLFocalOutside2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
                                               const GrDrawEffect&,
                                               const GrEffectKey& key,
                                               const char* outputColor,
@@ -502,7 +503,7 @@
                                               const TextureSamplerArray& samplers) {
     uint32_t baseKey = key.get32(0);
     this->emitUniforms(builder, baseKey);
-    fParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
+    fParamUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
                                          kFloat_GrSLType, "Conical2FSParams", 2);
     SkString tName("t");
     SkString p0; // focalX
@@ -512,33 +513,34 @@
     builder->getUniformVariable(fParamUni).appendArrayAccess(1, &p1);
 
     // if we have a vec3 from being in perspective, convert it to a vec2 first
-    SkString coords2DString = builder->ensureFSCoords2D(coords, 0);
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
     const char* coords2D = coords2DString.c_str();
 
     // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
 
     // output will default to transparent black (we simply won't write anything
     // else to it if invalid, instead of discarding or returning prematurely)
-    builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
+    fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
 
-    builder->fsCodeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
-    builder->fsCodeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
-    builder->fsCodeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
+    fsBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
+    fsBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
+    fsBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
 
     // Must check to see if we flipped the circle order (to make sure start radius < end radius)
     // If so we must also flip sign on sqrt
     if (!fIsFlipped) {
-        builder->fsCodeAppendf("\tfloat %s = %s.x * %s  + sqrt(d);\n", tName.c_str(),
+        fsBuilder->codeAppendf("\tfloat %s = %s.x * %s  + sqrt(d);\n", tName.c_str(),
                                coords2D, p0.c_str());
     } else {
-        builder->fsCodeAppendf("\tfloat %s = %s.x * %s  - sqrt(d);\n", tName.c_str(),
+        fsBuilder->codeAppendf("\tfloat %s = %s.x * %s  - sqrt(d);\n", tName.c_str(),
                                coords2D, p0.c_str());
     }
 
-    builder->fsCodeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
-    builder->fsCodeAppend("\t\t");
+    fsBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
+    fsBuilder->codeAppend("\t\t");
     this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
-    builder->fsCodeAppend("\t}\n");
+    fsBuilder->codeAppend("\t}\n");
 }
 
 void GLFocalOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
@@ -618,7 +620,7 @@
     GLFocalInside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
     virtual ~GLFocalInside2PtConicalEffect() {}
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -695,7 +697,7 @@
     , fFSVaryingName(NULL)
     , fCachedFocal(SK_ScalarMax) {}
 
-void GLFocalInside2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
+void GLFocalInside2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
                                              const GrDrawEffect&,
                                              const GrEffectKey& key,
                                              const char* outputColor,
@@ -704,7 +706,7 @@
                                              const TextureSamplerArray& samplers) {
     uint32_t baseKey = key.get32(0);
     this->emitUniforms(builder, baseKey);
-    fFocalUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fFocalUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                     kFloat_GrSLType, "Conical2FSParams");
     SkString tName("t");
 
@@ -713,11 +715,12 @@
     GrGLShaderVar focal = builder->getUniformVariable(fFocalUni);
 
     // if we have a vec3 from being in perspective, convert it to a vec2 first
-    SkString coords2DString = builder->ensureFSCoords2D(coords, 0);
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
     const char* coords2D = coords2DString.c_str();
 
     // t = p.x * focalX + length(p)
-    builder->fsCodeAppendf("\tfloat %s = %s.x * %s  + length(%s);\n", tName.c_str(),
+    fsBuilder->codeAppendf("\tfloat %s = %s.x * %s  + length(%s);\n", tName.c_str(),
                            coords2D, focal.c_str(), coords2D);
 
     this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
@@ -859,7 +862,7 @@
     GLCircleInside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
     virtual ~GLCircleInside2PtConicalEffect() {}
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -944,7 +947,7 @@
     , fCachedB(SK_ScalarMax)
     , fCachedC(SK_ScalarMax) {}
 
-void GLCircleInside2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
+void GLCircleInside2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
                                               const GrDrawEffect&,
                                               const GrEffectKey& key,
                                               const char* outputColor,
@@ -953,9 +956,9 @@
                                               const TextureSamplerArray& samplers) {
     uint32_t baseKey = key.get32(0);
     this->emitUniforms(builder, baseKey);
-    fCenterUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fCenterUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                      kVec2f_GrSLType, "Conical2FSCenter");
-    fParamUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fParamUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                     kVec3f_GrSLType, "Conical2FSParams");
     SkString tName("t");
 
@@ -966,7 +969,8 @@
     GrGLShaderVar params = builder->getUniformVariable(fParamUni);
 
     // if we have a vec3 from being in perspective, convert it to a vec2 first
-    SkString coords2DString = builder->ensureFSCoords2D(coords, 0);
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
     const char* coords2D = coords2DString.c_str();
 
     // p = coords2D
@@ -977,9 +981,9 @@
     // C = 1 / A
     // d = dot(e, p) + B
     // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
-    builder->fsCodeAppendf("\tfloat pDotp = dot(%s,  %s);\n", coords2D, coords2D);
-    builder->fsCodeAppendf("\tfloat d = dot(%s,  %s) + %s.y;\n", coords2D, center.c_str(), params.c_str());
-    builder->fsCodeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
+    fsBuilder->codeAppendf("\tfloat pDotp = dot(%s,  %s);\n", coords2D, coords2D);
+    fsBuilder->codeAppendf("\tfloat d = dot(%s,  %s) + %s.y;\n", coords2D, center.c_str(), params.c_str());
+    fsBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
                            tName.c_str(), params.c_str(), params.c_str());
 
     this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
@@ -1085,7 +1089,7 @@
     GLCircleOutside2PtConicalEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&);
     virtual ~GLCircleOutside2PtConicalEffect() {}
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -1178,7 +1182,7 @@
     fIsFlipped = data.isFlipped();
     }
 
-void GLCircleOutside2PtConicalEffect::emitCode(GrGLShaderBuilder* builder,
+void GLCircleOutside2PtConicalEffect::emitCode(GrGLProgramBuilder* builder,
                                                const GrDrawEffect&,
                                                const GrEffectKey& key,
                                                const char* outputColor,
@@ -1187,9 +1191,9 @@
                                                const TextureSamplerArray& samplers) {
     uint32_t baseKey = key.get32(0);
     this->emitUniforms(builder, baseKey);
-    fCenterUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fCenterUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                      kVec2f_GrSLType, "Conical2FSCenter");
-    fParamUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fParamUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                     kVec4f_GrSLType, "Conical2FSParams");
     SkString tName("t");
 
@@ -1200,12 +1204,13 @@
     GrGLShaderVar params = builder->getUniformVariable(fParamUni);
 
     // if we have a vec3 from being in perspective, convert it to a vec2 first
-    SkString coords2DString = builder->ensureFSCoords2D(coords, 0);
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2DString = fsBuilder->ensureFSCoords2D(coords, 0);
     const char* coords2D = coords2DString.c_str();
 
     // output will default to transparent black (we simply won't write anything
     // else to it if invalid, instead of discarding or returning prematurely)
-    builder->fsCodeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
+    fsBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
 
     // p = coords2D
     // e = center end
@@ -1216,22 +1221,22 @@
     // d = dot(e, p) + B
     // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
 
-    builder->fsCodeAppendf("\tfloat pDotp = dot(%s,  %s);\n", coords2D, coords2D);
-    builder->fsCodeAppendf("\tfloat d = dot(%s,  %s) + %s.y;\n", coords2D, center.c_str(), params.c_str());
-    builder->fsCodeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(), params.c_str());
+    fsBuilder->codeAppendf("\tfloat pDotp = dot(%s,  %s);\n", coords2D, coords2D);
+    fsBuilder->codeAppendf("\tfloat d = dot(%s,  %s) + %s.y;\n", coords2D, center.c_str(), params.c_str());
+    fsBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(), params.c_str());
 
     // Must check to see if we flipped the circle order (to make sure start radius < end radius)
     // If so we must also flip sign on sqrt
     if (!fIsFlipped) {
-        builder->fsCodeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
+        fsBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
     } else {
-        builder->fsCodeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
+        fsBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
     }
 
-    builder->fsCodeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
-    builder->fsCodeAppend("\t\t");
+    fsBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n", tName.c_str(), params.c_str());
+    fsBuilder->codeAppend("\t\t");
     this->emitColor(builder, tName.c_str(), baseKey, outputColor, inputColor, samplers);
-    builder->fsCodeAppend("\t}\n");
+    fsBuilder->codeAppend("\t}\n");
 }
 
 void GLCircleOutside2PtConicalEffect::setData(const GrGLProgramDataManager& pdman,
diff --git a/src/effects/gradients/SkTwoPointRadialGradient.cpp b/src/effects/gradients/SkTwoPointRadialGradient.cpp
index 754a532..bb5ec04 100644
--- a/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -398,7 +398,7 @@
 #if SK_SUPPORT_GPU
 
 #include "GrTBackendEffectFactory.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "SkGr.h"
 
 // For brevity
@@ -411,7 +411,7 @@
     GrGLRadial2Gradient(const GrBackendEffectFactory& factory, const GrDrawEffect&);
     virtual ~GrGLRadial2Gradient() { }
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -567,7 +567,7 @@
     fIsDegenerate = data.isDegenerate();
 }
 
-void GrGLRadial2Gradient::emitCode(GrGLShaderBuilder* builder,
+void GrGLRadial2Gradient::emitCode(GrGLProgramBuilder* builder,
                                    const GrDrawEffect& drawEffect,
                                    const GrEffectKey& key,
                                    const char* outputColor,
@@ -576,7 +576,7 @@
                                    const TextureSamplerArray& samplers) {
     uint32_t baseKey = key.get32(0);
     this->emitUniforms(builder, baseKey);
-    fParamUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
+    fParamUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
                                          kFloat_GrSLType, "Radial2FSParams", 6);
 
     SkString cName("c");
@@ -596,12 +596,13 @@
     builder->getUniformVariable(fParamUni).appendArrayAccess(4, &p4);
     builder->getUniformVariable(fParamUni).appendArrayAccess(5, &p5);
 
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     // We interpolate the linear component in coords[1].
     SkASSERT(coords[0].type() == coords[1].type());
     const char* coords2D;
     SkString bVar;
     if (kVec3f_GrSLType == coords[0].type()) {
-        builder->fsCodeAppendf("\tvec3 interpolants = vec3(%s.xy, %s.x) / %s.z;\n",
+        fsBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy, %s.x) / %s.z;\n",
                                coords[0].c_str(), coords[1].c_str(), coords[0].c_str());
         coords2D = "interpolants.xy";
         bVar = "interpolants.z";
@@ -611,7 +612,7 @@
     }
 
     // c = (x^2)+(y^2) - params[4]
-    builder->fsCodeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
+    fsBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
                            cName.c_str(), coords2D, coords2D, p4.c_str());
 
     // If we aren't degenerate, emit some extra code, and accept a slightly
@@ -619,13 +620,13 @@
     if (!fIsDegenerate) {
 
         // ac4 = 4.0 * params[0] * c
-        builder->fsCodeAppendf("\tfloat %s = %s * 4.0 * %s;\n",
+        fsBuilder->codeAppendf("\tfloat %s = %s * 4.0 * %s;\n",
                                ac4Name.c_str(), p0.c_str(),
                                cName.c_str());
 
         // root = sqrt(b^2-4ac)
         // (abs to avoid exception due to fp precision)
-        builder->fsCodeAppendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
+        fsBuilder->codeAppendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
                                rootName.c_str(), bVar.c_str(), bVar.c_str(),
                                ac4Name.c_str());
 
diff --git a/src/gpu/GrAAConvexPathRenderer.cpp b/src/gpu/GrAAConvexPathRenderer.cpp
index b2c32ac..b29c7c8 100644
--- a/src/gpu/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/GrAAConvexPathRenderer.cpp
@@ -6,6 +6,7 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrAAConvexPathRenderer.h"
 
 #include "GrContext.h"
@@ -19,7 +20,6 @@
 #include "SkTraceEvent.h"
 
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLVertexEffect.h"
 
@@ -531,7 +531,7 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
             : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLFullShaderBuilder* builder,
+        virtual void emitCode(GrGLFullProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -539,35 +539,38 @@
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
             const char *vsName, *fsName;
-            const SkString* attrName =
-                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
-
-            SkAssertResult(builder->enableFeature(
-                                              GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
             builder->addVarying(kVec4f_GrSLType, "QuadEdge", &vsName, &fsName);
 
+            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+
+            SkAssertResult(fsBuilder->enableFeature(
+                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
+            fsBuilder->codeAppendf("\t\tfloat edgeAlpha;\n");
+
             // keep the derivative instructions outside the conditional
-            builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            builder->fsCodeAppendf("\t\tif (%s.z > 0.0 && %s.w > 0.0) {\n", fsName, fsName);
+            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);
             // today we know z and w are in device space. We could use derivatives
-            builder->fsCodeAppendf("\t\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
+            fsBuilder->codeAppendf("\t\t\tedgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);\n", fsName,
                                     fsName);
-            builder->fsCodeAppendf ("\t\t} else {\n");
-            builder->fsCodeAppendf("\t\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+            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);
-            builder->fsCodeAppendf("\t\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
+            fsBuilder->codeAppendf("\t\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
                                     fsName);
-            builder->fsCodeAppendf("\t\t\tedgeAlpha = "
+            fsBuilder->codeAppendf("\t\t\tedgeAlpha = "
                                    "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);\n\t\t}\n");
 
 
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+            fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
 
-            builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+            GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+            const SkString* attr0Name =
+                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
         }
 
         static inline void GenKey(const GrDrawEffect&, const GrGLCaps&, GrEffectKeyBuilder*) {}
@@ -589,7 +592,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrEffect INHERITED;
 };
 
 GR_DEFINE_EFFECT_TEST(QuadEdgeEffect);
diff --git a/src/gpu/GrAARectRenderer.cpp b/src/gpu/GrAARectRenderer.cpp
index 1d350c3..b4790bb 100644
--- a/src/gpu/GrAARectRenderer.cpp
+++ b/src/gpu/GrAARectRenderer.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrAARectRenderer.h"
 #include "GrGpu.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "SkColorPriv.h"
@@ -44,7 +44,7 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLFullShaderBuilder* builder,
+        virtual void emitCode(GrGLFullProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -56,35 +56,38 @@
             //      zw -> w/2+0.5, h/2+0.5
             const char *vsRectName, *fsRectName;
             builder->addVarying(kVec4f_GrSLType, "Rect", &vsRectName, &fsRectName);
-            const SkString* attr0Name =
-                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            builder->vsCodeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
 
+            GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+            const SkString* attr0Name =
+                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsRectName, attr0Name->c_str());
+
+            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
             // TODO: compute all these offsets, spans, and scales in the VS
-            builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.z) - 0.5;\n", fsRectName);
-            builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.w) - 0.5;\n", fsRectName);
-            builder->fsCodeAppend("\tfloat outset = 0.5;\n");
+            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->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.
-            builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
-            builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
+            fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
+            fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
             // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
             // value of coverage that is used. In other words it is the coverage that is
             // used in the interior of the rect after the ramp.
-            builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
-            builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
+            fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
+            fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
 
             // Compute the coverage for the rect's width
-            builder->fsCodeAppendf(
+            fsBuilder->codeAppendf(
                 "\tfloat coverage = scaleW*clamp((%s.z-abs(%s.x))/spanW, 0.0, 1.0);\n", fsRectName,
                 fsRectName);
             // Compute the coverage for the rect's height and merge with the width
-            builder->fsCodeAppendf(
+            fsBuilder->codeAppendf(
                 "\tcoverage = coverage*scaleH*clamp((%s.w-abs(%s.y))/spanH, 0.0, 1.0);\n",
                 fsRectName, fsRectName);
 
 
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+            fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
         }
 
@@ -160,7 +163,7 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLFullShaderBuilder* builder,
+        virtual void emitCode(GrGLFullProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -172,50 +175,53 @@
             const char *vsRectEdgeName, *fsRectEdgeName;
             builder->addVarying(kVec4f_GrSLType, "RectEdge",
                                 &vsRectEdgeName, &fsRectEdgeName);
+
+            GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
             const SkString* attr0Name =
-                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            builder->vsCodeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
+                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsRectEdgeName, attr0Name->c_str());
 
             // setup the varying for width/2+.5 and height/2+.5
             const char *vsWidthHeightName, *fsWidthHeightName;
             builder->addVarying(kVec2f_GrSLType, "WidthHeight",
                                 &vsWidthHeightName, &fsWidthHeightName);
             const SkString* attr1Name =
-                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
-            builder->vsCodeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
+                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsWidthHeightName, attr1Name->c_str());
 
+            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
             // TODO: compute all these offsets, spans, and scales in the VS
-            builder->fsCodeAppendf("\tfloat insetW = min(1.0, %s.x) - 0.5;\n", fsWidthHeightName);
-            builder->fsCodeAppendf("\tfloat insetH = min(1.0, %s.y) - 0.5;\n", fsWidthHeightName);
-            builder->fsCodeAppend("\tfloat outset = 0.5;\n");
+            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->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.
-            builder->fsCodeAppend("\tfloat spanW = insetW + outset;\n");
-            builder->fsCodeAppend("\tfloat spanH = insetH + outset;\n");
+            fsBuilder->codeAppend("\tfloat spanW = insetW + outset;\n");
+            fsBuilder->codeAppend("\tfloat spanH = insetH + outset;\n");
             // For rects < 1 pixel wide or tall, these scale factors are used to cap the maximum
             // value of coverage that is used. In other words it is the coverage that is
             // used in the interior of the rect after the ramp.
-            builder->fsCodeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
-            builder->fsCodeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
+            fsBuilder->codeAppend("\tfloat scaleW = min(1.0, 2.0*insetW/spanW);\n");
+            fsBuilder->codeAppend("\tfloat scaleH = min(1.0, 2.0*insetH/spanH);\n");
 
             // Compute the coverage for the rect's width
-            builder->fsCodeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
-                                   builder->fragmentPosition(), fsRectEdgeName);
-            builder->fsCodeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
+            fsBuilder->codeAppendf("\tvec2 offset = %s.xy - %s.xy;\n",
+                                   fsBuilder->fragmentPosition(), fsRectEdgeName);
+            fsBuilder->codeAppendf("\tfloat perpDot = abs(offset.x * %s.w - offset.y * %s.z);\n",
                                    fsRectEdgeName, fsRectEdgeName);
-            builder->fsCodeAppendf(
+            fsBuilder->codeAppendf(
                 "\tfloat coverage = scaleW*clamp((%s.x-perpDot)/spanW, 0.0, 1.0);\n",
                 fsWidthHeightName);
 
             // Compute the coverage for the rect's height and merge with the width
-            builder->fsCodeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
+            fsBuilder->codeAppendf("\tperpDot = abs(dot(offset, %s.zw));\n",
                                    fsRectEdgeName);
-            builder->fsCodeAppendf(
+            fsBuilder->codeAppendf(
                     "\tcoverage = coverage*scaleH*clamp((%s.y-perpDot)/spanH, 0.0, 1.0);\n",
                     fsWidthHeightName);
 
 
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+            fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("coverage")).c_str());
         }
 
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 395c90b..dcce889 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -5,12 +5,12 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrOvalRenderer.h"
 
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
 
@@ -95,7 +95,7 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLFullShaderBuilder* builder,
+        virtual void emitCode(GrGLFullProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -106,18 +106,20 @@
             const char *vsName, *fsName;
             builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
 
-            const SkString* attrName =
-                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+            GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+            const SkString* attr0Name =
+                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
 
-            builder->fsCodeAppendf("\tfloat d = length(%s.xy);\n", fsName);
-            builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
+            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+            fsBuilder->codeAppendf("\tfloat d = length(%s.xy);\n", fsName);
+            fsBuilder->codeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName);
             if (circleEffect.isStroked()) {
-                builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName);
-                builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
+                fsBuilder->codeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName);
+                fsBuilder->codeAppend("\tedgeAlpha *= innerAlpha;\n");
             }
 
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+            fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
         }
 
@@ -206,7 +208,7 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLFullShaderBuilder* builder,
+        virtual void emitCode(GrGLFullProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -219,35 +221,38 @@
             const char *vsRadiiName, *fsRadiiName;
 
             builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName, &fsOffsetName);
+
+            GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
             const SkString* attr0Name =
-                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_str());
+                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_str());
 
             builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName);
             const SkString* attr1Name =
-                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
-            builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str());
+                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str());
 
             // for outer curve
-            builder->fsCodeAppendf("\tvec2 scaledOffset = %s*%s.xy;\n", fsOffsetName, fsRadiiName);
-            builder->fsCodeAppend("\tfloat test = dot(scaledOffset, scaledOffset) - 1.0;\n");
-            builder->fsCodeAppendf("\tvec2 grad = 2.0*scaledOffset*%s.xy;\n", fsRadiiName);
-            builder->fsCodeAppend("\tfloat grad_dot = dot(grad, grad);\n");
+            GrGLFragmentShaderBuilder* fsBuilder = builder->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");
             // avoid calling inversesqrt on zero.
-            builder->fsCodeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n");
-            builder->fsCodeAppend("\tfloat invlen = inversesqrt(grad_dot);\n");
-            builder->fsCodeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n");
+            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");
 
             // for inner curve
             if (ellipseEffect.isStroked()) {
-                builder->fsCodeAppendf("\tscaledOffset = %s*%s.zw;\n", fsOffsetName, fsRadiiName);
-                builder->fsCodeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n");
-                builder->fsCodeAppendf("\tgrad = 2.0*scaledOffset*%s.zw;\n", fsRadiiName);
-                builder->fsCodeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n");
-                builder->fsCodeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
+                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");
             }
 
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+            fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
         }
 
@@ -344,7 +349,7 @@
         GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
         : INHERITED (factory) {}
 
-        virtual void emitCode(GrGLFullShaderBuilder* builder,
+        virtual void emitCode(GrGLFullProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -353,57 +358,59 @@
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
             const DIEllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<DIEllipseEdgeEffect>();
 
-            SkAssertResult(builder->enableFeature(
-                                              GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
-
             const char *vsOffsetName0, *fsOffsetName0;
             builder->addVarying(kVec2f_GrSLType, "EllipseOffsets0",
                                       &vsOffsetName0, &fsOffsetName0);
+
+            GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
             const SkString* attr0Name =
-                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-            builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName0, attr0Name->c_str());
+                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName0, attr0Name->c_str());
             const char *vsOffsetName1, *fsOffsetName1;
             builder->addVarying(kVec2f_GrSLType, "EllipseOffsets1",
                                       &vsOffsetName1, &fsOffsetName1);
             const SkString* attr1Name =
-                builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
-            builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName1, attr1Name->c_str());
+                vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]);
+            vsBuilder->codeAppendf("\t%s = %s;\n", vsOffsetName1, attr1Name->c_str());
 
+            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+            SkAssertResult(fsBuilder->enableFeature(
+                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
             // for outer curve
-            builder->fsCodeAppendf("\tvec2 scaledOffset = %s.xy;\n", fsOffsetName0);
-            builder->fsCodeAppend("\tfloat test = dot(scaledOffset, scaledOffset) - 1.0;\n");
-            builder->fsCodeAppendf("\tvec2 duvdx = dFdx(%s);\n", fsOffsetName0);
-            builder->fsCodeAppendf("\tvec2 duvdy = dFdy(%s);\n", fsOffsetName0);
-            builder->fsCodeAppendf("\tvec2 grad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,\n"
+            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);
 
-            builder->fsCodeAppend("\tfloat grad_dot = dot(grad, grad);\n");
+            fsBuilder->codeAppend("\tfloat grad_dot = dot(grad, grad);\n");
             // avoid calling inversesqrt on zero.
-            builder->fsCodeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n");
-            builder->fsCodeAppend("\tfloat invlen = inversesqrt(grad_dot);\n");
+            fsBuilder->codeAppend("\tgrad_dot = max(grad_dot, 1.0e-4);\n");
+            fsBuilder->codeAppend("\tfloat invlen = inversesqrt(grad_dot);\n");
             if (kHairline == ellipseEffect.getMode()) {
                 // can probably do this with one step
-                builder->fsCodeAppend("\tfloat edgeAlpha = clamp(1.0-test*invlen, 0.0, 1.0);\n");
-                builder->fsCodeAppend("\tedgeAlpha *= clamp(1.0+test*invlen, 0.0, 1.0);\n");
+                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");
             } else {
-                builder->fsCodeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n");
+                fsBuilder->codeAppend("\tfloat edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);\n");
             }
 
             // for inner curve
             if (kStroke == ellipseEffect.getMode()) {
-                builder->fsCodeAppendf("\tscaledOffset = %s.xy;\n", fsOffsetName1);
-                builder->fsCodeAppend("\ttest = dot(scaledOffset, scaledOffset) - 1.0;\n");
-                builder->fsCodeAppendf("\tduvdx = dFdx(%s);\n", fsOffsetName1);
-                builder->fsCodeAppendf("\tduvdy = dFdy(%s);\n", fsOffsetName1);
-                builder->fsCodeAppendf("\tgrad = vec2(2.0*%s.x*duvdx.x + 2.0*%s.y*duvdx.y,\n"
+                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);
-                builder->fsCodeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n");
-                builder->fsCodeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
+                fsBuilder->codeAppend("\tinvlen = inversesqrt(dot(grad, grad));\n");
+                fsBuilder->codeAppend("\tedgeAlpha *= clamp(0.5+test*invlen, 0.0, 1.0);\n");
             }
 
-            builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+            fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
         }
 
diff --git a/src/gpu/effects/GrBezierEffect.cpp b/src/gpu/effects/GrBezierEffect.cpp
index 6f3772d..7384f62 100644
--- a/src/gpu/effects/GrBezierEffect.cpp
+++ b/src/gpu/effects/GrBezierEffect.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrBezierEffect.h"
 
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLVertexEffect.h"
 #include "GrTBackendEffectFactory.h"
@@ -17,7 +17,7 @@
 public:
     GrGLConicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLFullShaderBuilder* builder,
+    virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -42,7 +42,7 @@
     fEdgeType = ce.getEdgeType();
 }
 
-void GrGLConicEffect::emitCode(GrGLFullShaderBuilder* builder,
+void GrGLConicEffect::emitCode(GrGLFullProgramBuilder* builder,
                                const GrDrawEffect& drawEffect,
                                const GrEffectKey& key,
                                const char* outputColor,
@@ -53,67 +53,70 @@
 
     builder->addVarying(kVec4f_GrSLType, "ConicCoeffs",
                               &vsName, &fsName);
-    const SkString* attr0Name =
-        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
 
-    builder->fsCodeAppend("\t\tfloat edgeAlpha;\n");
+    GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+    const SkString* attr0Name =
+        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    vsBuilder->codeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->codeAppend("\t\tfloat edgeAlpha;\n");
 
     switch (fEdgeType) {
         case kHairlineAA_GrEffectEdgeType: {
-            SkAssertResult(builder->enableFeature(
-                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
-            builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
-            builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
-            builder->fsCodeAppendf("\t\tfloat dfdx =\n"
+            SkAssertResult(fsBuilder->enableFeature(
+                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
+            fsBuilder->codeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
+            fsBuilder->codeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
+            fsBuilder->codeAppendf("\t\tfloat dfdx =\n"
                                    "\t\t\t2.0*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n",
                                    fsName, fsName, fsName);
-            builder->fsCodeAppendf("\t\tfloat dfdy =\n"
+            fsBuilder->codeAppendf("\t\tfloat dfdy =\n"
                                    "\t\t\t2.0*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n",
                                    fsName, fsName, fsName);
-            builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
-            builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
-            builder->fsCodeAppendf("\t\tfloat func = %s.x*%s.x - %s.y*%s.z;\n", fsName, fsName,
+            fsBuilder->codeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
+            fsBuilder->codeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
+            fsBuilder->codeAppendf("\t\tfloat func = %s.x*%s.x - %s.y*%s.z;\n", fsName, fsName,
                                    fsName, fsName);
-            builder->fsCodeAppend("\t\tfunc = abs(func);\n");
-            builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n");
-            builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            fsBuilder->codeAppend("\t\tfunc = abs(func);\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = func / gFM;\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
             // Add line below for smooth cubic ramp
-            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            // fsBuilder->codeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
             break;
         }
         case kFillAA_GrEffectEdgeType: {
-            SkAssertResult(builder->enableFeature(
-                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
-            builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
-            builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
-            builder->fsCodeAppendf("\t\tfloat dfdx =\n"
+            SkAssertResult(fsBuilder->enableFeature(
+                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
+            fsBuilder->codeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
+            fsBuilder->codeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
+            fsBuilder->codeAppendf("\t\tfloat dfdx =\n"
                                    "\t\t\t2.0*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n",
                                    fsName, fsName, fsName);
-            builder->fsCodeAppendf("\t\tfloat dfdy =\n"
+            fsBuilder->codeAppendf("\t\tfloat dfdy =\n"
                                    "\t\t\t2.0*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n",
                                    fsName, fsName, fsName);
-            builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
-            builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
-            builder->fsCodeAppendf("\t\tfloat func = %s.x*%s.x - %s.y*%s.z;\n", fsName, fsName,
+            fsBuilder->codeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
+            fsBuilder->codeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
+            fsBuilder->codeAppendf("\t\tfloat func = %s.x*%s.x - %s.y*%s.z;\n", fsName, fsName,
                                    fsName, fsName);
-            builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n");
-            builder->fsCodeAppend("\t\tedgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = func / gFM;\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);\n");
             // Add line below for smooth cubic ramp
-            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            // fsBuilder->codeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
             break;
         }
         case kFillBW_GrEffectEdgeType: {
-            builder->fsCodeAppendf("\t\tedgeAlpha = %s.x*%s.x - %s.y*%s.z;\n", fsName, fsName,
+            fsBuilder->codeAppendf("\t\tedgeAlpha = %s.x*%s.x - %s.y*%s.z;\n", fsName, fsName,
                                    fsName, fsName);
-            builder->fsCodeAppend("\t\tedgeAlpha = float(edgeAlpha < 0.0);\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = float(edgeAlpha < 0.0);\n");
             break;
         }
         default:
             SkFAIL("Shouldn't get here");
     }
 
-    builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
 }
 
@@ -167,7 +170,7 @@
 public:
     GrGLQuadEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLFullShaderBuilder* builder,
+    virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -192,7 +195,7 @@
     fEdgeType = ce.getEdgeType();
 }
 
-void GrGLQuadEffect::emitCode(GrGLFullShaderBuilder* builder,
+void GrGLQuadEffect::emitCode(GrGLFullProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -200,61 +203,61 @@
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) {
     const char *vsName, *fsName;
-
-    const SkString* attrName =
-        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n");
-
     builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsName);
 
+    GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+    const SkString* attrName =
+        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    vsBuilder->codeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->codeAppendf("\t\tfloat edgeAlpha;\n");
+
     switch (fEdgeType) {
         case kHairlineAA_GrEffectEdgeType: {
-            SkAssertResult(builder->enableFeature(
-                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
-            builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+            SkAssertResult(fsBuilder->enableFeature(
+                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
+            fsBuilder->codeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            fsBuilder->codeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            fsBuilder->codeAppendf("\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,
+            fsBuilder->codeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
                                    fsName);
-            builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
-            builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / dot(gF, gF));\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
             // Add line below for smooth cubic ramp
-            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            // fsBuilder->codeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
             break;
         }
         case kFillAA_GrEffectEdgeType: {
-            SkAssertResult(builder->enableFeature(
-                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
-            builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
-            builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
-            builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,\n"
+            SkAssertResult(fsBuilder->enableFeature(
+                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
+            fsBuilder->codeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName);
+            fsBuilder->codeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName);
+            fsBuilder->codeAppendf("\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,
+            fsBuilder->codeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
                                    fsName);
-            builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha / sqrt(dot(gF, gF));\n");
-            builder->fsCodeAppend("\t\tedgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = edgeAlpha / sqrt(dot(gF, gF));\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);\n");
             // Add line below for smooth cubic ramp
-            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            // fsBuilder->codeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
             break;
         }
         case kFillBW_GrEffectEdgeType: {
-            builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
+            fsBuilder->codeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsName, fsName,
                                    fsName);
-            builder->fsCodeAppend("\t\tedgeAlpha = float(edgeAlpha < 0.0);\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = float(edgeAlpha < 0.0);\n");
             break;
         }
         default:
             SkFAIL("Shouldn't get here");
     }
 
-    builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
-
-
-    builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str());
 }
 
 void GrGLQuadEffect::GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&,
@@ -307,7 +310,7 @@
 public:
     GrGLCubicEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLFullShaderBuilder* builder,
+    virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -332,7 +335,7 @@
     fEdgeType = ce.getEdgeType();
 }
 
-void GrGLCubicEffect::emitCode(GrGLFullShaderBuilder* builder,
+void GrGLCubicEffect::emitCode(GrGLFullProgramBuilder* builder,
                                const GrDrawEffect& drawEffect,
                                const GrEffectKey& key,
                                const char* outputColor,
@@ -343,67 +346,70 @@
 
     builder->addVarying(kVec4f_GrSLType, "CubicCoeffs",
                               &vsName, &fsName);
-    const SkString* attr0Name =
-        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
 
-    builder->fsCodeAppend("\t\tfloat edgeAlpha;\n");
+    GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+    const SkString* attr0Name =
+        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    vsBuilder->codeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str());
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->codeAppend("\t\tfloat edgeAlpha;\n");
 
     switch (fEdgeType) {
         case kHairlineAA_GrEffectEdgeType: {
-            SkAssertResult(builder->enableFeature(
-                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
-            builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
-            builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
-            builder->fsCodeAppendf("\t\tfloat dfdx =\n"
+            SkAssertResult(fsBuilder->enableFeature(
+                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
+            fsBuilder->codeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
+            fsBuilder->codeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
+            fsBuilder->codeAppendf("\t\tfloat dfdx =\n"
                                    "\t\t3.0*%s.x*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n",
                                    fsName, fsName, fsName, fsName);
-            builder->fsCodeAppendf("\t\tfloat dfdy =\n"
+            fsBuilder->codeAppendf("\t\tfloat dfdy =\n"
                                    "\t\t3.0*%s.x*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n",
                                    fsName, fsName, fsName, fsName);
-            builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
-            builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
-            builder->fsCodeAppendf("\t\tfloat func = %s.x*%s.x*%s.x - %s.y*%s.z;\n",
+            fsBuilder->codeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
+            fsBuilder->codeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
+            fsBuilder->codeAppendf("\t\tfloat func = %s.x*%s.x*%s.x - %s.y*%s.z;\n",
                                    fsName, fsName, fsName, fsName, fsName);
-            builder->fsCodeAppend("\t\tfunc = abs(func);\n");
-            builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n");
-            builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
+            fsBuilder->codeAppend("\t\tfunc = abs(func);\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = func / gFM;\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n");
             // Add line below for smooth cubic ramp
-            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            // fsBuilder->codeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
             break;
         }
         case kFillAA_GrEffectEdgeType: {
-            SkAssertResult(builder->enableFeature(
-                    GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
-            builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
-            builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
-            builder->fsCodeAppendf("\t\tfloat dfdx =\n"
+            SkAssertResult(fsBuilder->enableFeature(
+                    GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
+            fsBuilder->codeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName);
+            fsBuilder->codeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName);
+            fsBuilder->codeAppendf("\t\tfloat dfdx =\n"
                                    "\t\t3.0*%s.x*%s.x*dklmdx.x - %s.y*dklmdx.z - %s.z*dklmdx.y;\n",
                                    fsName, fsName, fsName, fsName);
-            builder->fsCodeAppendf("\t\tfloat dfdy =\n"
+            fsBuilder->codeAppendf("\t\tfloat dfdy =\n"
                                    "\t\t3.0*%s.x*%s.x*dklmdy.x - %s.y*dklmdy.z - %s.z*dklmdy.y;\n",
                                    fsName, fsName, fsName, fsName);
-            builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
-            builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
-            builder->fsCodeAppendf("\t\tfloat func = %s.x*%s.x*%s.x - %s.y*%s.z;\n",
+            fsBuilder->codeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n");
+            fsBuilder->codeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n");
+            fsBuilder->codeAppendf("\t\tfloat func = %s.x*%s.x*%s.x - %s.y*%s.z;\n",
                                    fsName, fsName, fsName, fsName, fsName);
-            builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n");
-            builder->fsCodeAppend("\t\tedgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = func / gFM;\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = clamp(1.0 - edgeAlpha, 0.0, 1.0);\n");
             // Add line below for smooth cubic ramp
-            // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
+            // fsBuilder->codeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);\n");
             break;
         }
         case kFillBW_GrEffectEdgeType: {
-            builder->fsCodeAppendf("\t\tedgeAlpha = %s.x*%s.x*%s.x - %s.y*%s.z;\n",
+            fsBuilder->codeAppendf("\t\tedgeAlpha = %s.x*%s.x*%s.x - %s.y*%s.z;\n",
                                    fsName, fsName, fsName, fsName, fsName);
-            builder->fsCodeAppend("\t\tedgeAlpha = float(edgeAlpha < 0.0);\n");
+            fsBuilder->codeAppend("\t\tedgeAlpha = float(edgeAlpha < 0.0);\n");
             break;
         }
         default:
             SkFAIL("Shouldn't get here");
     }
 
-    builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("edgeAlpha")).c_str());
 }
 
diff --git a/src/gpu/effects/GrBicubicEffect.cpp b/src/gpu/effects/GrBicubicEffect.cpp
index fb98b4a..27d482a 100644
--- a/src/gpu/effects/GrBicubicEffect.cpp
+++ b/src/gpu/effects/GrBicubicEffect.cpp
@@ -5,9 +5,9 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrBicubicEffect.h"
 
-#include "gl/GrGLShaderBuilder.h"
 
 #define DS(x) SkDoubleToScalar(x)
 
@@ -24,7 +24,7 @@
     GrGLBicubicEffect(const GrBackendEffectFactory& factory,
                       const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -54,7 +54,7 @@
     : INHERITED(factory) {
 }
 
-void GrGLBicubicEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLBicubicEffect::emitCode(GrGLProgramBuilder* builder,
                                  const GrDrawEffect& drawEffect,
                                  const GrEffectKey& key,
                                  const char* outputColor,
@@ -63,10 +63,9 @@
                                  const TextureSamplerArray& samplers) {
     const GrTextureDomain& domain = drawEffect.castEffect<GrBicubicEffect>().domain();
 
-    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
-    fCoefficientsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fCoefficientsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                            kMat44f_GrSLType, "Coefficients");
-    fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec2f_GrSLType, "ImageIncrement");
 
     const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
@@ -82,7 +81,9 @@
         GrGLShaderVar("c2",            kVec4f_GrSLType),
         GrGLShaderVar("c3",            kVec4f_GrSLType),
     };
-    builder->fsEmitFunction(kVec4f_GrSLType,
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
+    fsBuilder->emitFunction(kVec4f_GrSLType,
                             "cubicBlend",
                             SK_ARRAY_COUNT(gCubicBlendArgs),
                             gCubicBlendArgs,
@@ -90,28 +91,28 @@
                             "\tvec4 c = coefficients * ts;\n"
                             "\treturn c.x * c0 + c.y * c1 + c.z * c2 + c.w * c3;\n",
                             &cubicBlendName);
-    builder->fsCodeAppendf("\tvec2 coord = %s - %s * vec2(0.5);\n", coords2D.c_str(), imgInc);
+    fsBuilder->codeAppendf("\tvec2 coord = %s - %s * vec2(0.5);\n", coords2D.c_str(), imgInc);
     // We unnormalize the coord in order to determine our fractional offset (f) within the texel
     // We then snap coord to a texel center and renormalize. The snap prevents cases where the
     // starting coords are near a texel boundary and accumulations of imgInc would cause us to skip/
     // double hit a texel.
-    builder->fsCodeAppendf("\tcoord /= %s;\n", imgInc);
-    builder->fsCodeAppend("\tvec2 f = fract(coord);\n");
-    builder->fsCodeAppendf("\tcoord = (coord - f + vec2(0.5)) * %s;\n", imgInc);
-    builder->fsCodeAppend("\tvec4 rowColors[4];\n");
+    fsBuilder->codeAppendf("\tcoord /= %s;\n", imgInc);
+    fsBuilder->codeAppend("\tvec2 f = fract(coord);\n");
+    fsBuilder->codeAppendf("\tcoord = (coord - f + vec2(0.5)) * %s;\n", imgInc);
+    fsBuilder->codeAppend("\tvec4 rowColors[4];\n");
     for (int y = 0; y < 4; ++y) {
         for (int x = 0; x < 4; ++x) {
             SkString coord;
             coord.printf("coord + %s * vec2(%d, %d)", imgInc, x - 1, y - 1);
             SkString sampleVar;
             sampleVar.printf("rowColors[%d]", x);
-            fDomain.sampleTexture(builder, domain, sampleVar.c_str(), coord, samplers[0]);
+            fDomain.sampleTexture(fsBuilder, domain, sampleVar.c_str(), coord, samplers[0]);
         }
-        builder->fsCodeAppendf("\tvec4 s%d = %s(%s, f.x, rowColors[0], rowColors[1], rowColors[2], rowColors[3]);\n", y, cubicBlendName.c_str(), coeff);
+        fsBuilder->codeAppendf("\tvec4 s%d = %s(%s, f.x, rowColors[0], rowColors[1], rowColors[2], rowColors[3]);\n", y, cubicBlendName.c_str(), coeff);
     }
     SkString bicubicColor;
     bicubicColor.printf("%s(%s, f.y, s0, s1, s2, s3)", cubicBlendName.c_str(), coeff);
-    builder->fsCodeAppendf("\t%s = %s;\n", outputColor, (GrGLSLExpr4(bicubicColor.c_str()) * GrGLSLExpr4(inputColor)).c_str());
+    fsBuilder->codeAppendf("\t%s = %s;\n", outputColor, (GrGLSLExpr4(bicubicColor.c_str()) * GrGLSLExpr4(inputColor)).c_str());
 }
 
 void GrGLBicubicEffect::setData(const GrGLProgramDataManager& pdman,
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index d7ba686..84e60cd 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -10,7 +10,7 @@
 #include "GrTBackendEffectFactory.h"
 #include "GrSimpleTextureEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "SkMatrix.h"
 
 class GrGLConfigConversionEffect : public GrGLEffect {
@@ -23,7 +23,7 @@
         fPMConversion = effect.pmConversion();
     }
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect&,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -34,20 +34,23 @@
         GrGLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, GrGLShaderVar::kHigh_Precision);
         SkString tmpDecl;
         tmpVar.appendDecl(builder->ctxInfo(), &tmpDecl);
-        builder->fsCodeAppendf("%s;", tmpDecl.c_str());
 
-        builder->fsCodeAppendf("%s = ", tmpVar.c_str());
-        builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
-        builder->fsCodeAppend(";");
+        GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+
+        fsBuilder->codeAppendf("%s;", tmpDecl.c_str());
+
+        fsBuilder->codeAppendf("%s = ", tmpVar.c_str());
+        fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
+        fsBuilder->codeAppend(";");
 
         if (GrConfigConversionEffect::kNone_PMConversion == fPMConversion) {
             SkASSERT(fSwapRedAndBlue);
-            builder->fsCodeAppendf("%s = %s.bgra;", outputColor, tmpVar.c_str());
+            fsBuilder->codeAppendf("%s = %s.bgra;", outputColor, tmpVar.c_str());
         } else {
             const char* swiz = fSwapRedAndBlue ? "bgr" : "rgb";
             switch (fPMConversion) {
                 case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
-                    builder->fsCodeAppendf(
+                    fsBuilder->codeAppendf(
                         "%s = vec4(ceil(%s.%s * %s.a * 255.0) / 255.0, %s.a);",
                         tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                     break;
@@ -56,17 +59,17 @@
                     // In Intel GPUs, the integer value converted from floor(%s.r * 255.0) / 255.0
                     // is less than the integer value converted from  %s.r by 1 when the %s.r is
                     // converted from the integer value 2^n, such as 1, 2, 4, 8, etc.
-                    builder->fsCodeAppendf(
+                    fsBuilder->codeAppendf(
                         "%s = vec4(floor(%s.%s * %s.a * 255.0 + 0.001) / 255.0, %s.a);",
                         tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                     break;
                 case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
-                    builder->fsCodeAppendf(
+                    fsBuilder->codeAppendf(
                         "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.%s / %s.a * 255.0) / 255.0, %s.a);",
                         tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                     break;
                 case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
-                    builder->fsCodeAppendf(
+                    fsBuilder->codeAppendf(
                         "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.%s / %s.a * 255.0) / 255.0, %s.a);",
                         tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), swiz, tmpVar.c_str(), tmpVar.c_str());
                     break;
@@ -74,11 +77,11 @@
                     SkFAIL("Unknown conversion op.");
                     break;
             }
-            builder->fsCodeAppendf("%s = %s;", outputColor, tmpVar.c_str());
+            fsBuilder->codeAppendf("%s = %s;", outputColor, tmpVar.c_str());
         }
         SkString modulate;
         GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
-        builder->fsCodeAppend(modulate.c_str());
+        fsBuilder->codeAppend(modulate.c_str());
     }
 
     static inline void GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&,
diff --git a/src/gpu/effects/GrConvexPolyEffect.cpp b/src/gpu/effects/GrConvexPolyEffect.cpp
index 41911c1..71a8bef 100644
--- a/src/gpu/effects/GrConvexPolyEffect.cpp
+++ b/src/gpu/effects/GrConvexPolyEffect.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrConvexPolyEffect.h"
 
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrTBackendEffectFactory.h"
 
@@ -89,7 +89,7 @@
 public:
     GLAARectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -113,7 +113,7 @@
     fPrevRect.fLeft = SK_ScalarNaN;
 }
 
-void GLAARectEffect::emitCode(GrGLShaderBuilder* builder,
+void GLAARectEffect::emitCode(GrGLProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -124,34 +124,36 @@
     const char *rectName;
     // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
     // respectively.
-    fRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                        kVec4f_GrSLType,
                                        "rect",
                                        &rectName);
-    const char* fragmentPos = builder->fragmentPosition();
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    const char* fragmentPos = fsBuilder->fragmentPosition();
     if (GrEffectEdgeTypeIsAA(aare.getEdgeType())) {
         // The amount of coverage removed in x and y by the edges is computed as a pair of negative
         // numbers, xSub and ySub.
-        builder->fsCodeAppend("\t\tfloat xSub, ySub;\n");
-        builder->fsCodeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName);
-        builder->fsCodeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos);
-        builder->fsCodeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName);
-        builder->fsCodeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos);
+        fsBuilder->codeAppend("\t\tfloat xSub, ySub;\n");
+        fsBuilder->codeAppendf("\t\txSub = min(%s.x - %s.x, 0.0);\n", fragmentPos, rectName);
+        fsBuilder->codeAppendf("\t\txSub += min(%s.z - %s.x, 0.0);\n", rectName, fragmentPos);
+        fsBuilder->codeAppendf("\t\tySub = min(%s.y - %s.y, 0.0);\n", fragmentPos, rectName);
+        fsBuilder->codeAppendf("\t\tySub += min(%s.w - %s.y, 0.0);\n", rectName, fragmentPos);
         // Now compute coverage in x and y and multiply them to get the fraction of the pixel
         // covered.
-        builder->fsCodeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
+        fsBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
     } else {
-        builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n");
-        builder->fsCodeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
-        builder->fsCodeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
-        builder->fsCodeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
-        builder->fsCodeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
+        fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n");
+        fsBuilder->codeAppendf("\t\talpha *= (%s.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
+        fsBuilder->codeAppendf("\t\talpha *= (%s.z - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
+        fsBuilder->codeAppendf("\t\talpha *= (%s.y - %s.y) > -0.5 ? 1.0 : 0.0;\n", fragmentPos, rectName);
+        fsBuilder->codeAppendf("\t\talpha *= (%s.w - %s.y) > -0.5 ? 1.0 : 0.0;\n", rectName, fragmentPos);
     }
 
     if (GrEffectEdgeTypeIsInverseFill(aare.getEdgeType())) {
-        builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
+        fsBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n");
     }
-    builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
 }
 
@@ -181,7 +183,7 @@
 public:
     GrGLConvexPolyEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -205,7 +207,7 @@
     fPrevEdges[0] = SK_ScalarNaN;
 }
 
-void GrGLConvexPolyEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLConvexPolyEffect::emitCode(GrGLProgramBuilder* builder,
                                     const GrDrawEffect& drawEffect,
                                     const GrEffectKey& key,
                                     const char* outputColor,
@@ -215,34 +217,35 @@
     const GrConvexPolyEffect& cpe = drawEffect.castEffect<GrConvexPolyEffect>();
 
     const char *edgeArrayName;
-    fEdgeUniform = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
+    fEdgeUniform = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
                                             kVec3f_GrSLType,
                                             "edges",
                                             cpe.getEdgeCount(),
                                             &edgeArrayName);
-    builder->fsCodeAppend("\t\tfloat alpha = 1.0;\n");
-    builder->fsCodeAppend("\t\tfloat edge;\n");
-    const char* fragmentPos = builder->fragmentPosition();
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->codeAppend("\t\tfloat alpha = 1.0;\n");
+    fsBuilder->codeAppend("\t\tfloat edge;\n");
+    const char* fragmentPos = fsBuilder->fragmentPosition();
     for (int i = 0; i < cpe.getEdgeCount(); ++i) {
-        builder->fsCodeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n",
+        fsBuilder->codeAppendf("\t\tedge = dot(%s[%d], vec3(%s.x, %s.y, 1));\n",
                                edgeArrayName, i, fragmentPos, fragmentPos);
         if (GrEffectEdgeTypeIsAA(cpe.getEdgeType())) {
-            builder->fsCodeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n");
+            fsBuilder->codeAppend("\t\tedge = clamp(edge, 0.0, 1.0);\n");
         } else {
-            builder->fsCodeAppend("\t\tedge = edge >= 0.5 ? 1.0 : 0.0;\n");
+            fsBuilder->codeAppend("\t\tedge = edge >= 0.5 ? 1.0 : 0.0;\n");
         }
-        builder->fsCodeAppend("\t\talpha *= edge;\n");
+        fsBuilder->codeAppend("\t\talpha *= edge;\n");
     }
 
     // Woe is me. See skbug.com/2149.
     if (kTegra2_GrGLRenderer == builder->ctxInfo().renderer()) {
-        builder->fsCodeAppend("\t\tif (-1.0 == alpha) {\n\t\t\tdiscard;\n\t\t}\n");
+        fsBuilder->codeAppend("\t\tif (-1.0 == alpha) {\n\t\t\tdiscard;\n\t\t}\n");
     }
 
     if (GrEffectEdgeTypeIsInverseFill(cpe.getEdgeType())) {
-        builder->fsCodeAppend("\talpha = 1.0 - alpha;\n");
+        fsBuilder->codeAppend("\talpha = 1.0 - alpha;\n");
     }
-    builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
 }
 
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index e0cf35b..ba9f814 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -5,9 +5,9 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrConvolutionEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "GrTBackendEffectFactory.h"
@@ -19,7 +19,7 @@
 public:
     GrGLConvolutionEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -55,30 +55,32 @@
     fDirection = c.direction();
 }
 
-void GrGLConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLConvolutionEffect::emitCode(GrGLProgramBuilder* builder,
                                      const GrDrawEffect&,
                                      const GrEffectKey& key,
                                      const char* outputColor,
                                      const char* inputColor,
                                      const TransformedCoordsArray& coords,
                                      const TextureSamplerArray& samplers) {
-    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
-    fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec2f_GrSLType, "ImageIncrement");
     if (this->useBounds()) {
-        fBoundsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fBoundsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                          kVec2f_GrSLType, "Bounds");
     }
-    fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
+    fKernelUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
                                           kFloat_GrSLType, "Kernel", this->width());
 
-    builder->fsCodeAppendf("\t\t%s = vec4(0, 0, 0, 0);\n", outputColor);
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
+
+    fsBuilder->codeAppendf("\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);
 
-    builder->fsCodeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str(), fRadius, imgInc);
+    fsBuilder->codeAppendf("\t\tvec2 coord = %s - %d.0 * %s;\n", coords2D.c_str(), fRadius, imgInc);
 
     // Manually unroll loop because some drivers don't; yields 20-30% speedup.
     for (int i = 0; i < width; i++) {
@@ -86,21 +88,21 @@
         SkString kernelIndex;
         index.appendS32(i);
         kernel.appendArrayAccess(index.c_str(), &kernelIndex);
-        builder->fsCodeAppendf("\t\t%s += ", outputColor);
-        builder->fsAppendTextureLookup(samplers[0], "coord");
+        fsBuilder->codeAppendf("\t\t%s += ", outputColor);
+        fsBuilder->appendTextureLookup(samplers[0], "coord");
         if (this->useBounds()) {
             const char* bounds = builder->getUniformCStr(fBoundsUni);
             const char* component = this->direction() == Gr1DKernelEffect::kY_Direction ? "y" : "x";
-            builder->fsCodeAppendf(" * float(coord.%s >= %s.x && coord.%s <= %s.y)",
+            fsBuilder->codeAppendf(" * float(coord.%s >= %s.x && coord.%s <= %s.y)",
                 component, bounds, component, bounds);
         }
-        builder->fsCodeAppendf(" * %s;\n", kernelIndex.c_str());
-        builder->fsCodeAppendf("\t\tcoord += %s;\n", imgInc);
+        fsBuilder->codeAppendf(" * %s;\n", kernelIndex.c_str());
+        fsBuilder->codeAppendf("\t\tcoord += %s;\n", imgInc);
     }
 
     SkString modulate;
     GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
-    builder->fsCodeAppend(modulate.c_str());
+    fsBuilder->codeAppend(modulate.c_str());
 }
 
 void GrGLConvolutionEffect::setData(const GrGLProgramDataManager& pdman,
diff --git a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
index d235d5f..0401c6c 100644
--- a/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
+++ b/src/gpu/effects/GrCustomCoordsTextureEffect.cpp
@@ -5,9 +5,9 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrCustomCoordsTextureEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "gl/GrGLVertexEffect.h"
@@ -19,7 +19,7 @@
     GrGLCustomCoordsTextureEffect(const GrBackendEffectFactory& factory, const GrDrawEffect& drawEffect)
         : INHERITED (factory) {}
 
-    virtual void emitCode(GrGLFullShaderBuilder* builder,
+    virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -34,16 +34,18 @@
         builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsVaryingName, &fsVaryingNamePtr);
         fsCoordName = fsVaryingNamePtr;
 
-        const char* attrName =
-            builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str();
-        builder->vsCodeAppendf("\t%s = %s;\n", vsVaryingName, attrName);
+        GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+        const SkString* attr0Name =
+            vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+        vsBuilder->codeAppendf("\t%s = %s;\n", vsVaryingName, attr0Name->c_str());
 
-        builder->fsCodeAppendf("\t%s = ", outputColor);
-        builder->fsAppendTextureLookupAndModulate(inputColor,
+        GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+        fsBuilder->codeAppendf("\t%s = ", outputColor);
+        fsBuilder->appendTextureLookupAndModulate(inputColor,
                                                   samplers[0],
                                                   fsCoordName.c_str(),
                                                   kVec2f_GrSLType);
-        builder->fsCodeAppend(";\n");
+        fsBuilder->codeAppend(";\n");
     }
 
     virtual void setData(const GrGLProgramDataManager& pdman,
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp
index f3af65e..4b2bafe 100644
--- a/src/gpu/effects/GrDashingEffect.cpp
+++ b/src/gpu/effects/GrDashingEffect.cpp
@@ -5,6 +5,7 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrDashingEffect.h"
 
 #include "../GrAARectRenderer.h"
@@ -12,7 +13,6 @@
 #include "effects/GrVertexEffect.h"
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLVertexEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrContext.h"
 #include "GrCoordTransform.h"
@@ -468,7 +468,7 @@
 public:
     GLDashingCircleEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLFullShaderBuilder* builder,
+    virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -496,7 +496,7 @@
     fPrevIntervalLength = SK_ScalarMax;
 }
 
-void GLDashingCircleEffect::emitCode(GrGLFullShaderBuilder* builder,
+void GLDashingCircleEffect::emitCode(GrGLFullProgramBuilder* builder,
                                     const GrDrawEffect& drawEffect,
                                     const GrEffectKey& key,
                                     const char* outputColor,
@@ -507,32 +507,35 @@
     const char *paramName;
     // The param uniforms, xyz, refer to circle radius - 0.5, cicles center x coord, and
     // the total interval length of the dash.
-    fParamUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fParamUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                        kVec3f_GrSLType,
                                        "params",
                                        &paramName);
 
     const char *vsCoordName, *fsCoordName;
     builder->addVarying(kVec2f_GrSLType, "Coord", &vsCoordName, &fsCoordName);
+
+    GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
     const SkString* attr0Name =
-        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
+        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
 
     // transforms all points so that we can compare them to our test circle
-    builder->fsCodeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s.z) * %s.z;\n",
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s.z) * %s.z;\n",
                            fsCoordName, fsCoordName, paramName, paramName);
-    builder->fsCodeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", fsCoordName);
-    builder->fsCodeAppendf("\t\tvec2 center = vec2(%s.y, 0.0);\n", paramName);
-    builder->fsCodeAppend("\t\tfloat dist = length(center - fragPosShifted);\n");
+    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", fsCoordName);
+    fsBuilder->codeAppendf("\t\tvec2 center = vec2(%s.y, 0.0);\n", paramName);
+    fsBuilder->codeAppend("\t\tfloat dist = length(center - fragPosShifted);\n");
     if (GrEffectEdgeTypeIsAA(dce.getEdgeType())) {
-        builder->fsCodeAppendf("\t\tfloat diff = dist - %s.x;\n", paramName);
-        builder->fsCodeAppend("\t\tdiff = 1.0 - diff;\n");
-        builder->fsCodeAppend("\t\tfloat alpha = clamp(diff, 0.0, 1.0);\n");
+        fsBuilder->codeAppendf("\t\tfloat diff = dist - %s.x;\n", paramName);
+        fsBuilder->codeAppend("\t\tdiff = 1.0 - diff;\n");
+        fsBuilder->codeAppend("\t\tfloat alpha = clamp(diff, 0.0, 1.0);\n");
     } else {
-        builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n");
-        builder->fsCodeAppendf("\t\talpha *=  dist < %s.x + 0.5 ? 1.0 : 0.0;\n", paramName);
+        fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n");
+        fsBuilder->codeAppendf("\t\talpha *=  dist < %s.x + 0.5 ? 1.0 : 0.0;\n", paramName);
     }
-    builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
 }
 
@@ -673,7 +676,7 @@
 public:
     GLDashingLineEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLFullShaderBuilder* builder,
+    virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -700,7 +703,7 @@
     fPrevIntervalLength = SK_ScalarMax;
 }
 
-void GLDashingLineEffect::emitCode(GrGLFullShaderBuilder* builder,
+void GLDashingLineEffect::emitCode(GrGLFullProgramBuilder* builder,
                                     const GrDrawEffect& drawEffect,
                                     const GrEffectKey& key,
                                     const char* outputColor,
@@ -711,45 +714,47 @@
     const char *rectName;
     // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bottom - 0.5),
     // respectively.
-    fRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                        kVec4f_GrSLType,
                                        "rect",
                                        &rectName);
     const char *intervalName;
     // The interval uniform's refers to the total length of the interval (on + off)
-    fIntervalUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fIntervalUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                        kFloat_GrSLType,
                                        "interval",
                                        &intervalName);
 
     const char *vsCoordName, *fsCoordName;
     builder->addVarying(kVec2f_GrSLType, "Coord", &vsCoordName, &fsCoordName);
+    GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
     const SkString* attr0Name =
-        builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
-    builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
+        vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+    vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
 
     // transforms all points so that we can compare them to our test rect
-    builder->fsCodeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s) * %s;\n",
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    fsBuilder->codeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s) * %s;\n",
                            fsCoordName, fsCoordName, intervalName, intervalName);
-    builder->fsCodeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", fsCoordName);
+    fsBuilder->codeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", fsCoordName);
     if (GrEffectEdgeTypeIsAA(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.
-        builder->fsCodeAppend("\t\tfloat xSub, ySub;\n");
-        builder->fsCodeAppendf("\t\txSub = min(fragPosShifted.x - %s.x, 0.0);\n", rectName);
-        builder->fsCodeAppendf("\t\txSub += min(%s.z - fragPosShifted.x, 0.0);\n", rectName);
-        builder->fsCodeAppendf("\t\tySub = min(fragPosShifted.y - %s.y, 0.0);\n", rectName);
-        builder->fsCodeAppendf("\t\tySub += min(%s.w - fragPosShifted.y, 0.0);\n", rectName);
+        fsBuilder->codeAppend("\t\tfloat xSub, ySub;\n");
+        fsBuilder->codeAppendf("\t\txSub = min(fragPosShifted.x - %s.x, 0.0);\n", rectName);
+        fsBuilder->codeAppendf("\t\txSub += min(%s.z - fragPosShifted.x, 0.0);\n", rectName);
+        fsBuilder->codeAppendf("\t\tySub = min(fragPosShifted.y - %s.y, 0.0);\n", rectName);
+        fsBuilder->codeAppendf("\t\tySub += min(%s.w - fragPosShifted.y, 0.0);\n", rectName);
         // Now compute coverage in x and y and multiply them to get the fraction of the pixel
         // covered.
-        builder->fsCodeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
+        fsBuilder->codeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n");
     } else {
         // Assuming the bounding geometry is tight so no need to check y values
-        builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n");
-        builder->fsCodeAppendf("\t\talpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName);
-        builder->fsCodeAppendf("\t\talpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;\n", rectName);
+        fsBuilder->codeAppendf("\t\tfloat alpha = 1.0;\n");
+        fsBuilder->codeAppendf("\t\talpha *= (fragPosShifted.x - %s.x) > -0.5 ? 1.0 : 0.0;\n", rectName);
+        fsBuilder->codeAppendf("\t\talpha *= (%s.z - fragPosShifted.x) >= -0.5 ? 1.0 : 0.0;\n", rectName);
     }
-    builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
 }
 
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
index 7ef1cbb..eaaefeb 100755
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.cpp
@@ -5,9 +5,9 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrDistanceFieldTextureEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "gl/GrGLVertexEffect.h"
@@ -36,7 +36,7 @@
         : INHERITED (factory)
         , fTextureSize(SkISize::Make(-1,-1)) {}
 
-    virtual void emitCode(GrGLFullShaderBuilder* builder,
+    virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -45,7 +45,9 @@
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
         SkASSERT(1 == drawEffect.castEffect<GrDistanceFieldTextureEffect>().numVertexAttribs());
 
-        SkAssertResult(builder->enableFeature(GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
+        GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+        SkAssertResult(fsBuilder->enableFeature(
+                GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
         const GrDistanceFieldTextureEffect& dfTexEffect =
                                               drawEffect.castEffect<GrDistanceFieldTextureEffect>();
 
@@ -55,73 +57,74 @@
         builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
         fsCoordName = fsCoordNamePtr;
 
-        const char* attrName0 =
-            builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str();
-        builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attrName0);
+        GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+        const SkString* attr0Name =
+            vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+        vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
 
         const char* textureSizeUniName = NULL;
-        fTextureSizeUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                               kVec2f_GrSLType, "TextureSize",
                                               &textureSizeUniName);
 
-        builder->fsCodeAppend("\tvec4 texColor = ");
-        builder->fsAppendTextureLookup(samplers[0],
+        fsBuilder->codeAppend("\tvec4 texColor = ");
+        fsBuilder->appendTextureLookup(samplers[0],
                                        fsCoordName.c_str(),
                                        kVec2f_GrSLType);
-        builder->fsCodeAppend(";\n");
-        builder->fsCodeAppend("\tfloat distance = "
+        fsBuilder->codeAppend(";\n");
+        fsBuilder->codeAppend("\tfloat distance = "
                           SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ")"
                           "+ " SK_DistanceFieldNonLCDFactor ";\n");
 
         // 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.
-        builder->fsCodeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
-        builder->fsCodeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName);
-        builder->fsCodeAppend("\tfloat afwidth;\n");
+        fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
+        fsBuilder->codeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName);
+        fsBuilder->codeAppend("\tfloat afwidth;\n");
         if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
             // this gives us a smooth step across approximately one fragment
-            builder->fsCodeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dFdx(st.x);\n");
+            fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dFdx(st.x);\n");
         } else {
-            builder->fsCodeAppend("\tvec2 Jdx = dFdx(st);\n");
-            builder->fsCodeAppend("\tvec2 Jdy = dFdy(st);\n");
+            fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
+            fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
 
-            builder->fsCodeAppend("\tvec2 uv_grad;\n");
+            fsBuilder->codeAppend("\tvec2 uv_grad;\n");
             if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) {
                 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
-                builder->fsCodeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
-                builder->fsCodeAppend("\tif (uv_len2 < 0.0001) {\n");
-                builder->fsCodeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
-                builder->fsCodeAppend("\t} else {\n");
-                builder->fsCodeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
-                builder->fsCodeAppend("\t}\n");
+                fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
+                fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
+                fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
+                fsBuilder->codeAppend("\t} else {\n");
+                fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
+                fsBuilder->codeAppend("\t}\n");
             } else {
-                builder->fsCodeAppend("\tuv_grad = normalize(uv);\n");
+                fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
             }
-            builder->fsCodeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
-            builder->fsCodeAppend("\t                 uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
+            fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
+            fsBuilder->codeAppend("\t                 uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
 
             // this gives us a smooth step across approximately one fragment
-            builder->fsCodeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
+            fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
         }
-        builder->fsCodeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n");
+        fsBuilder->codeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n");
 
 #ifdef SK_GAMMA_APPLY_TO_A8
         // adjust based on gamma
         const char* luminanceUniName = NULL;
         // width, height, 1/(3*width)
-        fLuminanceUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fLuminanceUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                             kFloat_GrSLType, "Luminance",
                                             &luminanceUniName);
 
-        builder->fsCodeAppendf("\tuv = vec2(val, %s);\n", luminanceUniName);
-        builder->fsCodeAppend("\tvec4 gammaColor = ");
-        builder->fsAppendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
-        builder->fsCodeAppend(";\n");
-        builder->fsCodeAppend("\tval = gammaColor.r;\n");
+        fsBuilder->codeAppendf("\tuv = vec2(val, %s);\n", luminanceUniName);
+        fsBuilder->codeAppend("\tvec4 gammaColor = ");
+        fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
+        fsBuilder->codeAppend(";\n");
+        fsBuilder->codeAppend("\tval = gammaColor.r;\n");
 #endif
 
-        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+        fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("val")).c_str());
     }
 
@@ -261,7 +264,7 @@
     : INHERITED (factory)
     , fTextureSize(SkISize::Make(-1,-1)) {}
 
-    virtual void emitCode(GrGLFullShaderBuilder* builder,
+    virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -270,7 +273,6 @@
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
         SkASSERT(1 == drawEffect.castEffect<GrDistanceFieldLCDTextureEffect>().numVertexAttribs());
 
-        SkAssertResult(builder->enableFeature(GrGLShaderBuilder::kStandardDerivatives_GLSLFeature));
         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
                                            drawEffect.castEffect<GrDistanceFieldLCDTextureEffect>();
 
@@ -280,49 +282,55 @@
         builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
         fsCoordName = fsCoordNamePtr;
 
-        const char* attrName0 =
-                   builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str();
-        builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attrName0);
+        GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+        const SkString* attr0Name =
+            vsBuilder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
+        vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str());
 
         const char* textureSizeUniName = NULL;
         // width, height, 1/(3*width)
-        fTextureSizeUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                               kVec3f_GrSLType, "TextureSize",
                                               &textureSizeUniName);
 
+        GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+
+        SkAssertResult(fsBuilder->enableFeature(
+                GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
+
         // create LCD offset adjusted by inverse of transform
-        builder->fsCodeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
-        builder->fsCodeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName);
+        fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
+        fsBuilder->codeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName);
         bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
         if (isUniformScale) {
-            builder->fsCodeAppend("\tfloat dx = dFdx(st.x);\n");
-            builder->fsCodeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName);
+            fsBuilder->codeAppend("\tfloat dx = dFdx(st.x);\n");
+            fsBuilder->codeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName);
         } else {
-            builder->fsCodeAppend("\tvec2 Jdx = dFdx(st);\n");
-            builder->fsCodeAppend("\tvec2 Jdy = dFdy(st);\n");
-            builder->fsCodeAppendf("\tvec2 offset = %s.z*Jdx;\n", textureSizeUniName);
+            fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
+            fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
+            fsBuilder->codeAppendf("\tvec2 offset = %s.z*Jdx;\n", textureSizeUniName);
         }
 
         // green is distance to uv center
-        builder->fsCodeAppend("\tvec4 texColor = ");
-        builder->fsAppendTextureLookup(samplers[0], "uv", kVec2f_GrSLType);
-        builder->fsCodeAppend(";\n");
-        builder->fsCodeAppend("\tvec3 distance;\n");
-        builder->fsCodeAppend("\tdistance.y = texColor.r;\n");
+        fsBuilder->codeAppend("\tvec4 texColor = ");
+        fsBuilder->appendTextureLookup(samplers[0], "uv", kVec2f_GrSLType);
+        fsBuilder->codeAppend(";\n");
+        fsBuilder->codeAppend("\tvec3 distance;\n");
+        fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
         // red is distance to left offset
-        builder->fsCodeAppend("\tvec2 uv_adjusted = uv - offset;\n");
-        builder->fsCodeAppend("\ttexColor = ");
-        builder->fsAppendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
-        builder->fsCodeAppend(";\n");
-        builder->fsCodeAppend("\tdistance.x = texColor.r;\n");
+        fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
+        fsBuilder->codeAppend("\ttexColor = ");
+        fsBuilder->appendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
+        fsBuilder->codeAppend(";\n");
+        fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
         // blue is distance to right offset
-        builder->fsCodeAppend("\tuv_adjusted = uv + offset;\n");
-        builder->fsCodeAppend("\ttexColor = ");
-        builder->fsAppendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
-        builder->fsCodeAppend(";\n");
-        builder->fsCodeAppend("\tdistance.z = texColor.r;\n");
+        fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
+        fsBuilder->codeAppend("\ttexColor = ");
+        fsBuilder->appendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
+        fsBuilder->codeAppend(";\n");
+        fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
 
-        builder->fsCodeAppend("\tdistance = "
+        fsBuilder->codeAppend("\tdistance = "
             "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"))"
             "+ vec3(" SK_DistanceFieldLCDFactor ");\n");
 
@@ -334,58 +342,58 @@
         // for each color component. However, this is only important when using perspective
         // transformations, and even then using a single factor seems like a reasonable
         // trade-off between quality and speed.
-        builder->fsCodeAppend("\tfloat afwidth;\n");
+        fsBuilder->codeAppend("\tfloat afwidth;\n");
         if (isUniformScale) {
             // this gives us a smooth step across approximately one fragment
-            builder->fsCodeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dx;\n");
+            fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dx;\n");
         } else {
-            builder->fsCodeAppend("\tvec2 uv_grad;\n");
+            fsBuilder->codeAppend("\tvec2 uv_grad;\n");
             if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) {
                 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
-                builder->fsCodeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
-                builder->fsCodeAppend("\tif (uv_len2 < 0.0001) {\n");
-                builder->fsCodeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
-                builder->fsCodeAppend("\t} else {\n");
-                builder->fsCodeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
-                builder->fsCodeAppend("\t}\n");
+                fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
+                fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
+                fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
+                fsBuilder->codeAppend("\t} else {\n");
+                fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
+                fsBuilder->codeAppend("\t}\n");
             } else {
-                builder->fsCodeAppend("\tuv_grad = normalize(uv);\n");
+                fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
             }
-            builder->fsCodeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
-            builder->fsCodeAppend("\t                 uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
+            fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
+            fsBuilder->codeAppend("\t                 uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
 
             // this gives us a smooth step across approximately one fragment
-            builder->fsCodeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
+            fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
         }
 
-        builder->fsCodeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n");
+        fsBuilder->codeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n");
 
         // adjust based on gamma
         const char* textColorUniName = NULL;
         // width, height, 1/(3*width)
-        fTextColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        fTextColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                             kVec3f_GrSLType, "TextColor",
                                             &textColorUniName);
 
-        builder->fsCodeAppendf("\tuv = vec2(val.x, %s.x);\n", textColorUniName);
-        builder->fsCodeAppend("\tvec4 gammaColor = ");
-        builder->fsAppendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
-        builder->fsCodeAppend(";\n");
-        builder->fsCodeAppend("\tval.x = gammaColor.r;\n");
+        fsBuilder->codeAppendf("\tuv = vec2(val.x, %s.x);\n", textColorUniName);
+        fsBuilder->codeAppend("\tvec4 gammaColor = ");
+        fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
+        fsBuilder->codeAppend(";\n");
+        fsBuilder->codeAppend("\tval.x = gammaColor.r;\n");
 
-        builder->fsCodeAppendf("\tuv = vec2(val.y, %s.y);\n", textColorUniName);
-        builder->fsCodeAppend("\tgammaColor = ");
-        builder->fsAppendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
-        builder->fsCodeAppend(";\n");
-        builder->fsCodeAppend("\tval.y = gammaColor.r;\n");
+        fsBuilder->codeAppendf("\tuv = vec2(val.y, %s.y);\n", textColorUniName);
+        fsBuilder->codeAppend("\tgammaColor = ");
+        fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
+        fsBuilder->codeAppend(";\n");
+        fsBuilder->codeAppend("\tval.y = gammaColor.r;\n");
 
-        builder->fsCodeAppendf("\tuv = vec2(val.z, %s.z);\n", textColorUniName);
-        builder->fsCodeAppend("\tgammaColor = ");
-        builder->fsAppendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
-        builder->fsCodeAppend(";\n");
-        builder->fsCodeAppend("\tval.z = gammaColor.r;\n");
+        fsBuilder->codeAppendf("\tuv = vec2(val.z, %s.z);\n", textColorUniName);
+        fsBuilder->codeAppend("\tgammaColor = ");
+        fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
+        fsBuilder->codeAppend(";\n");
+        fsBuilder->codeAppend("\tval.z = gammaColor.r;\n");
 
-        builder->fsCodeAppendf("\t%s = %s;\n", outputColor,
+        fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
                                (GrGLSLExpr4(inputColor) * GrGLSLExpr4("val")).c_str());
     }
 
diff --git a/src/gpu/effects/GrDistanceFieldTextureEffect.h b/src/gpu/effects/GrDistanceFieldTextureEffect.h
index ab84753..dca1949 100644
--- a/src/gpu/effects/GrDistanceFieldTextureEffect.h
+++ b/src/gpu/effects/GrDistanceFieldTextureEffect.h
@@ -86,7 +86,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrEffect INHERITED;
 };
 
 /**
@@ -131,7 +131,7 @@
 
     GR_DECLARE_EFFECT_TEST;
 
-    typedef GrVertexEffect INHERITED;
+    typedef GrEffect INHERITED;
 };
 
 #endif
diff --git a/src/gpu/effects/GrDitherEffect.cpp b/src/gpu/effects/GrDitherEffect.cpp
index a431897..443df9e 100644
--- a/src/gpu/effects/GrDitherEffect.cpp
+++ b/src/gpu/effects/GrDitherEffect.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrDitherEffect.h"
 
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrTBackendEffectFactory.h"
 
@@ -70,7 +70,7 @@
 public:
     GLDitherEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -87,13 +87,14 @@
     : INHERITED (factory) {
 }
 
-void GLDitherEffect::emitCode(GrGLShaderBuilder* builder,
+void GLDitherEffect::emitCode(GrGLProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray&,
                               const TextureSamplerArray& samplers) {
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     // Generate a random number based on the fragment position. For this
     // random number generator, we use the "GLSL rand" function
     // that seems to be floating around on the internet. It works under
@@ -103,10 +104,10 @@
 
     // For each channel c, add the random offset to the pixel to either bump
     // it up or let it remain constant during quantization.
-    builder->fsCodeAppendf("\t\tfloat r = "
+    fsBuilder->codeAppendf("\t\tfloat r = "
                            "fract(sin(dot(%s.xy ,vec2(12.9898,78.233))) * 43758.5453);\n",
-                           builder->fragmentPosition());
-    builder->fsCodeAppendf("\t\t%s = (1.0/255.0) * vec4(r, r, r, r) + %s;\n",
+                           fsBuilder->fragmentPosition());
+    fsBuilder->codeAppendf("\t\t%s = (1.0/255.0) * vec4(r, r, r, r) + %s;\n",
                            outputColor, GrGLSLExpr4(inputColor).c_str());
 }
 
diff --git a/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
index 01cf944..e573996 100644
--- a/src/gpu/effects/GrMatrixConvolutionEffect.cpp
+++ b/src/gpu/effects/GrMatrixConvolutionEffect.cpp
@@ -4,8 +4,8 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrMatrixConvolutionEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLEffect.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
@@ -15,7 +15,7 @@
 public:
     GrGLMatrixConvolutionEffect(const GrBackendEffectFactory& factory,
                                 const GrDrawEffect& effect);
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -51,7 +51,7 @@
     fConvolveAlpha = m.convolveAlpha();
 }
 
-void GrGLMatrixConvolutionEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLMatrixConvolutionEffect::emitCode(GrGLProgramBuilder* builder,
                                            const GrDrawEffect& drawEffect,
                                            const GrEffectKey& key,
                                            const char* outputColor,
@@ -60,20 +60,20 @@
                                            const TextureSamplerArray& samplers) {
     sk_ignore_unused_variable(inputColor);
     const GrTextureDomain& domain = drawEffect.castEffect<GrMatrixConvolutionEffect>().domain();
-    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
-    fBoundsUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+
+    fBoundsUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                      kVec4f_GrSLType, "Bounds");
-    fImageIncrementUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fImageIncrementUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                              kVec2f_GrSLType, "ImageIncrement");
-    fKernelUni = builder->addUniformArray(GrGLShaderBuilder::kFragment_Visibility,
+    fKernelUni = builder->addUniformArray(GrGLProgramBuilder::kFragment_Visibility,
                                           kFloat_GrSLType,
                                           "Kernel",
                                           fKernelSize.width() * fKernelSize.height());
-    fKernelOffsetUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fKernelOffsetUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                            kVec2f_GrSLType, "KernelOffset");
-    fGainUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fGainUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                    kFloat_GrSLType, "Gain");
-    fBiasUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fBiasUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                    kFloat_GrSLType, "Bias");
 
     const char* kernelOffset = builder->getUniformCStr(fKernelOffsetUni);
@@ -84,38 +84,40 @@
     int kWidth = fKernelSize.width();
     int kHeight = fKernelSize.height();
 
-    builder->fsCodeAppend("vec4 sum = vec4(0, 0, 0, 0);");
-    builder->fsCodeAppendf("vec2 coord = %s - %s * %s;", coords2D.c_str(), kernelOffset,
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
+    fsBuilder->codeAppend("vec4 sum = vec4(0, 0, 0, 0);");
+    fsBuilder->codeAppendf("vec2 coord = %s - %s * %s;", coords2D.c_str(), kernelOffset,
                            imgInc);
-    builder->fsCodeAppend("vec4 c;");
+    fsBuilder->codeAppend("vec4 c;");
 
     for (int y = 0; y < kHeight; y++) {
         for (int x = 0; x < kWidth; x++) {
-            GrGLShaderBuilder::FSBlock block(builder);
-            builder->fsCodeAppendf("float k = %s[%d * %d + %d];", kernel, y, kWidth, x);
+            GrGLShaderBuilder::ShaderBlock block(fsBuilder);
+            fsBuilder->codeAppendf("float k = %s[%d * %d + %d];", kernel, y, kWidth, x);
             SkString coord;
             coord.printf("coord + vec2(%d, %d) * %s", x, y, imgInc);
-            fDomain.sampleTexture(builder, domain, "c", coord, samplers[0]);
+            fDomain.sampleTexture(fsBuilder, domain, "c", coord, samplers[0]);
             if (!fConvolveAlpha) {
-                builder->fsCodeAppend("c.rgb /= c.a;");
+                fsBuilder->codeAppend("c.rgb /= c.a;");
             }
-            builder->fsCodeAppend("sum += c * k;");
+            fsBuilder->codeAppend("sum += c * k;");
         }
     }
     if (fConvolveAlpha) {
-        builder->fsCodeAppendf("%s = sum * %s + %s;", outputColor, gain, bias);
-        builder->fsCodeAppendf("%s.rgb = clamp(%s.rgb, 0.0, %s.a);",
+        fsBuilder->codeAppendf("%s = sum * %s + %s;", outputColor, gain, bias);
+        fsBuilder->codeAppendf("%s.rgb = clamp(%s.rgb, 0.0, %s.a);",
                                outputColor, outputColor, outputColor);
     } else {
-        fDomain.sampleTexture(builder, domain, "c", coords2D, samplers[0]);
-        builder->fsCodeAppendf("%s.a = c.a;", outputColor);
-        builder->fsCodeAppendf("%s.rgb = sum.rgb * %s + %s;", outputColor, gain, bias);
-        builder->fsCodeAppendf("%s.rgb *= %s.a;", outputColor, outputColor);
+        fDomain.sampleTexture(fsBuilder, domain, "c", coords2D, samplers[0]);
+        fsBuilder->codeAppendf("%s.a = c.a;", outputColor);
+        fsBuilder->codeAppendf("%s.rgb = sum.rgb * %s + %s;", outputColor, gain, bias);
+        fsBuilder->codeAppendf("%s.rgb *= %s.a;", outputColor, outputColor);
     }
 
     SkString modulate;
     GrGLSLMulVarBy4f(&modulate, 2, outputColor, inputColor);
-    builder->fsCodeAppend(modulate.c_str());
+    fsBuilder->codeAppend(modulate.c_str());
 }
 
 void GrGLMatrixConvolutionEffect::GenKey(const GrDrawEffect& drawEffect,
diff --git a/src/gpu/effects/GrOvalEffect.cpp b/src/gpu/effects/GrOvalEffect.cpp
index d915250..369b780 100644
--- a/src/gpu/effects/GrOvalEffect.cpp
+++ b/src/gpu/effects/GrOvalEffect.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrOvalEffect.h"
 
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrTBackendEffectFactory.h"
 
@@ -100,7 +100,7 @@
 public:
     GLCircleEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -126,7 +126,7 @@
     fPrevRadius = -1.f;
 }
 
-void GLCircleEffect::emitCode(GrGLShaderBuilder* builder,
+void GLCircleEffect::emitCode(GrGLProgramBuilder* builder,
                               const GrDrawEffect& drawEffect,
                               const GrEffectKey& key,
                               const char* outputColor,
@@ -137,27 +137,29 @@
     const char *circleName;
     // The circle uniform is (center.x, center.y, radius + 0.5) for regular fills and
     // (... ,radius - 0.5) for inverse fills.
-    fCircleUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fCircleUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                          kVec3f_GrSLType,
                                          "circle",
                                          &circleName);
-    const char* fragmentPos = builder->fragmentPosition();
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    const char* fragmentPos = fsBuilder->fragmentPosition();
 
     SkASSERT(kHairlineAA_GrEffectEdgeType != ce.getEdgeType());
     if (GrEffectEdgeTypeIsInverseFill(ce.getEdgeType())) {
-        builder->fsCodeAppendf("\t\tfloat d = length(%s.xy - %s.xy) - %s.z;\n",
+        fsBuilder->codeAppendf("\t\tfloat d = length(%s.xy - %s.xy) - %s.z;\n",
                                 circleName, fragmentPos, circleName);
     } else {
-        builder->fsCodeAppendf("\t\tfloat d = %s.z - length(%s.xy - %s.xy);\n",
+        fsBuilder->codeAppendf("\t\tfloat d = %s.z - length(%s.xy - %s.xy);\n",
                                circleName, fragmentPos, circleName);
     }
     if (GrEffectEdgeTypeIsAA(ce.getEdgeType())) {
-        builder->fsCodeAppend("\t\td = clamp(d, 0.0, 1.0);\n");
+        fsBuilder->codeAppend("\t\td = clamp(d, 0.0, 1.0);\n");
     } else {
-        builder->fsCodeAppend("\t\td = d > 0.5 ? 1.0 : 0.0;\n");
+        fsBuilder->codeAppend("\t\td = d > 0.5 ? 1.0 : 0.0;\n");
     }
 
-    builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("d")).c_str());
 }
 
@@ -272,7 +274,7 @@
 public:
     GLEllipseEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -298,7 +300,7 @@
     fPrevRadii.fX = -1.f;
 }
 
-void GLEllipseEffect::emitCode(GrGLShaderBuilder* builder,
+void GLEllipseEffect::emitCode(GrGLProgramBuilder* builder,
                                const GrDrawEffect& drawEffect,
                                const GrEffectKey& key,
                                const char* outputColor,
@@ -308,41 +310,43 @@
     const EllipseEffect& ee = drawEffect.castEffect<EllipseEffect>();
     const char *ellipseName;
     // The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2)
-    fEllipseUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fEllipseUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                          kVec4f_GrSLType,
                                          "ellipse",
                                          &ellipseName);
-    const char* fragmentPos = builder->fragmentPosition();
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    const char* fragmentPos = fsBuilder->fragmentPosition();
 
     // d is the offset to the ellipse center
-    builder->fsCodeAppendf("\t\tvec2 d = %s.xy - %s.xy;\n", fragmentPos, ellipseName);
-    builder->fsCodeAppendf("\t\tvec2 Z = d * %s.zw;\n", ellipseName);
+    fsBuilder->codeAppendf("\t\tvec2 d = %s.xy - %s.xy;\n", fragmentPos, ellipseName);
+    fsBuilder->codeAppendf("\t\tvec2 Z = d * %s.zw;\n", ellipseName);
     // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
-    builder->fsCodeAppend("\t\tfloat implicit = dot(Z, d) - 1.0;\n");
+    fsBuilder->codeAppend("\t\tfloat implicit = dot(Z, d) - 1.0;\n");
     // grad_dot is the squared length of the gradient of the implicit.
-    builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
+    fsBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
     // avoid calling inversesqrt on zero.
-    builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
-    builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
+    fsBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
+    fsBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
 
     switch (ee.getEdgeType()) {
         case kFillAA_GrEffectEdgeType:
-            builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
+            fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
             break;
         case kInverseFillAA_GrEffectEdgeType:
-            builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
+            fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
             break;
         case kFillBW_GrEffectEdgeType:
-            builder->fsCodeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n");
+            fsBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n");
             break;
         case kInverseFillBW_GrEffectEdgeType:
-            builder->fsCodeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 1.0 : 0.0;\n");
+            fsBuilder->codeAppend("\t\tfloat alpha = approx_dist > 0.0 ? 1.0 : 0.0;\n");
             break;
         case kHairlineAA_GrEffectEdgeType:
             SkFAIL("Hairline not expected here.");
     }
 
-    builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
 }
 
diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp
index 5a2b0c3..8a3fc44 100644
--- a/src/gpu/effects/GrRRectEffect.cpp
+++ b/src/gpu/effects/GrRRectEffect.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrRRectEffect.h"
 
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "GrConvexPolyEffect.h"
 #include "GrOvalEffect.h"
@@ -134,7 +134,7 @@
 public:
     GLCircularRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -159,7 +159,7 @@
     fPrevRRect.setEmpty();
 }
 
-void GLCircularRRectEffect::emitCode(GrGLShaderBuilder* builder,
+void GLCircularRRectEffect::emitCode(GrGLProgramBuilder* builder,
                              const GrDrawEffect& drawEffect,
                              const GrEffectKey& key,
                              const char* outputColor,
@@ -173,15 +173,17 @@
     // edges correspond to components x, y, z, and w, respectively. When a side of the rrect has
     // only rectangular corners, that side's value corresponds to the rect edge's value outset by
     // half a pixel.
-    fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fInnerRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                             kVec4f_GrSLType,
                                             "innerRect",
                                             &rectName);
-    fRadiusPlusHalfUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fRadiusPlusHalfUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                  kFloat_GrSLType,
                                                  "radiusPlusHalf",
                                                  &radiusPlusHalfName);
-    const char* fragmentPos = builder->fragmentPosition();
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    const char* fragmentPos = fsBuilder->fragmentPosition();
     // At each quarter-circle corner we compute a vector that is the offset of the fragment position
     // from the circle center. The vector is pinned in x and y to be in the quarter-plane relevant
     // to that corner. This means that points near the interior near the rrect top edge will have
@@ -199,95 +201,95 @@
     // alphas together.
     switch (crre.getCircularCornerFlags()) {
         case CircularRRectEffect::kAll_CornerFlags:
-            builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
-            builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
-            builder->fsCodeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
+            fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
+            fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
+            fsBuilder->codeAppendf("\t\tfloat alpha = clamp(%s - length(dxy), 0.0, 1.0);\n",
                                    radiusPlusHalfName);
             break;
         case CircularRRectEffect::kTopLeft_CornerFlag:
-            builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n",
+            fsBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.xy, 0.0);\n",
                                    rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
                                     rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
                                     rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat alpha = bottomAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
                                    radiusPlusHalfName);
             break;
         case CircularRRectEffect::kTopRight_CornerFlag:
-            builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n",
+            fsBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.z, %s.y - %s.y), 0.0);\n",
                                    fragmentPos, rectName, rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
                                    fragmentPos, rectName);
-            builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
                                     rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat alpha = bottomAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
                                    radiusPlusHalfName);
             break;
         case CircularRRectEffect::kBottomRight_CornerFlag:
-            builder->fsCodeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n",
+            fsBuilder->codeAppendf("\t\tvec2 dxy = max(%s.xy - %s.zw, 0.0);\n",
                                    fragmentPos, rectName);
-            builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
                                    fragmentPos, rectName);
-            builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
                                    fragmentPos, rectName);
-            builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
                                    radiusPlusHalfName);
             break;
         case CircularRRectEffect::kBottomLeft_CornerFlag:
-            builder->fsCodeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n",
+            fsBuilder->codeAppendf("\t\tvec2 dxy = max(vec2(%s.x - %s.x, %s.y - %s.w), 0.0);\n",
                                    rectName, fragmentPos, fragmentPos, rectName);
-            builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
                                     rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
                                    fragmentPos, rectName);
-            builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
                                    radiusPlusHalfName);
             break;
         case CircularRRectEffect::kLeft_CornerFlags:
-            builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName);
-            builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n");
-            builder->fsCodeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
+            fsBuilder->codeAppendf("\t\tfloat dy1 = %s.y - %s.w;\n", fragmentPos, rectName);
+            fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy0.x, max(dxy0.y, dy1)), 0.0);\n");
+            fsBuilder->codeAppendf("\t\tfloat rightAlpha = clamp(%s.z - %s.x, 0.0, 1.0);\n",
                                     rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat alpha = rightAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
                                    radiusPlusHalfName);
             break;
         case CircularRRectEffect::kTop_CornerFlags:
-            builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName);
-            builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n");
-            builder->fsCodeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
+            fsBuilder->codeAppendf("\t\tfloat dx1 = %s.x - %s.z;\n", fragmentPos, rectName);
+            fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dxy0.x, dx1), dxy0.y), 0.0);\n");
+            fsBuilder->codeAppendf("\t\tfloat bottomAlpha = clamp(%s.w - %s.y, 0.0, 1.0);\n",
                                    rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat alpha = bottomAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
                                    radiusPlusHalfName);
             break;
         case CircularRRectEffect::kRight_CornerFlags:
-            builder->fsCodeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
-            builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n");
-            builder->fsCodeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat dy0 = %s.y - %s.y;\n", rectName, fragmentPos);
+            fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
+            fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(dxy1.x, max(dy0, dxy1.y)), 0.0);\n");
+            fsBuilder->codeAppendf("\t\tfloat leftAlpha = clamp(%s.x - %s.x, 0.0, 1.0);\n",
                                    fragmentPos, rectName);
-            builder->fsCodeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat alpha = leftAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
                                    radiusPlusHalfName);
             break;
         case CircularRRectEffect::kBottom_CornerFlags:
-            builder->fsCodeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos);
-            builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
-            builder->fsCodeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n");
-            builder->fsCodeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat dx0 = %s.x - %s.x;\n", rectName, fragmentPos);
+            fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
+            fsBuilder->codeAppend("\t\tvec2 dxy = max(vec2(max(dx0, dxy1.x), dxy1.y), 0.0);\n");
+            fsBuilder->codeAppendf("\t\tfloat topAlpha = clamp(%s.y - %s.y, 0.0, 1.0);\n",
                                    fragmentPos, rectName);
-            builder->fsCodeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
+            fsBuilder->codeAppendf("\t\tfloat alpha = topAlpha * clamp(%s - length(dxy), 0.0, 1.0);\n",
                                    radiusPlusHalfName);
             break;
     }
 
     if (kInverseFillAA_GrEffectEdgeType == crre.getEdgeType()) {
-        builder->fsCodeAppend("\t\talpha = 1.0 - alpha;\n");
+        fsBuilder->codeAppend("\t\talpha = 1.0 - alpha;\n");
     }
 
-    builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
 }
 
@@ -486,7 +488,7 @@
 public:
     GLEllipticalRRectEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
@@ -511,7 +513,7 @@
     fPrevRRect.setEmpty();
 }
 
-void GLEllipticalRRectEffect::emitCode(GrGLShaderBuilder* builder,
+void GLEllipticalRRectEffect::emitCode(GrGLProgramBuilder* builder,
                                        const GrDrawEffect& drawEffect,
                                        const GrEffectKey& key,
                                        const char* outputColor,
@@ -521,11 +523,13 @@
     const EllipticalRRectEffect& erre = drawEffect.castEffect<EllipticalRRectEffect>();
     const char *rectName;
     // The inner rect is the rrect bounds inset by the x/y radii
-    fInnerRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+    fInnerRectUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                             kVec4f_GrSLType,
                                             "innerRect",
                                             &rectName);
-    const char* fragmentPos = builder->fragmentPosition();
+
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    const char* fragmentPos = fsBuilder->fragmentPosition();
     // At each quarter-ellipse corner we compute a vector that is the offset of the fragment pos
     // to the ellipse center. The vector is pinned in x and y to be in the quarter-plane relevant
     // to that corner. This means that points near the interior near the rrect top edge will have
@@ -537,31 +541,31 @@
     // The code below is a simplified version of the above that performs maxs on the vector
     // components before computing distances and alpha values so that only one distance computation
     // need be computed to determine the min alpha.
-    builder->fsCodeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
-    builder->fsCodeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
+    fsBuilder->codeAppendf("\t\tvec2 dxy0 = %s.xy - %s.xy;\n", rectName, fragmentPos);
+    fsBuilder->codeAppendf("\t\tvec2 dxy1 = %s.xy - %s.zw;\n", fragmentPos, rectName);
     switch (erre.getRRect().getType()) {
         case SkRRect::kSimple_Type: {
             const char *invRadiiXYSqdName;
-            fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+            fInvRadiiSqdUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                       kVec2f_GrSLType,
                                                       "invRadiiXY",
                                                       &invRadiiXYSqdName);
-            builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
+            fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
             // Z is the x/y offsets divided by squared radii.
-            builder->fsCodeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
+            fsBuilder->codeAppendf("\t\tvec2 Z = dxy * %s;\n", invRadiiXYSqdName);
             break;
         }
         case SkRRect::kNinePatch_Type: {
             const char *invRadiiLTRBSqdName;
-            fInvRadiiSqdUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+            fInvRadiiSqdUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                       kVec4f_GrSLType,
                                                       "invRadiiLTRB",
                                                       &invRadiiLTRBSqdName);
-            builder->fsCodeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
+            fsBuilder->codeAppend("\t\tvec2 dxy = max(max(dxy0, dxy1), 0.0);\n");
             // Z is the x/y offsets divided by squared radii. We only care about the (at most) one
             // corner where both the x and y offsets are positive, hence the maxes. (The inverse
             // squared radii will always be positive.)
-            builder->fsCodeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
+            fsBuilder->codeAppendf("\t\tvec2 Z = max(max(dxy0 * %s.xy, dxy1 * %s.zw), 0.0);\n",
                                    invRadiiLTRBSqdName, invRadiiLTRBSqdName);
             break;
         }
@@ -569,20 +573,20 @@
             SkFAIL("RRect should always be simple or nine-patch.");
     }
     // implicit is the evaluation of (x/a)^2 + (y/b)^2 - 1.
-    builder->fsCodeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
+    fsBuilder->codeAppend("\t\tfloat implicit = dot(Z, dxy) - 1.0;\n");
     // grad_dot is the squared length of the gradient of the implicit.
-    builder->fsCodeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
+    fsBuilder->codeAppendf("\t\tfloat grad_dot = 4.0 * dot(Z, Z);\n");
     // avoid calling inversesqrt on zero.
-    builder->fsCodeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
-    builder->fsCodeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
+    fsBuilder->codeAppend("\t\tgrad_dot = max(grad_dot, 1.0e-4);\n");
+    fsBuilder->codeAppendf("\t\tfloat approx_dist = implicit * inversesqrt(grad_dot);\n");
 
     if (kFillAA_GrEffectEdgeType == erre.getEdgeType()) {
-        builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
+        fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 - approx_dist, 0.0, 1.0);\n");
     } else {
-        builder->fsCodeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
+        fsBuilder->codeAppend("\t\tfloat alpha = clamp(0.5 + approx_dist, 0.0, 1.0);\n");
     }
 
-    builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor,
+    fsBuilder->codeAppendf("\t\t%s = %s;\n", outputColor,
                            (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str());
 }
 
diff --git a/src/gpu/effects/GrSimpleTextureEffect.cpp b/src/gpu/effects/GrSimpleTextureEffect.cpp
index 74926bc..fe55ce9 100644
--- a/src/gpu/effects/GrSimpleTextureEffect.cpp
+++ b/src/gpu/effects/GrSimpleTextureEffect.cpp
@@ -5,9 +5,9 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrSimpleTextureEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "GrTBackendEffectFactory.h"
@@ -19,19 +19,20 @@
         : INHERITED (factory) {
     }
 
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
                           const char* inputColor,
                           const TransformedCoordsArray& coords,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        builder->fsCodeAppendf("\t%s = ", outputColor);
-        builder->fsAppendTextureLookupAndModulate(inputColor,
+        GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+        fsBuilder->codeAppendf("\t%s = ", outputColor);
+        fsBuilder->appendTextureLookupAndModulate(inputColor,
                                                   samplers[0],
                                                   coords[0].c_str(),
                                                   coords[0].type());
-        builder->fsCodeAppend(";\n");
+        fsBuilder->codeAppend(";\n");
     }
 
 private:
diff --git a/src/gpu/effects/GrTextureDomain.cpp b/src/gpu/effects/GrTextureDomain.cpp
index 2bad5e8..40006a3 100644
--- a/src/gpu/effects/GrTextureDomain.cpp
+++ b/src/gpu/effects/GrTextureDomain.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrTextureDomain.h"
 #include "GrSimpleTextureEffect.h"
 #include "GrTBackendEffectFactory.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "SkFloatingPoint.h"
 
 
@@ -49,23 +49,25 @@
     SkASSERT((Mode)-1 == fMode || textureDomain.mode() == fMode);
     SkDEBUGCODE(fMode = textureDomain.mode();)
 
+    GrGLProgramBuilder* program = builder->getProgramBuilder();
+
     if (textureDomain.mode() != kIgnore_Mode && !fDomainUni.isValid()) {
         const char* name;
         SkString uniName("TexDom");
         if (textureDomain.fIndex >= 0) {
             uniName.appendS32(textureDomain.fIndex);
         }
-        fDomainUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
-                                         kVec4f_GrSLType, uniName.c_str(), &name);
+        fDomainUni = program->addUniform(GrGLProgramBuilder::kFragment_Visibility, kVec4f_GrSLType,
+                uniName.c_str(), &name);
         fDomainName = name;
     }
 
     switch (textureDomain.mode()) {
         case kIgnore_Mode: {
-            builder->fsCodeAppendf("\t%s = ", outColor);
-            builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler,
+            builder->codeAppendf("\t%s = ", outColor);
+            builder->appendTextureLookupAndModulate(inModulateColor, sampler,
                                                       inCoords.c_str());
-            builder->fsCodeAppend(";\n");
+            builder->codeAppend(";\n");
             break;
         }
         case kClamp_Mode: {
@@ -73,49 +75,49 @@
             clampedCoords.appendf("\tclamp(%s, %s.xy, %s.zw)",
                                   inCoords.c_str(), fDomainName.c_str(), fDomainName.c_str());
 
-            builder->fsCodeAppendf("\t%s = ", outColor);
-            builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler,
+            builder->codeAppendf("\t%s = ", outColor);
+            builder->appendTextureLookupAndModulate(inModulateColor, sampler,
                                                       clampedCoords.c_str());
-            builder->fsCodeAppend(";\n");
+            builder->codeAppend(";\n");
             break;
         }
         case kDecal_Mode: {
             // Add a block since we're going to declare variables.
-            GrGLShaderBuilder::FSBlock block(builder);
+            GrGLShaderBuilder::ShaderBlock block(builder);
 
             const char* domain = fDomainName.c_str();
-            if (kImagination_GrGLVendor == builder->ctxInfo().vendor()) {
+            if (kImagination_GrGLVendor == program->ctxInfo().vendor()) {
                 // On the NexusS and GalaxyNexus, the other path (with the 'any'
                 // call) causes the compilation error "Calls to any function that
                 // may require a gradient calculation inside a conditional block
                 // 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->fsCodeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n");
-                builder->fsCodeAppend("\tvec4 inside = ");
-                builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler,
+                builder->codeAppend("\tvec4 outside = vec4(0.0, 0.0, 0.0, 0.0);\n");
+                builder->codeAppend("\tvec4 inside = ");
+                builder->appendTextureLookupAndModulate(inModulateColor, sampler,
                                                           inCoords.c_str());
-                builder->fsCodeAppend(";\n");
-                builder->fsCodeAppendf("\tfloat x = (%s).x;\n", inCoords.c_str());
-                builder->fsCodeAppendf("\tfloat y = (%s).y;\n", inCoords.c_str());
+                builder->codeAppend(";\n");
+                builder->codeAppendf("\tfloat x = (%s).x;\n", inCoords.c_str());
+                builder->codeAppendf("\tfloat y = (%s).y;\n", inCoords.c_str());
 
-                builder->fsCodeAppendf("\tx = abs(2.0*(x - %s.x)/(%s.z - %s.x) - 1.0);\n",
+                builder->codeAppendf("\tx = abs(2.0*(x - %s.x)/(%s.z - %s.x) - 1.0);\n",
                                        domain, domain, domain);
-                builder->fsCodeAppendf("\ty = abs(2.0*(y - %s.y)/(%s.w - %s.y) - 1.0);\n",
+                builder->codeAppendf("\ty = abs(2.0*(y - %s.y)/(%s.w - %s.y) - 1.0);\n",
                                        domain, domain, domain);
-                builder->fsCodeAppend("\tfloat blend = step(1.0, max(x, y));\n");
-                builder->fsCodeAppendf("\t%s = mix(inside, outside, blend);\n", outColor);
+                builder->codeAppend("\tfloat blend = step(1.0, max(x, y));\n");
+                builder->codeAppendf("\t%s = mix(inside, outside, blend);\n", outColor);
             } else {
-                builder->fsCodeAppend("\tbvec4 outside;\n");
-                builder->fsCodeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", inCoords.c_str(),
+                builder->codeAppend("\tbvec4 outside;\n");
+                builder->codeAppendf("\toutside.xy = lessThan(%s, %s.xy);\n", inCoords.c_str(),
                                        domain);
-                builder->fsCodeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", inCoords.c_str(),
+                builder->codeAppendf("\toutside.zw = greaterThan(%s, %s.zw);\n", inCoords.c_str(),
                                        domain);
-                builder->fsCodeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ",
+                builder->codeAppendf("\t%s = any(outside) ? vec4(0.0, 0.0, 0.0, 0.0) : ",
                                        outColor);
-                builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler,
+                builder->appendTextureLookupAndModulate(inModulateColor, sampler,
                                                           inCoords.c_str());
-                builder->fsCodeAppend(";\n");
+                builder->codeAppend(";\n");
             }
             break;
         }
@@ -125,10 +127,10 @@
                                  inCoords.c_str(), fDomainName.c_str(), fDomainName.c_str(),
                                  fDomainName.c_str(), fDomainName.c_str());
 
-            builder->fsCodeAppendf("\t%s = ", outColor);
-            builder->fsAppendTextureLookupAndModulate(inModulateColor, sampler,
+            builder->codeAppendf("\t%s = ", outColor);
+            builder->appendTextureLookupAndModulate(inModulateColor, sampler,
                                                       clampedCoords.c_str());
-            builder->fsCodeAppend(";\n");
+            builder->codeAppend(";\n");
             break;
         }
     }
@@ -167,7 +169,7 @@
 public:
     GrGLTextureDomainEffect(const GrBackendEffectFactory&, const GrDrawEffect&);
 
-    virtual void emitCode(GrGLShaderBuilder*,
+    virtual void emitCode(GrGLProgramBuilder*,
                           const GrDrawEffect&,
                           const GrEffectKey&,
                           const char* outputColor,
@@ -189,7 +191,7 @@
     : INHERITED(factory) {
 }
 
-void GrGLTextureDomainEffect::emitCode(GrGLShaderBuilder* builder,
+void GrGLTextureDomainEffect::emitCode(GrGLProgramBuilder* builder,
                                        const GrDrawEffect& drawEffect,
                                        const GrEffectKey& key,
                                        const char* outputColor,
@@ -199,8 +201,9 @@
     const GrTextureDomainEffect& effect = drawEffect.castEffect<GrTextureDomainEffect>();
     const GrTextureDomain& domain = effect.textureDomain();
 
-    SkString coords2D = builder->ensureFSCoords2D(coords, 0);
-    fGLDomain.sampleTexture(builder, domain, outputColor, coords2D, samplers[0], inputColor);
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    SkString coords2D = fsBuilder->ensureFSCoords2D(coords, 0);
+    fGLDomain.sampleTexture(fsBuilder, domain, outputColor, coords2D, samplers[0], inputColor);
 }
 
 void GrGLTextureDomainEffect::setData(const GrGLProgramDataManager& pdman,
diff --git a/src/gpu/effects/GrTextureDomain.h b/src/gpu/effects/GrTextureDomain.h
index 577098a..6cb5ad4 100644
--- a/src/gpu/effects/GrTextureDomain.h
+++ b/src/gpu/effects/GrTextureDomain.h
@@ -11,6 +11,7 @@
 #include "GrSingleTextureEffect.h"
 #include "gl/GrGLEffect.h"
 
+class GrGLProgramBuilder;
 class GrGLShaderBuilder;
 struct SkRect;
 
diff --git a/src/gpu/effects/GrYUVtoRGBEffect.cpp b/src/gpu/effects/GrYUVtoRGBEffect.cpp
index 15e51a2..41d75c3 100644
--- a/src/gpu/effects/GrYUVtoRGBEffect.cpp
+++ b/src/gpu/effects/GrYUVtoRGBEffect.cpp
@@ -5,12 +5,12 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrYUVtoRGBEffect.h"
 
 #include "GrCoordTransform.h"
 #include "GrEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "GrTBackendEffectFactory.h"
 
 namespace {
@@ -44,26 +44,27 @@
         : INHERITED(factory) {
         }
 
-        virtual void emitCode(GrGLShaderBuilder* builder,
+        virtual void emitCode(GrGLProgramBuilder* builder,
                               const GrDrawEffect&,
                               const GrEffectKey&,
                               const char* outputColor,
                               const char* inputColor,
                               const TransformedCoordsArray& coords,
                               const TextureSamplerArray& samplers) SK_OVERRIDE {
+            GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
             const char* yuvMatrix   = "yuvMatrix";
-            builder->fsCodeAppendf("\tconst mat4 %s = mat4(1.0,  0.0,    1.402, -0.701,\n\t\t\t"
+            fsBuilder->codeAppendf("\tconst mat4 %s = mat4(1.0,  0.0,    1.402, -0.701,\n\t\t\t"
                                                           "1.0, -0.344, -0.714,  0.529,\n\t\t\t"
                                                           "1.0,  1.772,  0.0,   -0.886,\n\t\t\t"
                                                           "0.0,  0.0,    0.0,    1.0);\n",
                                    yuvMatrix);
-            builder->fsCodeAppendf("\t%s = vec4(\n\t\t", outputColor);
-            builder->fsAppendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
-            builder->fsCodeAppend(".r,\n\t\t");
-            builder->fsAppendTextureLookup(samplers[1], coords[0].c_str(), coords[0].type());
-            builder->fsCodeAppend(".r,\n\t\t");
-            builder->fsAppendTextureLookup(samplers[2], coords[0].c_str(), coords[0].type());
-            builder->fsCodeAppendf(".r,\n\t\t1.0) * %s;\n", yuvMatrix);
+            fsBuilder->codeAppendf("\t%s = vec4(\n\t\t", outputColor);
+            fsBuilder->appendTextureLookup(samplers[0], coords[0].c_str(), coords[0].type());
+            fsBuilder->codeAppend(".r,\n\t\t");
+            fsBuilder->appendTextureLookup(samplers[1], coords[0].c_str(), coords[0].type());
+            fsBuilder->codeAppend(".r,\n\t\t");
+            fsBuilder->appendTextureLookup(samplers[2], coords[0].c_str(), coords[0].type());
+            fsBuilder->codeAppendf(".r,\n\t\t1.0) * %s;\n", yuvMatrix);
         }
 
         typedef GrGLEffect INHERITED;
diff --git a/src/gpu/gl/GrGLEffect.h b/src/gpu/gl/GrGLEffect.h
index 18b3002..88aa4cd 100644
--- a/src/gpu/gl/GrGLEffect.h
+++ b/src/gpu/gl/GrGLEffect.h
@@ -68,7 +68,7 @@
                             GrGLEffect. These can be passed to the builder to emit texture
                             reads in the generated code.
         */
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index d8c751d..d49d000 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -24,13 +24,12 @@
                                  const GrGLProgramDesc& desc,
                                  const GrEffectStage* colorStages[],
                                  const GrEffectStage* coverageStages[]) {
-    SkAutoTDelete<GrGLShaderBuilder> builder;
+    SkAutoTDelete<GrGLProgramBuilder> builder;
     if (desc.getHeader().fHasVertexCode ||!gpu->shouldUseFixedFunctionTexturing()) {
-        builder.reset(SkNEW_ARGS(GrGLFullShaderBuilder, (gpu, desc)));
+        builder.reset(SkNEW_ARGS(GrGLFullProgramBuilder, (gpu, desc)));
     } else {
-        builder.reset(SkNEW_ARGS(GrGLFragmentOnlyShaderBuilder, (gpu, desc)));
+        builder.reset(SkNEW_ARGS(GrGLFragmentOnlyProgramBuilder, (gpu, desc)));
     }
-
     if (builder->genProgram(colorStages, coverageStages)) {
         SkASSERT(0 != builder->getProgramID());
         return SkNEW_ARGS(GrGLProgram, (gpu, desc, *builder));
@@ -40,7 +39,7 @@
 
 GrGLProgram::GrGLProgram(GrGpuGL* gpu,
                          const GrGLProgramDesc& desc,
-                         const GrGLShaderBuilder& builder)
+                         const GrGLProgramBuilder& builder)
     : fColor(GrColor_ILLEGAL)
     , fCoverage(GrColor_ILLEGAL)
     , fDstCopyTexUnit(-1)
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index fb49685..7af55f1 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -9,10 +9,10 @@
 #ifndef GrGLProgram_DEFINED
 #define GrGLProgram_DEFINED
 
+#include "builders/GrGLProgramBuilder.h"
 #include "GrDrawState.h"
 #include "GrGLContext.h"
 #include "GrGLProgramDesc.h"
-#include "GrGLShaderBuilder.h"
 #include "GrGLSL.h"
 #include "GrGLTexture.h"
 #include "GrGLProgramDataManager.h"
@@ -22,7 +22,7 @@
 
 class GrGLEffect;
 class GrGLProgramEffects;
-class GrGLShaderBuilder;
+class GrGLProgramBuilder;
 
 /**
  * This class manages a GPU program and records per-program information.
@@ -37,7 +37,7 @@
 public:
     SK_DECLARE_INST_COUNT(GrGLProgram)
 
-    typedef GrGLShaderBuilder::BuiltinUniformHandles BuiltinUniformHandles;
+    typedef GrGLProgramBuilder::BuiltinUniformHandles BuiltinUniformHandles;
 
     static GrGLProgram* Create(GrGpuGL* gpu,
                                const GrGLProgramDesc& desc,
@@ -167,7 +167,7 @@
 
     GrGLProgram(GrGpuGL*,
                 const GrGLProgramDesc&,
-                const GrGLShaderBuilder&);
+                const GrGLProgramBuilder&);
 
     // Sets the texture units for samplers.
     void initSamplerUniforms();
diff --git a/src/gpu/gl/GrGLProgramDataManager.cpp b/src/gpu/gl/GrGLProgramDataManager.cpp
index c4c5193..eed9d19 100644
--- a/src/gpu/gl/GrGLProgramDataManager.cpp
+++ b/src/gpu/gl/GrGLProgramDataManager.cpp
@@ -5,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-#include "gl/GrGLShaderBuilder.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "gl/GrGLProgram.h"
 #include "gl/GrGLUniformHandle.h"
 #include "gl/GrGpuGL.h"
@@ -17,13 +17,13 @@
 
 GrGLProgramDataManager::GrGLProgramDataManager(GrGpuGL* gpu,
                                                GrGLProgram*,
-                                               const GrGLShaderBuilder& builder)
+                                               const GrGLProgramBuilder& builder)
     : fGpu(gpu) {
     int count = builder.getUniformInfos().count();
     fUniforms.push_back_n(count);
     for (int i = 0; i < count; i++) {
         Uniform& uniform = fUniforms[i];
-        const GrGLShaderBuilder::UniformInfo& builderUniform = builder.getUniformInfos()[i];
+        const GrGLProgramBuilder::UniformInfo& builderUniform = builder.getUniformInfos()[i];
         SkASSERT(GrGLShaderVar::kNonArray == builderUniform.fVariable.getArrayCount() ||
                  builderUniform.fVariable.getArrayCount() > 0);
         SkDEBUGCODE(
@@ -32,12 +32,12 @@
         );
         // TODO: Move the Xoom uniform array in both FS and VS bug workaround here.
 
-        if (GrGLShaderBuilder::kVertex_Visibility & builderUniform.fVisibility) {
+        if (GrGLProgramBuilder::kVertex_Visibility & builderUniform.fVisibility) {
             uniform.fVSLocation = builderUniform.fLocation;
         } else {
             uniform.fVSLocation = kUnusedUniform;
             }
-        if (GrGLShaderBuilder::kFragment_Visibility & builderUniform.fVisibility) {
+        if (GrGLProgramBuilder::kFragment_Visibility & builderUniform.fVisibility) {
             uniform.fFSLocation = builderUniform.fLocation;
         } else {
             uniform.fFSLocation = kUnusedUniform;
diff --git a/src/gpu/gl/GrGLProgramDataManager.h b/src/gpu/gl/GrGLProgramDataManager.h
index 8ef4a41..3082f6f0 100644
--- a/src/gpu/gl/GrGLProgramDataManager.h
+++ b/src/gpu/gl/GrGLProgramDataManager.h
@@ -17,7 +17,7 @@
 class GrGpuGL;
 class SkMatrix;
 class GrGLProgram;
-class GrGLShaderBuilder;
+class GrGLProgramBuilder;
 
 /** Manages the resources used by a shader program.
  * The resources are objects the program uses to communicate with the
@@ -51,10 +51,10 @@
 
         int fValue;
         friend class GrGLProgramDataManager; // For accessing toProgramDataIndex().
-        friend class GrGLShaderBuilder; // For accessing toShaderBuilderIndex().
+        friend class GrGLProgramBuilder; // For accessing toShaderBuilderIndex().
     };
 
-    GrGLProgramDataManager(GrGpuGL*, GrGLProgram*, const GrGLShaderBuilder&);
+    GrGLProgramDataManager(GrGpuGL*, GrGLProgram*, const GrGLProgramBuilder&);
 
     /** Functions for uploading uniform values. The varities ending in v can be used to upload to an
      *  array of uniforms. arrayCount must be <= the array count of the uniform.
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index e1a3191..7cdbcd0 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -5,11 +5,11 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrGLProgramDesc.h"
 #include "GrBackendEffectFactory.h"
 #include "GrDrawEffect.h"
 #include "GrEffect.h"
-#include "GrGLShaderBuilder.h"
 #include "GrGpuGL.h"
 
 #include "SkChecksum.h"
@@ -212,15 +212,16 @@
         if (NULL != dstCopy) {
             dstCopyTexture = dstCopy->texture();
         }
-        header->fDstReadKey = GrGLShaderBuilder::KeyForDstRead(dstCopyTexture, gpu->glCaps());
+        header->fDstReadKey = GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
+                gpu->glCaps());
         SkASSERT(0 != header->fDstReadKey);
     } else {
         header->fDstReadKey = 0;
     }
 
     if (readFragPosition) {
-        header->fFragPosKey = GrGLShaderBuilder::KeyForFragmentPosition(drawState.getRenderTarget(),
-                                                                      gpu->glCaps());
+        header->fFragPosKey = GrGLFragmentShaderBuilder::KeyForFragmentPosition(
+                drawState.getRenderTarget(), gpu->glCaps());
     } else {
         header->fFragPosKey = 0;
     }
diff --git a/src/gpu/gl/GrGLProgramDesc.h b/src/gpu/gl/GrGLProgramDesc.h
index cccdee9..e8925d0 100644
--- a/src/gpu/gl/GrGLProgramDesc.h
+++ b/src/gpu/gl/GrGLProgramDesc.h
@@ -252,9 +252,12 @@
     // part of GrGLShaderBuilder that is used by effects so that this header doesn't need to be
     // visible to GrGLEffects. Then make public accessors as necessary and remove friends.
     friend class GrGLProgram;
-    friend class GrGLShaderBuilder;
-    friend class GrGLFullShaderBuilder;
-    friend class GrGLFragmentOnlyShaderBuilder;
+    friend class GrGLProgramBuilder;
+    friend class GrGLFullProgramBuilder;
+    friend class GrGLFragmentOnlyProgramBuilder;
+    friend class GrGLVertexShaderBuilder;
+    friend class GrGLFragmentShaderBuilder;
+    friend class GrGLGeometryShaderBuilder;
 };
 
 #endif
diff --git a/src/gpu/gl/GrGLProgramEffects.cpp b/src/gpu/gl/GrGLProgramEffects.cpp
index 8ea77d0..efb64fe 100644
--- a/src/gpu/gl/GrGLProgramEffects.cpp
+++ b/src/gpu/gl/GrGLProgramEffects.cpp
@@ -5,10 +5,10 @@
  * found in the LICENSE file.
  */
 
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "GrGLProgramEffects.h"
 #include "GrDrawEffect.h"
 #include "gl/GrGLEffect.h"
-#include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLVertexEffect.h"
 #include "gl/GrGpuGL.h"
 
@@ -204,7 +204,7 @@
     }
 }
 
-void GrGLProgramEffects::emitSamplers(GrGLShaderBuilder* builder,
+void GrGLProgramEffects::emitSamplers(GrGLProgramBuilder* builder,
                                       const GrEffect* effect,
                                       TextureSamplerArray* outSamplers) {
     SkTArray<Sampler, true>& samplers = fSamplers.push_back();
@@ -213,7 +213,7 @@
     SkString name;
     for (int t = 0; t < numTextures; ++t) {
         name.printf("Sampler%d", t);
-        samplers[t].fUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility,
+        samplers[t].fUniform = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
                                                    kSampler2D_GrSLType,
                                                    name.c_str());
         SkNEW_APPEND_TO_TARRAY(outSamplers, TextureSampler,
@@ -250,7 +250,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrGLVertexProgramEffects::emitEffect(GrGLFullShaderBuilder* builder,
+void GrGLVertexProgramEffects::emitEffect(GrGLFullProgramBuilder* builder,
                                           const GrEffectStage& stage,
                                           const GrEffectKey& key,
                                           const char* outColor,
@@ -261,7 +261,9 @@
     SkSTArray<2, TransformedCoords> coords(effect->numTransforms());
     SkSTArray<4, TextureSampler> samplers(effect->numTextures());
 
-    this->emitAttributes(builder, stage);
+    GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
+    vsBuilder->emitAttributes(stage);
     this->emitTransforms(builder, drawEffect, &coords);
     this->emitSamplers(builder, effect, &samplers);
 
@@ -271,8 +273,8 @@
     // Enclose custom code in a block to avoid namespace conflicts
     SkString openBrace;
     openBrace.printf("\t{ // Stage %d: %s\n", stageIndex, glEffect->name());
-    builder->vsCodeAppend(openBrace.c_str());
-    builder->fsCodeAppend(openBrace.c_str());
+    fsBuilder->codeAppend(openBrace.c_str());
+    vsBuilder->codeAppend(openBrace.c_str());
 
     if (glEffect->isVertexEffect()) {
         GrGLVertexEffect* vertexEffect = static_cast<GrGLVertexEffect*>(glEffect);
@@ -281,25 +283,11 @@
         glEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers);
     }
 
-    builder->vsCodeAppend("\t}\n");
-    builder->fsCodeAppend("\t}\n");
+    vsBuilder->codeAppend("\t}\n");
+    fsBuilder->codeAppend("\t}\n");
 }
 
-void GrGLVertexProgramEffects::emitAttributes(GrGLFullShaderBuilder* builder,
-                                              const GrEffectStage& stage) {
-    int numAttributes = stage.getVertexAttribIndexCount();
-    const int* attributeIndices = stage.getVertexAttribIndices();
-    for (int a = 0; a < numAttributes; ++a) {
-        // TODO: Make addAttribute mangle the name.
-        SkString attributeName("aAttr");
-        attributeName.appendS32(attributeIndices[a]);
-        builder->addEffectAttribute(attributeIndices[a],
-                                    stage.getEffect()->vertexAttribType(a),
-                                    attributeName);
-    }
-}
-
-void GrGLVertexProgramEffects::emitTransforms(GrGLFullShaderBuilder* builder,
+void GrGLVertexProgramEffects::emitTransforms(GrGLFullProgramBuilder* builder,
                                               const GrDrawEffect& drawEffect,
                                               TransformedCoordsArray* outCoords) {
     SkTArray<Transform, true>& transforms = fTransforms.push_back();
@@ -327,7 +315,7 @@
             suffixedUniName.appendf("_%i", t);
             uniName = suffixedUniName.c_str();
         }
-        transforms[t].fHandle = builder->addUniform(GrGLShaderBuilder::kVertex_Visibility,
+        transforms[t].fHandle = builder->addUniform(GrGLProgramBuilder::kVertex_Visibility,
                                                     kMat33f_GrSLType,
                                                     uniName,
                                                     &uniName);
@@ -341,18 +329,19 @@
         }
         const char* vsVaryingName;
         const char* fsVaryingName;
+        GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
         builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
 
         const GrGLShaderVar& coords = kPosition_GrCoordSet == get_source_coords(totalKey, t) ?
-                                          builder->positionAttribute() :
-                                          builder->localCoordsAttribute();
+                                          vsBuilder->positionAttribute() :
+                                          vsBuilder->localCoordsAttribute();
         // varying = matrix * coords (logically)
         SkASSERT(kVec2f_GrSLType == varyingType || kVec3f_GrSLType == varyingType);
         if (kVec2f_GrSLType == varyingType) {
-            builder->vsCodeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
+            vsBuilder->codeAppendf("\t%s = (%s * vec3(%s, 1)).xy;\n",
                                    vsVaryingName, uniName, coords.c_str());
         } else {
-            builder->vsCodeAppendf("\t%s = %s * vec3(%s, 1);\n",
+            vsBuilder->codeAppendf("\t%s = %s * vec3(%s, 1);\n",
                                    vsVaryingName, uniName, coords.c_str());
         }
         SkNEW_APPEND_TO_TARRAY(outCoords, TransformedCoords,
@@ -390,13 +379,13 @@
     }
 }
 
-GrGLVertexProgramEffectsBuilder::GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder* builder,
+GrGLVertexProgramEffectsBuilder::GrGLVertexProgramEffectsBuilder(GrGLFullProgramBuilder* builder,
                                                                  int reserveCount)
     : fBuilder(builder)
     , fProgramEffects(SkNEW_ARGS(GrGLVertexProgramEffects,
-                                 (reserveCount, fBuilder->hasExplicitLocalCoords()))) {
+                                 (reserveCount,
+                                  fBuilder->getVertexShaderBuilder()->hasExplicitLocalCoords()))) {
 }
-
 void GrGLVertexProgramEffectsBuilder::emitEffect(const GrEffectStage& stage,
                                                  const GrEffectKey& key,
                                                  const char* outColor,
@@ -408,7 +397,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrGLPathTexGenProgramEffects::emitEffect(GrGLFragmentOnlyShaderBuilder* builder,
+void GrGLPathTexGenProgramEffects::emitEffect(GrGLFragmentOnlyProgramBuilder* builder,
                                           const GrEffectStage& stage,
                                           const GrEffectKey& key,
                                           const char* outColor,
@@ -426,18 +415,19 @@
     GrGLEffect* glEffect = effect->getFactory().createGLInstance(drawEffect);
     fGLEffects.push_back(glEffect);
 
+    GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
     // Enclose custom code in a block to avoid namespace conflicts
     SkString openBrace;
     openBrace.printf("\t{ // Stage %d: %s\n", stageIndex, glEffect->name());
-    builder->fsCodeAppend(openBrace.c_str());
+    fsBuilder->codeAppend(openBrace.c_str());
 
     SkASSERT(!glEffect->isVertexEffect());
     glEffect->emitCode(builder, drawEffect, key, outColor, inColor, coords, samplers);
 
-    builder->fsCodeAppend("\t}\n");
+    fsBuilder->codeAppend("\t}\n");
 }
 
-void GrGLPathTexGenProgramEffects::setupPathTexGen(GrGLFragmentOnlyShaderBuilder* builder,
+void GrGLPathTexGenProgramEffects::setupPathTexGen(GrGLFragmentOnlyProgramBuilder* builder,
                                            const GrDrawEffect& drawEffect,
                                            TransformedCoordsArray* outCoords) {
     int numTransforms = drawEffect.effect()->numTransforms();
@@ -499,12 +489,11 @@
 }
 
 GrGLPathTexGenProgramEffectsBuilder::GrGLPathTexGenProgramEffectsBuilder(
-        GrGLFragmentOnlyShaderBuilder* builder,
+        GrGLFragmentOnlyProgramBuilder* builder,
         int reserveCount)
     : fBuilder(builder)
     , fProgramEffects(SkNEW_ARGS(GrGLPathTexGenProgramEffects, (reserveCount))) {
 }
-
 void GrGLPathTexGenProgramEffectsBuilder::emitEffect(const GrEffectStage& stage,
                                                      const GrEffectKey& key,
                                                      const char* outColor,
@@ -513,3 +502,4 @@
     SkASSERT(NULL != fProgramEffects.get());
     fProgramEffects->emitEffect(fBuilder, stage, key, outColor, inColor, stageIndex);
 }
+
diff --git a/src/gpu/gl/GrGLProgramEffects.h b/src/gpu/gl/GrGLProgramEffects.h
index 7ae925b..e4d84a0 100644
--- a/src/gpu/gl/GrGLProgramEffects.h
+++ b/src/gpu/gl/GrGLProgramEffects.h
@@ -16,9 +16,9 @@
 class GrEffect;
 class GrEffectStage;
 class GrGLVertexProgramEffectsBuilder;
-class GrGLShaderBuilder;
-class GrGLFullShaderBuilder;
-class GrGLFragmentOnlyShaderBuilder;
+class GrGLProgramBuilder;
+class GrGLFullProgramBuilder;
+class GrGLFragmentOnlyProgramBuilder;
 
 /**
  * This class encapsulates an array of GrGLEffects and their supporting data (coord transforms
@@ -54,6 +54,8 @@
                          const GrGLProgramDataManager&,
                          const GrEffectStage* effectStages[]) = 0;
 
+    void addEffect(GrGLEffect* effect) { fGLEffects.push_back(effect); }
+
     /**
      * Passed to GrGLEffects so they can add transformed coordinates to their shader code.
      */
@@ -100,6 +102,7 @@
     typedef SkTArray<TextureSampler> TextureSamplerArray;
 
 protected:
+
     /**
      * Helpers for GenEffectMetaKey.
      */
@@ -117,7 +120,7 @@
      * appends the necessary data to the TextureSamplerArray* object so effects can add texture
      * lookups to their code. This method is only meant to be called during the construction phase.
      */
-    void emitSamplers(GrGLShaderBuilder*, const GrEffect*, TextureSamplerArray*);
+    void emitSamplers(GrGLProgramBuilder*, const GrEffect*, TextureSamplerArray*);
 
     /**
      * Helper for setData(). Binds all the textures for an effect.
@@ -134,6 +137,7 @@
     SkTArray<SkSTArray<4, Sampler, true> > fSamplers;
 
 private:
+    friend class GrGLFragmentO;
     typedef SkRefCnt INHERITED;
 };
 
@@ -143,7 +147,6 @@
 class GrGLProgramEffectsBuilder {
 public:
     virtual ~GrGLProgramEffectsBuilder() { }
-
     /**
      * Emits the effect's shader code, and stores the necessary uniforms internally.
      */
@@ -166,19 +169,17 @@
                          const GrEffectStage* effectStages[]) SK_OVERRIDE;
 
 private:
-    friend class GrGLVertexProgramEffectsBuilder;
+    friend class GrGLFullProgramBuilder;
 
     GrGLVertexProgramEffects(int reserveCount, bool explicitLocalCoords)
         : INHERITED(reserveCount)
         , fTransforms(reserveCount)
         , fHasExplicitLocalCoords(explicitLocalCoords) {
     }
-
     /**
-     * Helper for GrGLProgramEffectsBuilder::emitEfffect(). This method is meant to only be called
-     * during the construction phase.
+     * This method is meant to only be called during the construction phase.
      */
-    void emitEffect(GrGLFullShaderBuilder*,
+    void emitEffect(GrGLFullProgramBuilder*,
                     const GrEffectStage&,
                     const GrEffectKey&,
                     const char* outColor,
@@ -188,7 +189,7 @@
     /**
      * Helper for emitEffect(). Emits any attributes an effect may have.
      */
-    void emitAttributes(GrGLFullShaderBuilder*, const GrEffectStage&);
+    void emitAttributes(GrGLFullProgramBuilder*, const GrEffectStage&);
 
     /**
      * Helper for emitEffect(). Emits code to implement an effect's coord transforms in the VS.
@@ -197,7 +198,7 @@
      * of the varyings in the VS and FS as well their types are appended to the
      * TransformedCoordsArray* object, which is in turn passed to the effect's emitCode() function.
      */
-    void emitTransforms(GrGLFullShaderBuilder*,
+    void emitTransforms(GrGLFullProgramBuilder*,
                         const GrDrawEffect&,
                         TransformedCoordsArray*);
 
@@ -215,6 +216,8 @@
     SkTArray<SkSTArray<2, Transform, true> > fTransforms;
     bool                                     fHasExplicitLocalCoords;
 
+    friend class GrGLVertexProgramEffectsBuilder;
+
     typedef GrGLProgramEffects INHERITED;
 };
 
@@ -223,25 +226,21 @@
  */
 class GrGLVertexProgramEffectsBuilder : public GrGLProgramEffectsBuilder {
 public:
-    GrGLVertexProgramEffectsBuilder(GrGLFullShaderBuilder*, int reserveCount);
+    GrGLVertexProgramEffectsBuilder(GrGLFullProgramBuilder*, int reserveCount);
     virtual ~GrGLVertexProgramEffectsBuilder() { }
-
     virtual void emitEffect(const GrEffectStage&,
                             const GrEffectKey&,
                             const char* outColor,
                             const char* inColor,
                             int stageIndex) SK_OVERRIDE;
-
     /**
      * Finalizes the building process and returns the effect array. After this call, the builder
      * becomes invalid.
      */
     GrGLProgramEffects* finish() { return fProgramEffects.detach(); }
-
 private:
-    GrGLFullShaderBuilder*                  fBuilder;
+    GrGLFullProgramBuilder*                 fBuilder;
     SkAutoTDelete<GrGLVertexProgramEffects> fProgramEffects;
-
     typedef GrGLProgramEffectsBuilder INHERITED;
 };
 
@@ -258,7 +257,7 @@
                          const GrEffectStage* effectStages[]) SK_OVERRIDE;
 
 private:
-    friend class GrGLPathTexGenProgramEffectsBuilder;
+    friend class GrGLFragmentOnlyProgramBuilder;
 
     GrGLPathTexGenProgramEffects(int reserveCount)
         : INHERITED(reserveCount)
@@ -266,10 +265,9 @@
     }
 
     /**
-     * Helper for GrGLProgramEffectsBuilder::emitEfffect(). This method is meant to only be called
-     * during the construction phase.
+     * This method is meant to only be called during the construction phase.
      */
-    void emitEffect(GrGLFragmentOnlyShaderBuilder*,
+    void emitEffect(GrGLFragmentOnlyProgramBuilder*,
                     const GrEffectStage&,
                     const GrEffectKey&,
                     const char* outColor,
@@ -284,7 +282,7 @@
      * types are appended to the TransformedCoordsArray* object, which is in turn passed to the
      * effect's emitCode() function.
      */
-    void setupPathTexGen(GrGLFragmentOnlyShaderBuilder*,
+    void setupPathTexGen(GrGLFragmentOnlyProgramBuilder*,
                          const GrDrawEffect&,
                          TransformedCoordsArray*);
 
@@ -302,6 +300,7 @@
 
     SkTArray<Transforms> fTransforms;
 
+    friend class GrGLPathTexGenProgramEffectsBuilder;
     typedef GrGLProgramEffects INHERITED;
 };
 
@@ -310,26 +309,23 @@
  */
 class GrGLPathTexGenProgramEffectsBuilder : public GrGLProgramEffectsBuilder {
 public:
-    GrGLPathTexGenProgramEffectsBuilder(GrGLFragmentOnlyShaderBuilder*, int reserveCount);
+    GrGLPathTexGenProgramEffectsBuilder(GrGLFragmentOnlyProgramBuilder*, int reserveCount);
     virtual ~GrGLPathTexGenProgramEffectsBuilder() { }
-
     virtual void emitEffect(const GrEffectStage&,
                             const GrEffectKey&,
                             const char* outColor,
                             const char* inColor,
                             int stageIndex) SK_OVERRIDE;
-
     /**
      * Finalizes the building process and returns the effect array. After this call, the builder
      * becomes invalid.
      */
     GrGLProgramEffects* finish() { return fProgramEffects.detach(); }
-
 private:
-    GrGLFragmentOnlyShaderBuilder*          fBuilder;
+    GrGLFragmentOnlyProgramBuilder*          fBuilder;
     SkAutoTDelete<GrGLPathTexGenProgramEffects> fProgramEffects;
-
     typedef GrGLProgramEffectsBuilder INHERITED;
 };
 
+
 #endif
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
deleted file mode 100644
index 9fffd26..0000000
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ /dev/null
@@ -1,1071 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "gl/GrGLShaderBuilder.h"
-#include "gl/GrGLProgram.h"
-#include "gl/GrGLSLPrettyPrint.h"
-#include "gl/GrGLUniformHandle.h"
-#include "GrCoordTransform.h"
-#include "GrDrawEffect.h"
-#include "GrGpuGL.h"
-#include "GrTexture.h"
-#include "SkRTConf.h"
-#include "SkTraceEvent.h"
-
-#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
-#define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
-
-// number of each input/output type in a single allocation block
-static const int kVarsPerBlock = 8;
-
-// except FS outputs where we expect 2 at most.
-static const int kMaxFSOutputs = 2;
-
-// ES2 FS only guarantees mediump and lowp support
-static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
-
-typedef GrGLProgramDataManager::UniformHandle UniformHandle;
-
-SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false,
-                "Print the source code for all shaders generated.");
-
-///////////////////////////////////////////////////////////////////////////////
-
-namespace {
-
-inline const char* color_attribute_name() { return "aColor"; }
-inline const char* coverage_attribute_name() { return "aCoverage"; }
-inline const char* declared_color_output_name() { return "fsColorOut"; }
-inline const char* dual_source_output_name() { return "dualSourceOut"; }
-inline const char* sample_function_name(GrSLType type, GrGLSLGeneration glslGen) {
-    if (kVec2f_GrSLType == type) {
-        return glslGen >= k130_GrGLSLGeneration ? "texture" : "texture2D";
-    } else {
-        SkASSERT(kVec3f_GrSLType == type);
-        return glslGen >= k130_GrGLSLGeneration ? "textureProj" : "texture2DProj";
-    }
-}
-
-void append_texture_lookup(SkString* out,
-                           GrGpuGL* gpu,
-                           const char* samplerName,
-                           const char* coordName,
-                           uint32_t configComponentMask,
-                           const char* swizzle,
-                           GrSLType varyingType = kVec2f_GrSLType) {
-    SkASSERT(NULL != coordName);
-
-    out->appendf("%s(%s, %s)",
-                 sample_function_name(varyingType, gpu->glslGeneration()),
-                 samplerName,
-                 coordName);
-
-    char mangledSwizzle[5];
-
-    // The swizzling occurs using texture params instead of shader-mangling if ARB_texture_swizzle
-    // is available.
-    if (!gpu->glCaps().textureSwizzleSupport() &&
-        (kA_GrColorComponentFlag == configComponentMask)) {
-        char alphaChar = gpu->glCaps().textureRedSupport() ? 'r' : 'a';
-        int i;
-        for (i = 0; '\0' != swizzle[i]; ++i) {
-            mangledSwizzle[i] = alphaChar;
-        }
-        mangledSwizzle[i] ='\0';
-        swizzle = mangledSwizzle;
-    }
-    // For shader prettiness we omit the swizzle rather than appending ".rgba".
-    if (memcmp(swizzle, "rgba", 4)) {
-        out->appendf(".%s", swizzle);
-    }
-}
-
-}
-
-static const char kDstCopyColorName[] = "_dstColor";
-
-///////////////////////////////////////////////////////////////////////////////
-
-bool GrGLShaderBuilder::genProgram(const GrEffectStage* colorStages[],
-                                   const GrEffectStage* coverageStages[]) {
-    const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
-
-    ///////////////////////////////////////////////////////////////////////////
-    // emit code to read the dst copy texture, if necessary
-    if (kNoDstRead_DstReadKey != header.fDstReadKey && !fGpu->glCaps().fbFetchSupport()) {
-        bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey);
-        const char* dstCopyTopLeftName;
-        const char* dstCopyCoordScaleName;
-        const char* dstCopySamplerName;
-        uint32_t configMask;
-        if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) {
-            configMask = kA_GrColorComponentFlag;
-        } else {
-            configMask = kRGBA_GrColorComponentFlags;
-        }
-        fUniformHandles.fDstCopySamplerUni =
-            this->addUniform(kFragment_Visibility, kSampler2D_GrSLType, "DstCopySampler",
-                             &dstCopySamplerName);
-        fUniformHandles.fDstCopyTopLeftUni =
-            this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyUpperLeft",
-                             &dstCopyTopLeftName);
-        fUniformHandles.fDstCopyScaleUni =
-            this->addUniform(kFragment_Visibility, kVec2f_GrSLType, "DstCopyCoordScale",
-                             &dstCopyCoordScaleName);
-        const char* fragPos = this->fragmentPosition();
-        this->fsCodeAppend("\t// Read color from copy of the destination.\n");
-        this->fsCodeAppendf("\tvec2 _dstTexCoord = (%s.xy - %s) * %s;\n",
-                            fragPos, dstCopyTopLeftName, dstCopyCoordScaleName);
-        if (!topDown) {
-            this->fsCodeAppend("\t_dstTexCoord.y = 1.0 - _dstTexCoord.y;\n");
-        }
-        this->fsCodeAppendf("\tvec4 %s = ", kDstCopyColorName);
-        append_texture_lookup(&fFSCode,
-                              fGpu,
-                              dstCopySamplerName,
-                              "_dstTexCoord",
-                              configMask,
-                              "rgba");
-        this->fsCodeAppend(";\n\n");
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // get the initial color and coverage to feed into the first effect in each effect chain
-
-    GrGLSLExpr4 inputColor;
-    GrGLSLExpr4 inputCoverage;
-
-    if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) {
-        const char* name;
-        fUniformHandles.fColorUni =
-            this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Color",
-                             &name);
-        inputColor = GrGLSLExpr4(name);
-    }
-
-    if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
-        const char* name;
-        fUniformHandles.fCoverageUni =
-            this->addUniform(GrGLShaderBuilder::kFragment_Visibility, kVec4f_GrSLType, "Coverage",
-                             &name);
-        inputCoverage = GrGLSLExpr4(name);
-    } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fCoverageInput) {
-        inputCoverage = GrGLSLExpr4(1);
-    }
-
-    if (k110_GrGLSLGeneration != fGpu->glslGeneration()) {
-        fFSOutputs.push_back().set(kVec4f_GrSLType,
-                                   GrGLShaderVar::kOut_TypeModifier,
-                                   declared_color_output_name());
-        fHasCustomColorOutput = true;
-    }
-
-    this->emitCodeBeforeEffects(&inputColor, &inputCoverage);
-
-    ///////////////////////////////////////////////////////////////////////////
-    // emit the per-effect code for both color and coverage effects
-
-    GrGLProgramDesc::EffectKeyProvider colorKeyProvider(
-        &this->desc(), GrGLProgramDesc::EffectKeyProvider::kColor_EffectType);
-    fColorEffects.reset(this->createAndEmitEffects(colorStages,
-                                                   this->desc().numColorEffects(),
-                                                   colorKeyProvider,
-                                                   &inputColor));
-
-    GrGLProgramDesc::EffectKeyProvider coverageKeyProvider(
-        &this->desc(), GrGLProgramDesc::EffectKeyProvider::kCoverage_EffectType);
-    fCoverageEffects.reset(this->createAndEmitEffects(coverageStages,
-                                                      this->desc().numCoverageEffects(),
-                                                      coverageKeyProvider,
-                                                      &inputCoverage));
-
-    this->emitCodeAfterEffects();
-
-    ///////////////////////////////////////////////////////////////////////////
-    // write the secondary color output if necessary
-    if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) {
-        const char* secondaryOutputName = this->enableSecondaryOutput();
-
-        // default coeff to ones for kCoverage_DualSrcOutput
-        GrGLSLExpr4 coeff(1);
-        if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) {
-            // Get (1-A) into coeff
-            coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a());
-        } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput ==
-                   header.fCoverageOutput){
-            // Get (1-RGBA) into coeff
-            coeff = GrGLSLExpr4(1) - inputColor;
-        }
-        // Get coeff * coverage into modulate and then write that to the dual source output.
-        this->fsCodeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage).c_str());
-    }
-
-    ///////////////////////////////////////////////////////////////////////////
-    // combine color and coverage as frag color
-
-    // Get "color * coverage" into fragColor
-    GrGLSLExpr4 fragColor = inputColor * inputCoverage;
-    // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so.
-    if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) {
-        GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage;
-
-        GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(this->dstColor());
-
-        fragColor = fragColor + dstContribution;
-    }
-    this->fsCodeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str());
-
-    if (!this->finish()) {
-        return false;
-    }
-
-    return true;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-GrGLShaderBuilder::GrGLShaderBuilder(GrGpuGL* gpu,
-                                     const GrGLProgramDesc& desc)
-    : fHasVertexShader(false)
-    , fTexCoordSetCnt(0)
-    , fProgramID(0)
-    , fDesc(desc)
-    , fGpu(gpu)
-    , fFSFeaturesAddedMask(0)
-    , fFSInputs(kVarsPerBlock)
-    , fFSOutputs(kMaxFSOutputs)
-    , fUniforms(kVarsPerBlock)
-    , fSetupFragPosition(false)
-    , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey)
-    , fHasCustomColorOutput(false)
-    , fHasSecondaryOutput(false) {
-}
-
-bool GrGLShaderBuilder::enableFeature(GLSLFeature feature) {
-    switch (feature) {
-        case kStandardDerivatives_GLSLFeature:
-            if (!fGpu->glCaps().shaderDerivativeSupport()) {
-                return false;
-            }
-            if (kGLES_GrGLStandard == fGpu->glStandard()) {
-                this->addFSFeature(1 << kStandardDerivatives_GLSLFeature,
-                                   "GL_OES_standard_derivatives");
-            }
-            return true;
-        default:
-            SkFAIL("Unexpected GLSLFeature requested.");
-            return false;
-    }
-}
-
-void GrGLShaderBuilder::addFSFeature(uint32_t featureBit, const char* extensionName) {
-    if (!(featureBit & fFSFeaturesAddedMask)) {
-        fFSExtensions.appendf("#extension %s: require\n", extensionName);
-        fFSFeaturesAddedMask |= featureBit;
-    }
-}
-
-void GrGLShaderBuilder::nameVariable(SkString* out, char prefix, const char* name) {
-    if ('\0' == prefix) {
-        *out = name;
-    } else {
-        out->printf("%c%s", prefix, name);
-    }
-    if (fCodeStage.inStageCode()) {
-        if (out->endsWith('_')) {
-            // Names containing "__" are reserved.
-            out->append("x");
-        }
-        out->appendf("_Stage%d", fCodeStage.stageIndex());
-    }
-}
-
-const char* GrGLShaderBuilder::dstColor() {
-    if (fCodeStage.inStageCode()) {
-        const GrEffect* effect = fCodeStage.effectStage()->getEffect();
-        if (!effect->willReadDstColor()) {
-            SkDEBUGFAIL("GrGLEffect asked for dst color but its generating GrEffect "
-                         "did not request access.");
-            return "";
-        }
-    }
-
-    if (fGpu->glCaps().fbFetchSupport()) {
-        this->addFSFeature(1 << (kLastGLSLPrivateFeature + 1),
-                           fGpu->glCaps().fbFetchExtensionString());
-        return fGpu->glCaps().fbFetchColorName();
-    } else if (fUniformHandles.fDstCopySamplerUni.isValid()) {
-        return kDstCopyColorName;
-    } else {
-        return "";
-    }
-}
-
-void GrGLShaderBuilder::appendTextureLookup(SkString* out,
-                                            const GrGLShaderBuilder::TextureSampler& sampler,
-                                            const char* coordName,
-                                            GrSLType varyingType) const {
-    append_texture_lookup(out,
-                          fGpu,
-                          this->getUniformCStr(sampler.samplerUniform()),
-                          coordName,
-                          sampler.configComponentMask(),
-                          sampler.swizzle(),
-                          varyingType);
-}
-
-void GrGLShaderBuilder::fsAppendTextureLookup(const GrGLShaderBuilder::TextureSampler& sampler,
-                                              const char* coordName,
-                                              GrSLType varyingType) {
-    this->appendTextureLookup(&fFSCode, sampler, coordName, varyingType);
-}
-
-void GrGLShaderBuilder::fsAppendTextureLookupAndModulate(
-                                            const char* modulation,
-                                            const GrGLShaderBuilder::TextureSampler& sampler,
-                                            const char* coordName,
-                                            GrSLType varyingType) {
-    SkString lookup;
-    this->appendTextureLookup(&lookup, sampler, coordName, varyingType);
-    fFSCode.append((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str());
-}
-
-GrGLShaderBuilder::DstReadKey GrGLShaderBuilder::KeyForDstRead(const GrTexture* dstCopy,
-                                                               const GrGLCaps& caps) {
-    uint32_t key = kYesDstRead_DstReadKeyBit;
-    if (caps.fbFetchSupport()) {
-        return key;
-    }
-    SkASSERT(NULL != dstCopy);
-    if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
-        // The fact that the config is alpha-only must be considered when generating code.
-        key |= kUseAlphaConfig_DstReadKeyBit;
-    }
-    if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
-        key |= kTopLeftOrigin_DstReadKeyBit;
-    }
-    SkASSERT(static_cast<DstReadKey>(key) == key);
-    return static_cast<DstReadKey>(key);
-}
-
-GrGLShaderBuilder::FragPosKey GrGLShaderBuilder::KeyForFragmentPosition(const GrRenderTarget* dst,
-                                                                        const GrGLCaps&) {
-    if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
-        return kTopLeftFragPosRead_FragPosKey;
-    } else {
-        return kBottomLeftFragPosRead_FragPosKey;
-    }
-}
-
-
-const GrGLenum* GrGLShaderBuilder::GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps) {
-    if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) {
-        if (caps.textureRedSupport()) {
-            static const GrGLenum gRedSmear[] = { GR_GL_RED, GR_GL_RED, GR_GL_RED, GR_GL_RED };
-            return gRedSmear;
-        } else {
-            static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA,
-                                                    GR_GL_ALPHA, GR_GL_ALPHA };
-            return gAlphaSmear;
-        }
-    } else {
-        static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN, GR_GL_BLUE, GR_GL_ALPHA };
-        return gStraight;
-    }
-}
-
-GrGLProgramDataManager::UniformHandle GrGLShaderBuilder::addUniformArray(uint32_t visibility,
-                                                                         GrSLType type,
-                                                                         const char* name,
-                                                                         int count,
-                                                                         const char** outName) {
-    SkASSERT(name && strlen(name));
-    SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility);
-    SkASSERT(0 == (~kVisibilityMask & visibility));
-    SkASSERT(0 != visibility);
-
-    UniformInfo& uni = fUniforms.push_back();
-    uni.fVariable.setType(type);
-    uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
-    this->nameVariable(uni.fVariable.accessName(), 'u', name);
-    uni.fVariable.setArrayCount(count);
-    uni.fVisibility = visibility;
-
-    // If it is visible in both the VS and FS, the precision must match.
-    // We declare a default FS precision, but not a default VS. So set the var
-    // to use the default FS precision.
-    if ((kVertex_Visibility | kFragment_Visibility) == visibility) {
-        // the fragment and vertex precisions must match
-        uni.fVariable.setPrecision(kDefaultFragmentPrecision);
-    }
-
-    if (NULL != outName) {
-        *outName = uni.fVariable.c_str();
-    }
-    return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1);
-}
-
-SkString GrGLShaderBuilder::ensureFSCoords2D(const TransformedCoordsArray& coords, int index) {
-    if (kVec3f_GrSLType != coords[index].type()) {
-        SkASSERT(kVec2f_GrSLType == coords[index].type());
-        return coords[index].getName();
-    }
-
-    SkString coords2D("coords2D");
-    if (0 != index) {
-        coords2D.appendf("_%i", index);
-    }
-    this->fsCodeAppendf("\tvec2 %s = %s.xy / %s.z;",
-                        coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
-    return coords2D;
-}
-
-const char* GrGLShaderBuilder::fragmentPosition() {
-    if (fCodeStage.inStageCode()) {
-        const GrEffect* effect = fCodeStage.effectStage()->getEffect();
-        if (!effect->willReadFragmentPosition()) {
-            SkDEBUGFAIL("GrGLEffect asked for frag position but its generating GrEffect "
-                         "did not request access.");
-            return "";
-        }
-    }
-    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
-    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
-    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
-    if (fTopLeftFragPosRead) {
-        fSetupFragPosition = true;
-        return "gl_FragCoord";
-    } else if (fGpu->glCaps().fragCoordConventionsSupport()) {
-        if (!fSetupFragPosition) {
-            if (fGpu->glslGeneration() < k150_GrGLSLGeneration) {
-                this->addFSFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
-                                   "GL_ARB_fragment_coord_conventions");
-            }
-            fFSInputs.push_back().set(kVec4f_GrSLType,
-                                      GrGLShaderVar::kIn_TypeModifier,
-                                      "gl_FragCoord",
-                                      GrGLShaderVar::kDefault_Precision,
-                                      GrGLShaderVar::kUpperLeft_Origin);
-            fSetupFragPosition = true;
-        }
-        return "gl_FragCoord";
-    } else {
-        static const char* kCoordName = "fragCoordYDown";
-        if (!fSetupFragPosition) {
-            // temporarily change the stage index because we're inserting non-stage code.
-            CodeStage::AutoStageRestore csar(&fCodeStage, NULL);
-
-            SkASSERT(!fUniformHandles.fRTHeightUni.isValid());
-            const char* rtHeightName;
-
-            fUniformHandles.fRTHeightUni =
-                this->addUniform(kFragment_Visibility, kFloat_GrSLType, "RTHeight", &rtHeightName);
-
-            // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
-            // causes programs to fail to link. Making this function return a vec2() didn't fix the
-            // problem but using 1.0 for the last two components does.
-            this->fFSCode.prependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, "
-                                   "1.0);\n", kCoordName, rtHeightName);
-            fSetupFragPosition = true;
-        }
-        SkASSERT(fUniformHandles.fRTHeightUni.isValid());
-        return kCoordName;
-    }
-}
-
-void GrGLShaderBuilder::fsEmitFunction(GrSLType returnType,
-                                       const char* name,
-                                       int argCnt,
-                                       const GrGLShaderVar* args,
-                                       const char* body,
-                                       SkString* outName) {
-    fFSFunctions.append(GrGLSLTypeString(returnType));
-    this->nameVariable(outName, '\0', name);
-    fFSFunctions.appendf(" %s", outName->c_str());
-    fFSFunctions.append("(");
-    for (int i = 0; i < argCnt; ++i) {
-        args[i].appendDecl(this->ctxInfo(), &fFSFunctions);
-        if (i < argCnt - 1) {
-            fFSFunctions.append(", ");
-        }
-    }
-    fFSFunctions.append(") {\n");
-    fFSFunctions.append(body);
-    fFSFunctions.append("}\n\n");
-}
-
-namespace {
-
-inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
-                                               GrGLStandard standard,
-                                               SkString* str) {
-    // Desktop GLSL has added precision qualifiers but they don't do anything.
-    if (kGLES_GrGLStandard == standard) {
-        switch (p) {
-            case GrGLShaderVar::kHigh_Precision:
-                str->append("precision highp float;\n");
-                break;
-            case GrGLShaderVar::kMedium_Precision:
-                str->append("precision mediump float;\n");
-                break;
-            case GrGLShaderVar::kLow_Precision:
-                str->append("precision lowp float;\n");
-                break;
-            case GrGLShaderVar::kDefault_Precision:
-                SkFAIL("Default precision now allowed.");
-            default:
-                SkFAIL("Unknown precision value.");
-        }
-    }
-}
-}
-
-void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
-    for (int i = 0; i < vars.count(); ++i) {
-        vars[i].appendDecl(this->ctxInfo(), out);
-        out->append(";\n");
-    }
-}
-
-void GrGLShaderBuilder::appendUniformDecls(ShaderVisibility visibility,
-                                           SkString* out) const {
-    for (int i = 0; i < fUniforms.count(); ++i) {
-        if (fUniforms[i].fVisibility & visibility) {
-            fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out);
-            out->append(";\n");
-        }
-    }
-}
-
-void GrGLShaderBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder,
-                                             const GrEffectStage* effectStages[],
-                                             int effectCnt,
-                                             const GrGLProgramDesc::EffectKeyProvider& keyProvider,
-                                             GrGLSLExpr4* fsInOutColor) {
-    bool effectEmitted = false;
-
-    GrGLSLExpr4 inColor = *fsInOutColor;
-    GrGLSLExpr4 outColor;
-
-    for (int e = 0; e < effectCnt; ++e) {
-        SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect());
-        const GrEffectStage& stage = *effectStages[e];
-
-        CodeStage::AutoStageRestore csar(&fCodeStage, &stage);
-
-        if (inColor.isZeros()) {
-            SkString inColorName;
-
-            // Effects have no way to communicate zeros, they treat an empty string as ones.
-            this->nameVariable(&inColorName, '\0', "input");
-            this->fsCodeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor.c_str());
-            inColor = inColorName;
-        }
-
-        // create var to hold stage result
-        SkString outColorName;
-        this->nameVariable(&outColorName, '\0', "output");
-        this->fsCodeAppendf("\tvec4 %s;\n", outColorName.c_str());
-        outColor = outColorName;
-
-
-        programEffectsBuilder->emitEffect(stage,
-                                          keyProvider.get(e),
-                                          outColor.c_str(),
-                                          inColor.isOnes() ? NULL : inColor.c_str(),
-                                          fCodeStage.stageIndex());
-
-        inColor = outColor;
-        effectEmitted = true;
-    }
-
-    if (effectEmitted) {
-        *fsInOutColor = outColor;
-    }
-}
-
-const char* GrGLShaderBuilder::getColorOutputName() const {
-    return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor";
-}
-
-const char* GrGLShaderBuilder::enableSecondaryOutput() {
-    if (!fHasSecondaryOutput) {
-        fFSOutputs.push_back().set(kVec4f_GrSLType,
-                                   GrGLShaderVar::kOut_TypeModifier,
-                                   dual_source_output_name());
-        fHasSecondaryOutput = true;
-    }
-    return dual_source_output_name();
-}
-
-bool GrGLShaderBuilder::finish() {
-    SkASSERT(0 == fProgramID);
-    GL_CALL_RET(fProgramID, CreateProgram());
-    if (!fProgramID) {
-        return false;
-    }
-
-    SkTDArray<GrGLuint> shadersToDelete;
-
-    if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) {
-        GL_CALL(DeleteProgram(fProgramID));
-        return false;
-    }
-
-    this->bindProgramLocations(fProgramID);
-
-    GL_CALL(LinkProgram(fProgramID));
-
-    // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
-    bool checkLinked = !fGpu->ctxInfo().isChromium();
-#ifdef SK_DEBUG
-    checkLinked = true;
-#endif
-    if (checkLinked) {
-        GrGLint linked = GR_GL_INIT_ZERO;
-        GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked));
-        if (!linked) {
-            GrGLint infoLen = GR_GL_INIT_ZERO;
-            GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen));
-            SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
-            if (infoLen > 0) {
-                // retrieve length even though we don't need it to workaround
-                // bug in chrome cmd buffer param validation.
-                GrGLsizei length = GR_GL_INIT_ZERO;
-                GL_CALL(GetProgramInfoLog(fProgramID,
-                                          infoLen+1,
-                                          &length,
-                                          (char*)log.get()));
-                GrPrintf((char*)log.get());
-            }
-            SkDEBUGFAIL("Error linking program");
-            GL_CALL(DeleteProgram(fProgramID));
-            fProgramID = 0;
-            return false;
-        }
-    }
-
-    this->resolveProgramLocations(fProgramID);
-
-    for (int i = 0; i < shadersToDelete.count(); ++i) {
-      GL_CALL(DeleteShader(shadersToDelete[i]));
-    }
-
-    return true;
-}
-
-// Compiles a GL shader and attaches it to a program. Returns the shader ID if
-// successful, or 0 if not.
-static GrGLuint attach_shader(const GrGLContext& glCtx,
-                              GrGLuint programId,
-                              GrGLenum type,
-                              const SkString& shaderSrc) {
-    const GrGLInterface* gli = glCtx.interface();
-
-    GrGLuint shaderId;
-    GR_GL_CALL_RET(gli, shaderId, CreateShader(type));
-    if (0 == shaderId) {
-        return 0;
-    }
-
-#ifdef SK_DEBUG
-    SkString prettySource = GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, false);
-    const GrGLchar* sourceStr = prettySource.c_str();
-    GrGLint sourceLength = static_cast<GrGLint>(prettySource.size());
-#else
-    GrGLint sourceLength = static_cast<GrGLint>(shaderSrc.size());
-    const GrGLchar* sourceStr = shaderSrc.c_str();
-#endif
-    GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength));
-    GR_GL_CALL(gli, CompileShader(shaderId));
-
-    // Calling GetShaderiv in Chromium is quite expensive. Assume success in release builds.
-    bool checkCompiled = !glCtx.isChromium();
-#ifdef SK_DEBUG
-    checkCompiled = true;
-#endif
-    if (checkCompiled) {
-        GrGLint compiled = GR_GL_INIT_ZERO;
-        GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled));
-
-        if (!compiled) {
-            GrGLint infoLen = GR_GL_INIT_ZERO;
-            GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen));
-            SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
-            if (infoLen > 0) {
-                // retrieve length even though we don't need it to workaround bug in Chromium cmd
-                // buffer param validation.
-                GrGLsizei length = GR_GL_INIT_ZERO;
-                GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1,
-                                                 &length, (char*)log.get()));
-                GrPrintf(GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, true).c_str());
-                GrPrintf("\n%s", log.get());
-            }
-            SkDEBUGFAIL("Shader compilation failed!");
-            GR_GL_CALL(gli, DeleteShader(shaderId));
-            return 0;
-        }
-    }
-
-    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "skia_gpu::GLShader",
-                         TRACE_EVENT_SCOPE_THREAD, "shader", TRACE_STR_COPY(shaderSrc.c_str()));
-    if (c_PrintShaders) {
-        GrPrintf(GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, true).c_str());
-        GrPrintf("\n");
-    }
-
-    // Attach the shader, but defer deletion until after we have linked the program.
-    // This works around a bug in the Android emulator's GLES2 wrapper which
-    // will immediately delete the shader object and free its memory even though it's
-    // attached to a program, which then causes glLinkProgram to fail.
-    GR_GL_CALL(gli, AttachShader(programId, shaderId));
-
-    return shaderId;
-}
-
-bool GrGLShaderBuilder::compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const {
-    SkString fragShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo()));
-    fragShaderSrc.append(fFSExtensions);
-    append_default_precision_qualifier(kDefaultFragmentPrecision,
-                                       fGpu->glStandard(),
-                                       &fragShaderSrc);
-    this->appendUniformDecls(kFragment_Visibility, &fragShaderSrc);
-    this->appendDecls(fFSInputs, &fragShaderSrc);
-    // We shouldn't have declared outputs on 1.10
-    SkASSERT(k110_GrGLSLGeneration != fGpu->glslGeneration() || fFSOutputs.empty());
-    this->appendDecls(fFSOutputs, &fragShaderSrc);
-    fragShaderSrc.append(fFSFunctions);
-    fragShaderSrc.append("void main() {\n");
-    fragShaderSrc.append(fFSCode);
-    fragShaderSrc.append("}\n");
-
-    GrGLuint fragShaderId = attach_shader(fGpu->glContext(), programId, GR_GL_FRAGMENT_SHADER, fragShaderSrc);
-    if (!fragShaderId) {
-        return false;
-    }
-
-    *shaderIds->append() = fragShaderId;
-
-    return true;
-}
-
-void GrGLShaderBuilder::bindProgramLocations(GrGLuint programId) {
-    if (fHasCustomColorOutput) {
-        GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name()));
-    }
-    if (fHasSecondaryOutput) {
-        GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_name()));
-    }
-    // skbug.com/2056
-    bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
-    if (usingBindUniform) {
-        int count = fUniforms.count();
-        for (int i = 0; i < count; ++i) {
-            GL_CALL(BindUniformLocation(programId, i, fUniforms[i].fVariable.c_str()));
-            fUniforms[i].fLocation = i;
-        }
-    }
-}
-
-void GrGLShaderBuilder::resolveProgramLocations(GrGLuint programId) {
-    bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
-    if (!usingBindUniform) {
-        int count = fUniforms.count();
-        for (int i = 0; i < count; ++i) {
-            GrGLint location;
-            GL_CALL_RET(location,
-                        GetUniformLocation(programId, fUniforms[i].fVariable.c_str()));
-            fUniforms[i].fLocation = location;
-        }
-    }
-}
-
-const GrGLContextInfo& GrGLShaderBuilder::ctxInfo() const {
-    return fGpu->ctxInfo();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-GrGLFullShaderBuilder::GrGLFullShaderBuilder(GrGpuGL* gpu,
-                                             const GrGLProgramDesc& desc)
-    : INHERITED(gpu, desc)
-    , fVSAttrs(kVarsPerBlock)
-    , fVSOutputs(kVarsPerBlock)
-    , fGSInputs(kVarsPerBlock)
-    , fGSOutputs(kVarsPerBlock) {
-}
-
-void GrGLFullShaderBuilder::emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) {
-    const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
-
-    fHasVertexShader = true;
-
-    fPositionVar = &fVSAttrs.push_back();
-    fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
-    if (-1 != header.fLocalCoordAttributeIndex) {
-        fLocalCoordsVar = &fVSAttrs.push_back();
-        fLocalCoordsVar->set(kVec2f_GrSLType,
-                             GrGLShaderVar::kAttribute_TypeModifier,
-                             "aLocalCoords");
-    } else {
-        fLocalCoordsVar = fPositionVar;
-    }
-
-    const char* viewMName;
-    fUniformHandles.fViewMatrixUni =
-        this->addUniform(GrGLShaderBuilder::kVertex_Visibility, kMat33f_GrSLType, "ViewM",
-                          &viewMName);
-
-    // Transform the position into Skia's device coords.
-    this->vsCodeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n",
-                        viewMName, fPositionVar->c_str());
-
-    // we output point size in the GS if present
-    if (header.fEmitsPointSize
-#if GR_GL_EXPERIMENTAL_GS
-        && !header.fExperimentalGS
-#endif
-        ) {
-        this->vsCodeAppend("\tgl_PointSize = 1.0;\n");
-    }
-
-    if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) {
-        this->addAttribute(kVec4f_GrSLType, color_attribute_name());
-        const char *vsName, *fsName;
-        this->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
-        this->vsCodeAppendf("\t%s = %s;\n", vsName, color_attribute_name());
-        *color = fsName;
-    }
-
-    if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) {
-        this->addAttribute(kVec4f_GrSLType, coverage_attribute_name());
-        const char *vsName, *fsName;
-        this->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
-        this->vsCodeAppendf("\t%s = %s;\n", vsName, coverage_attribute_name());
-        *coverage = fsName;
-    }
-}
-
-void GrGLFullShaderBuilder::emitCodeAfterEffects() {
-    const char* rtAdjustName;
-    fUniformHandles.fRTAdjustmentUni =
-        this->addUniform(GrGLShaderBuilder::kVertex_Visibility, kVec4f_GrSLType, "rtAdjustment",
-                         &rtAdjustName);
-
-    // Transform from Skia's device coords to GL's normalized device coords.
-    this->vsCodeAppendf(
-        "\tgl_Position = vec4(dot(pos3.xz, %s.xy), dot(pos3.yz, %s.zw), 0, pos3.z);\n",
-        rtAdjustName, rtAdjustName);
-}
-
-bool GrGLFullShaderBuilder::addAttribute(GrSLType type, const char* name) {
-    for (int i = 0; i < fVSAttrs.count(); ++i) {
-        const GrGLShaderVar& attr = fVSAttrs[i];
-        // if attribute already added, don't add it again
-        if (attr.getName().equals(name)) {
-            SkASSERT(attr.getType() == type);
-            return false;
-        }
-    }
-    fVSAttrs.push_back().set(type,
-                             GrGLShaderVar::kAttribute_TypeModifier,
-                             name);
-    return true;
-}
-
-bool GrGLFullShaderBuilder::addEffectAttribute(int attributeIndex,
-                                               GrSLType type,
-                                               const SkString& name) {
-    if (!this->addAttribute(type, name.c_str())) {
-        return false;
-    }
-
-    fEffectAttributes.push_back().set(attributeIndex, name);
-    return true;
-}
-
-void GrGLFullShaderBuilder::addVarying(GrSLType type,
-                                       const char* name,
-                                       const char** vsOutName,
-                                       const char** fsInName) {
-    fVSOutputs.push_back();
-    fVSOutputs.back().setType(type);
-    fVSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
-    this->nameVariable(fVSOutputs.back().accessName(), 'v', name);
-
-    if (vsOutName) {
-        *vsOutName = fVSOutputs.back().getName().c_str();
-    }
-    // input to FS comes either from VS or GS
-    const SkString* fsName;
-#if GR_GL_EXPERIMENTAL_GS
-    if (this->desc().getHeader().fExperimentalGS) {
-        // if we have a GS take each varying in as an array
-        // and output as non-array.
-        fGSInputs.push_back();
-        fGSInputs.back().setType(type);
-        fGSInputs.back().setTypeModifier(GrGLShaderVar::kVaryingIn_TypeModifier);
-        fGSInputs.back().setUnsizedArray();
-        *fGSInputs.back().accessName() = fVSOutputs.back().getName();
-        fGSOutputs.push_back();
-        fGSOutputs.back().setType(type);
-        fGSOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
-        this->nameVariable(fGSOutputs.back().accessName(), 'g', name);
-        fsName = fGSOutputs.back().accessName();
-    } else
-#endif
-    {
-        fsName = fVSOutputs.back().accessName();
-    }
-    this->fsInputAppend().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, *fsName);
-    if (fsInName) {
-        *fsInName = fsName->c_str();
-    }
-}
-
-const SkString* GrGLFullShaderBuilder::getEffectAttributeName(int attributeIndex) const {
-    const AttributePair* attribEnd = fEffectAttributes.end();
-    for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) {
-        if (attrib->fIndex == attributeIndex) {
-            return &attrib->fName;
-        }
-    }
-
-    return NULL;
-}
-
-GrGLProgramEffects* GrGLFullShaderBuilder::createAndEmitEffects(
-        const GrEffectStage* effectStages[],
-        int effectCnt,
-        const GrGLProgramDesc::EffectKeyProvider& keyProvider,
-        GrGLSLExpr4* inOutFSColor) {
-
-    GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt);
-    this->INHERITED::createAndEmitEffects(&programEffectsBuilder,
-                                          effectStages,
-                                          effectCnt,
-                                          keyProvider,
-                                          inOutFSColor);
-    return programEffectsBuilder.finish();
-}
-
-bool GrGLFullShaderBuilder::compileAndAttachShaders(GrGLuint programId,
-                                                    SkTDArray<GrGLuint>* shaderIds) const {
-    const GrGLContext& glCtx = this->gpu()->glContext();
-    SkString vertShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo()));
-    this->appendUniformDecls(kVertex_Visibility, &vertShaderSrc);
-    this->appendDecls(fVSAttrs, &vertShaderSrc);
-    this->appendDecls(fVSOutputs, &vertShaderSrc);
-    vertShaderSrc.append("void main() {\n");
-    vertShaderSrc.append(fVSCode);
-    vertShaderSrc.append("}\n");
-    GrGLuint vertShaderId = attach_shader(glCtx, programId, GR_GL_VERTEX_SHADER, vertShaderSrc);
-    if (!vertShaderId) {
-        return false;
-    }
-    *shaderIds->append() = vertShaderId;
-
-#if GR_GL_EXPERIMENTAL_GS
-    if (this->desc().getHeader().fExperimentalGS) {
-        SkASSERT(this->ctxInfo().glslGeneration() >= k150_GrGLSLGeneration);
-        SkString geomShaderSrc(GrGetGLSLVersionDecl(this->ctxInfo()));
-        geomShaderSrc.append("layout(triangles) in;\n"
-                             "layout(triangle_strip, max_vertices = 6) out;\n");
-        this->appendDecls(fGSInputs, &geomShaderSrc);
-        this->appendDecls(fGSOutputs, &geomShaderSrc);
-        geomShaderSrc.append("void main() {\n");
-        geomShaderSrc.append("\tfor (int i = 0; i < 3; ++i) {\n"
-                             "\t\tgl_Position = gl_in[i].gl_Position;\n");
-        if (this->desc().getHeader().fEmitsPointSize) {
-            geomShaderSrc.append("\t\tgl_PointSize = 1.0;\n");
-        }
-        SkASSERT(fGSInputs.count() == fGSOutputs.count());
-        for (int i = 0; i < fGSInputs.count(); ++i) {
-            geomShaderSrc.appendf("\t\t%s = %s[i];\n",
-                                  fGSOutputs[i].getName().c_str(),
-                                  fGSInputs[i].getName().c_str());
-        }
-        geomShaderSrc.append("\t\tEmitVertex();\n"
-                             "\t}\n"
-                             "\tEndPrimitive();\n");
-        geomShaderSrc.append("}\n");
-        GrGLuint geomShaderId = attach_shader(glCtx, programId, GR_GL_GEOMETRY_SHADER, geomShaderSrc);
-        if (!geomShaderId) {
-            return false;
-        }
-        *shaderIds->append() = geomShaderId;
-    }
-#endif
-
-    return this->INHERITED::compileAndAttachShaders(programId, shaderIds);
-}
-
-void GrGLFullShaderBuilder::bindProgramLocations(GrGLuint programId) {
-    this->INHERITED::bindProgramLocations(programId);
-
-    const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
-
-    // Bind the attrib locations to same values for all shaders
-    SkASSERT(-1 != header.fPositionAttributeIndex);
-    GL_CALL(BindAttribLocation(programId,
-                               header.fPositionAttributeIndex,
-                               fPositionVar->c_str()));
-    if (-1 != header.fLocalCoordAttributeIndex) {
-        GL_CALL(BindAttribLocation(programId,
-                                   header.fLocalCoordAttributeIndex,
-                                   fLocalCoordsVar->c_str()));
-    }
-    if (-1 != header.fColorAttributeIndex) {
-        GL_CALL(BindAttribLocation(programId,
-                                   header.fColorAttributeIndex,
-                                   color_attribute_name()));
-    }
-    if (-1 != header.fCoverageAttributeIndex) {
-        GL_CALL(BindAttribLocation(programId,
-                                   header.fCoverageAttributeIndex,
-                                   coverage_attribute_name()));
-    }
-
-    const AttributePair* attribEnd = fEffectAttributes.end();
-    for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) {
-         GL_CALL(BindAttribLocation(programId, attrib->fIndex, attrib->fName.c_str()));
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-GrGLFragmentOnlyShaderBuilder::GrGLFragmentOnlyShaderBuilder(GrGpuGL* gpu,
-                                                             const GrGLProgramDesc& desc)
-    : INHERITED(gpu, desc) {
-    SkASSERT(!desc.getHeader().fHasVertexCode);
-    SkASSERT(gpu->glCaps().pathRenderingSupport());
-    SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput);
-    SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput);
-}
-
-int GrGLFragmentOnlyShaderBuilder::addTexCoordSets(int count) {
-    int firstFreeCoordSet = fTexCoordSetCnt;
-    fTexCoordSetCnt += count;
-    SkASSERT(gpu()->glCaps().maxFixedFunctionTextureCoords() >= fTexCoordSetCnt);
-    return firstFreeCoordSet;
-}
-
-GrGLProgramEffects* GrGLFragmentOnlyShaderBuilder::createAndEmitEffects(
-        const GrEffectStage* effectStages[],
-        int effectCnt,
-        const GrGLProgramDesc::EffectKeyProvider& keyProvider,
-        GrGLSLExpr4* inOutFSColor) {
-
-    GrGLPathTexGenProgramEffectsBuilder pathTexGenEffectsBuilder(this,
-                                                                 effectCnt);
-    this->INHERITED::createAndEmitEffects(&pathTexGenEffectsBuilder,
-                                          effectStages,
-                                          effectCnt,
-                                          keyProvider,
-                                          inOutFSColor);
-    return pathTexGenEffectsBuilder.finish();
-}
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
deleted file mode 100644
index 2a14a1f..0000000
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * Copyright 2012 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrGLShaderBuilder_DEFINED
-#define GrGLShaderBuilder_DEFINED
-
-#include "GrAllocator.h"
-#include "GrBackendEffectFactory.h"
-#include "GrColor.h"
-#include "GrEffect.h"
-#include "SkTypes.h"
-#include "gl/GrGLProgramDesc.h"
-#include "gl/GrGLProgramEffects.h"
-#include "gl/GrGLSL.h"
-#include "gl/GrGLProgramDataManager.h"
-
-#include <stdarg.h>
-
-class GrGLContextInfo;
-class GrEffectStage;
-class GrGLProgramDesc;
-
-/**
-  Contains all the incremental state of a shader as it is being built,as well as helpers to
-  manipulate that state.
-*/
-class GrGLShaderBuilder {
-public:
-    typedef GrTAllocator<GrGLShaderVar> VarArray;
-    typedef GrGLProgramEffects::TextureSampler TextureSampler;
-    typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray;
-
-    enum ShaderVisibility {
-        kVertex_Visibility   = 0x1,
-        kGeometry_Visibility = 0x2,
-        kFragment_Visibility = 0x4,
-    };
-
-    typedef GrGLProgramDataManager::UniformHandle UniformHandle;
-
-    // Handles for program uniforms (other than per-effect uniforms)
-    struct BuiltinUniformHandles {
-        UniformHandle       fViewMatrixUni;
-        UniformHandle       fRTAdjustmentUni;
-        UniformHandle       fColorUni;
-        UniformHandle       fCoverageUni;
-
-        // We use the render target height to provide a y-down frag coord when specifying
-        // origin_upper_left is not supported.
-        UniformHandle       fRTHeightUni;
-
-        // Uniforms for computing texture coords to do the dst-copy lookup
-        UniformHandle       fDstCopyTopLeftUni;
-        UniformHandle       fDstCopyScaleUni;
-        UniformHandle       fDstCopySamplerUni;
-    };
-
-    struct UniformInfo {
-        GrGLShaderVar fVariable;
-        uint32_t      fVisibility;
-        GrGLint       fLocation;
-    };
-
-    // This uses an allocator rather than array so that the GrGLShaderVars don't move in memory
-    // after they are inserted. Users of GrGLShaderBuilder get refs to the vars and ptrs to their
-    // name strings. Otherwise, we'd have to hand out copies.
-    typedef GrTAllocator<UniformInfo> UniformInfoArray;
-
-    /** Generates a shader program.
-     *
-     * The program implements what is specified in the stages given as input.
-     * After successful generation, the builder result objects are available
-     * to be used.
-     * @return true if generation was successful.
-     */
-    bool genProgram(const GrEffectStage* inColorStages[],
-                    const GrEffectStage* inCoverageStages[]);
-
-    // Below are the results of the shader generation.
-
-    GrGLProgramEffects* getColorEffects() const { SkASSERT(fProgramID); return fColorEffects.get(); }
-    GrGLProgramEffects* getCoverageEffects() const { SkASSERT(fProgramID); return fCoverageEffects.get(); }
-    const BuiltinUniformHandles& getBuiltinUniformHandles() const {
-        SkASSERT(fProgramID);
-        return fUniformHandles;
-    }
-    GrGLuint getProgramID() const { SkASSERT(fProgramID); return fProgramID; }
-    bool hasVertexShader() const { SkASSERT(fProgramID); return fHasVertexShader; }
-    int getTexCoordSetCount() const { SkASSERT(fProgramID); return fTexCoordSetCnt; }
-    const UniformInfoArray& getUniformInfos() const { return fUniforms; }
-
-    virtual ~GrGLShaderBuilder() {}
-
-    /**
-     * Use of these features may require a GLSL extension to be enabled. Shaders may not compile
-     * if code is added that uses one of these features without calling enableFeature()
-     */
-    enum GLSLFeature {
-        kStandardDerivatives_GLSLFeature = 0,
-
-        kLastGLSLFeature = kStandardDerivatives_GLSLFeature
-    };
-
-    /**
-     * If the feature is supported then true is returned and any necessary #extension declarations
-     * are added to the shaders. If the feature is not supported then false will be returned.
-     */
-    bool enableFeature(GLSLFeature);
-
-    /**
-     * Called by GrGLEffects to add code the fragment shader.
-     */
-    void fsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
-        va_list args;
-        va_start(args, format);
-        fFSCode.appendVAList(format, args);
-        va_end(args);
-    }
-
-    void fsCodeAppend(const char* str) { fFSCode.append(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. */
-    void appendTextureLookup(SkString* out,
-                             const TextureSampler&,
-                             const char* coordName,
-                             GrSLType coordType = kVec2f_GrSLType) const;
-
-    /** Version of above that appends the result to the fragment shader code instead.*/
-    void fsAppendTextureLookup(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 fsAppendTextureLookupAndModulate(const char* modulation,
-                                          const TextureSampler&,
-                                          const char* coordName,
-                                          GrSLType coordType = kVec2f_GrSLType);
-
-    /** Emits a helper function outside of main() in the fragment shader. */
-    void fsEmitFunction(GrSLType returnType,
-                        const char* name,
-                        int argCnt,
-                        const GrGLShaderVar* args,
-                        const char* body,
-                        SkString* outName);
-
-    typedef uint8_t DstReadKey;
-    typedef uint8_t FragPosKey;
-
-    /**  Returns a key for adding code to read the copy-of-dst color in service of effects that
-         require reading the dst. It must not return 0 because 0 indicates that there is no dst
-         copy read at all (in which case this function should not be called). */
-    static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&);
-
-    /** Returns a key for reading the fragment location. This should only be called if there is an
-        effect that will requires the fragment position. If the fragment position is not required,
-        the key is 0. */
-    static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&);
-
-    /** If texture swizzling is available using tex parameters then it is preferred over mangling
-        the generated shader code. This potentially allows greater reuse of cached shaders. */
-    static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
-
-    /** Add a uniform variable to the current program, that has visibility in one or more shaders.
-        visibility is a bitfield of ShaderVisibility values indicating from which shaders the
-        uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not
-        supported at this time. The actual uniform name will be mangled. If outName is not NULL then
-        it will refer to the final uniform name after return. Use the addUniformArray variant to add
-        an array of uniforms. */
-    GrGLProgramDataManager::UniformHandle addUniform(uint32_t visibility,
-                                                     GrSLType type,
-                                                     const char* name,
-                                                     const char** outName = NULL) {
-        return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
-    }
-    GrGLProgramDataManager::UniformHandle addUniformArray(uint32_t visibility,
-                                                          GrSLType type,
-                                                          const char* name,
-                                                          int arrayCount,
-                                                          const char** outName = NULL);
-
-    const GrGLShaderVar& getUniformVariable(GrGLProgramDataManager::UniformHandle u) const {
-        return fUniforms[u.toShaderBuilderIndex()].fVariable;
-    }
-
-    /**
-     * Shortcut for getUniformVariable(u).c_str()
-     */
-    const char* getUniformCStr(GrGLProgramDataManager::UniformHandle u) const {
-        return this->getUniformVariable(u).c_str();
-    }
-
-    /**
-     * This returns a variable name to access the 2D, perspective correct version of the coords in
-     * the fragment shader. If the coordinates at index are 3-dimensional, it immediately emits a
-     * perspective divide into the fragment shader (xy / z) to convert them to 2D.
-     */
-    SkString ensureFSCoords2D(const TransformedCoordsArray&, int index);
-
-    /** Returns a variable name that represents the position of the fragment in the FS. The position
-        is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
-    const char* fragmentPosition();
-
-    /** Returns the variable name that holds the color of the destination pixel. This may be NULL if
-        no effect advertised that it will read the destination. */
-    const char* dstColor();
-
-    const GrGLContextInfo& ctxInfo() const;
-
-    /**
-     * Helper for begining and ending a block in the fragment code. TODO: Make GrGLShaderBuilder
-     * aware of all blocks and turn single \t's into the correct number of tabs (or spaces) so that
-     * our shaders print pretty without effect writers tracking indentation.
-     */
-    class FSBlock {
-    public:
-        FSBlock(GrGLShaderBuilder* builder) : fBuilder(builder) {
-            SkASSERT(NULL != builder);
-            fBuilder->fsCodeAppend("\t{\n");
-        }
-
-        ~FSBlock() {
-            fBuilder->fsCodeAppend("\t}\n");
-        }
-    private:
-        GrGLShaderBuilder* fBuilder;
-    };
-
-protected:
-    GrGLShaderBuilder(GrGpuGL*, const GrGLProgramDesc&);
-
-    GrGpuGL* gpu() const { return fGpu; }
-
-    const GrGLProgramDesc& desc() const { return fDesc; }
-
-    /** Add input/output variable declarations (i.e. 'varying') to the fragment shader. */
-    GrGLShaderVar& fsInputAppend() { return fFSInputs.push_back(); }
-
-    // Helper for emitEffects().
-    void createAndEmitEffects(GrGLProgramEffectsBuilder*,
-                              const GrEffectStage* effectStages[],
-                              int effectCnt,
-                              const GrGLProgramDesc::EffectKeyProvider&,
-                              GrGLSLExpr4* inOutFSColor);
-
-    // Generates a name for a variable. The generated string will be name prefixed by the prefix
-    // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
-    // generating stage code.
-    void nameVariable(SkString* out, char prefix, const char* name);
-
-    virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
-
-    virtual void bindProgramLocations(GrGLuint programId);
-    void resolveProgramLocations(GrGLuint programId);
-
-    void appendDecls(const VarArray&, SkString*) const;
-    void appendUniformDecls(ShaderVisibility, SkString*) const;
-
-    SkAutoTUnref<GrGLProgramEffects> fColorEffects;
-    SkAutoTUnref<GrGLProgramEffects> fCoverageEffects;
-    BuiltinUniformHandles            fUniformHandles;
-    bool                             fHasVertexShader;
-    int                              fTexCoordSetCnt;
-    GrGLuint                         fProgramID;
-private:
-    class CodeStage : SkNoncopyable {
-    public:
-        CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {}
-
-        bool inStageCode() const {
-            this->validate();
-            return NULL != fEffectStage;
-        }
-
-        const GrEffectStage* effectStage() const {
-            this->validate();
-            return fEffectStage;
-        }
-
-        int stageIndex() const {
-            this->validate();
-            return fCurrentIndex;
-        }
-
-        class AutoStageRestore : SkNoncopyable {
-        public:
-            AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) {
-                SkASSERT(NULL != codeStage);
-                fSavedIndex = codeStage->fCurrentIndex;
-                fSavedEffectStage = codeStage->fEffectStage;
-
-                if (NULL == newStage) {
-                    codeStage->fCurrentIndex = -1;
-                } else {
-                    codeStage->fCurrentIndex = codeStage->fNextIndex++;
-                }
-                codeStage->fEffectStage = newStage;
-
-                fCodeStage = codeStage;
-            }
-            ~AutoStageRestore() {
-                fCodeStage->fCurrentIndex = fSavedIndex;
-                fCodeStage->fEffectStage = fSavedEffectStage;
-            }
-        private:
-            CodeStage*              fCodeStage;
-            int                     fSavedIndex;
-            const GrEffectStage*    fSavedEffectStage;
-        };
-    private:
-        void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); }
-        int                     fNextIndex;
-        int                     fCurrentIndex;
-        const GrEffectStage*    fEffectStage;
-    } fCodeStage;
-
-    /**
-     * The base class will emit the fragment code that precedes the per-effect code and then call
-     * this function. The subclass can use it to insert additional fragment code that should
-     * execute before the effects' code and/or emit other shaders (e.g. geometry, vertex).
-     *
-     * The subclass can modify the initial color or coverage 
-     */
-    virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) = 0;
-
-    /**
-    * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for
-    * deleting it when finished. effectStages contains the effects to add. The effect key provider 
-    * is used to communicate the key each effect created in its GenKey function. inOutFSColor
-    * specifies the input color to the first stage and is updated to be the output color of the
-    * last stage. The handles to texture samplers for effectStage[i] are added to
-    * effectSamplerHandles[i].
-    */
-    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
-                                                     int effectCnt,
-                                                     const GrGLProgramDesc::EffectKeyProvider&,
-                                                     GrGLSLExpr4* inOutFSColor) = 0;
-
-    /**
-     * Similar to emitCodeBeforeEffects() but called after per-effect code is emitted.
-     */
-    virtual void emitCodeAfterEffects() = 0;
-
-    /** Enables using the secondary color output and returns the name of the var in which it is
-        to be stored */
-    const char* enableSecondaryOutput();
-    /** Gets the name of the primary color output. */
-    const char* getColorOutputName() const;
-
-    /**
-     * Compiles all the shaders, links them into a program, and writes the program id to the output
-     * struct.
-     **/
-    bool finish();
-
-    /**
-     * Features that should only be enabled by GrGLShaderBuilder itself.
-     */
-    enum GLSLPrivateFeature {
-        kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
-        kLastGLSLPrivateFeature = kFragCoordConventions_GLSLPrivateFeature
-    };
-    bool enablePrivateFeature(GLSLPrivateFeature);
-
-    // If we ever have VS/GS features we can expand this to take a bitmask of ShaderVisibility and
-    // track the enables separately for each shader.
-    void addFSFeature(uint32_t featureBit, const char* extensionName);
-
-    // Interpretation of DstReadKey when generating code
-    enum {
-        kNoDstRead_DstReadKey           = 0,
-        kYesDstRead_DstReadKeyBit       = 0x1, // Set if we do a dst-copy-read.
-        kUseAlphaConfig_DstReadKeyBit   = 0x2, // Set if dst-copy config is alpha only.
-        kTopLeftOrigin_DstReadKeyBit    = 0x4, // Set if dst-copy origin is top-left.
-    };
-
-    enum {
-        kNoFragPosRead_FragPosKey           = 0,  // The fragment positition will not be needed.
-        kTopLeftFragPosRead_FragPosKey      = 0x1,// Read frag pos relative to top-left.
-        kBottomLeftFragPosRead_FragPosKey   = 0x2,// Read frag pos relative to bottom-left.
-    };
-
-    const GrGLProgramDesc&                  fDesc;
-    GrGpuGL*                                fGpu;
-    uint32_t                                fFSFeaturesAddedMask;
-    SkString                                fFSFunctions;
-    SkString                                fFSExtensions;
-    VarArray                                fFSInputs;
-    VarArray                                fFSOutputs;
-    UniformInfoArray                        fUniforms;
-
-    SkString                                fFSCode;
-
-    bool                                    fSetupFragPosition;
-    bool                                    fTopLeftFragPosRead;
-
-    bool                                    fHasCustomColorOutput;
-    bool                                    fHasSecondaryOutput;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-class GrGLFullShaderBuilder : public GrGLShaderBuilder {
-public:
-    GrGLFullShaderBuilder(GrGpuGL*, const GrGLProgramDesc&);
-
-    /**
-     * Called by GrGLEffects to add code to one of the shaders.
-     */
-    void vsCodeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
-        va_list args;
-        va_start(args, format);
-        fVSCode.appendVAList(format, args);
-        va_end(args);
-    }
-
-    void vsCodeAppend(const char* str) { fVSCode.append(str); }
-
-   /** Add a vertex attribute to the current program that is passed in from the vertex data.
-       Returns false if the attribute was already there, true otherwise. */
-    bool addAttribute(GrSLType type, const char* name);
-
-   /** Add a varying variable to the current program to pass values between vertex and fragment
-        shaders. If the last two parameters are non-NULL, they are filled in with the name
-        generated. */
-    void addVarying(GrSLType type,
-                    const char* name,
-                    const char** vsOutName = NULL,
-                    const char** fsInName = NULL);
-
-    /** Returns a vertex attribute that represents the vertex position in the VS. This is the
-        pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
-      */
-    const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
-
-    /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
-        as positionAttribute() or it may not be. It depends upon whether the rendering code
-        specified explicit local coords or not in the GrDrawState. */
-    const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
-
-    /**
-     * Are explicit local coordinates provided as input to the vertex shader.
-     */
-    bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
-
-    bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name);
-    const SkString* getEffectAttributeName(int attributeIndex) const;
-
-private:
-    virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE;
-
-    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
-                                                     int effectCnt,
-                                                     const GrGLProgramDesc::EffectKeyProvider&,
-                                                     GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
-
-    virtual void emitCodeAfterEffects() SK_OVERRIDE;
-
-    virtual bool compileAndAttachShaders(GrGLuint programId,
-                                         SkTDArray<GrGLuint>* shaderIds) const SK_OVERRIDE;
-
-    virtual void bindProgramLocations(GrGLuint programId) SK_OVERRIDE;
-
-    VarArray                            fVSAttrs;
-    VarArray                            fVSOutputs;
-    VarArray                            fGSInputs;
-    VarArray                            fGSOutputs;
-
-    SkString                            fVSCode;
-
-    struct AttributePair {
-        void set(int index, const SkString& name) {
-            fIndex = index; fName = name;
-        }
-        int      fIndex;
-        SkString fName;
-    };
-    SkSTArray<10, AttributePair, true>  fEffectAttributes;
-
-    GrGLShaderVar*                      fPositionVar;
-    GrGLShaderVar*                      fLocalCoordsVar;
-
-    typedef GrGLShaderBuilder INHERITED;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-class GrGLFragmentOnlyShaderBuilder : public GrGLShaderBuilder {
-public:
-    GrGLFragmentOnlyShaderBuilder(GrGpuGL*, const GrGLProgramDesc&);
-
-    int addTexCoordSets(int count);
-
-private:
-    virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE {}
-
-    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
-                                                     int effectCnt,
-                                                     const GrGLProgramDesc::EffectKeyProvider&,
-                                                     GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
-
-    virtual void emitCodeAfterEffects() SK_OVERRIDE {}
-
-    typedef GrGLShaderBuilder INHERITED;
-};
-
-#endif
diff --git a/src/gpu/gl/GrGLVertexEffect.h b/src/gpu/gl/GrGLVertexEffect.h
index eba1fbe..2e82fbc 100644
--- a/src/gpu/gl/GrGLVertexEffect.h
+++ b/src/gpu/gl/GrGLVertexEffect.h
@@ -24,27 +24,27 @@
      * This is similar to emitCode() in the base class, except it takes a full shader builder.
      * This allows the effect subclass to emit vertex code.
      */
-    virtual void emitCode(GrGLFullShaderBuilder* builder,
+    virtual void emitCode(GrGLFullProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
                           const char* inputColor,
                           const TransformedCoordsArray& coords,
                           const TextureSamplerArray& samplers) = 0;
-
     /**
      * Provide a default override for base class's emitCode() function.
      */
-    virtual void emitCode(GrGLShaderBuilder* builder,
+    virtual void emitCode(GrGLProgramBuilder* builder,
                           const GrDrawEffect& drawEffect,
                           const GrEffectKey& key,
                           const char* outputColor,
                           const char* inputColor,
                           const TransformedCoordsArray& coords,
                           const TextureSamplerArray& samplers) SK_OVERRIDE {
-        SkFAIL("GrGLVertexEffect requires GrGLFullShaderBuilder* overload for emitCode().");
+        SkFAIL("GrGLVertexEffect requires GrGLFullProgramBuilder* overload for emitCode().");
     }
 
+
 private:
     typedef GrGLEffect INHERITED;
 };
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index 418f591..3c22d17 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -8,7 +8,6 @@
 
 #include "GrGpuGL.h"
 #include "GrGLStencilBuffer.h"
-#include "GrGLShaderBuilder.h"
 #include "GrTemplates.h"
 #include "GrTypes.h"
 #include "SkStrokeRec.h"
diff --git a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
new file mode 100644
index 0000000..d216a18
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLFragmentShaderBuilder.h"
+#include "GrGLShaderStringBuilder.h"
+#include "GrGLProgramBuilder.h"
+#include "../GrGpuGL.h"
+
+namespace {
+#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
+#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
+// ES2 FS only guarantees mediump and lowp support
+static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
+static const char kDstCopyColorName[] = "_dstColor";
+inline const char* declared_color_output_name() { return "fsColorOut"; }
+inline const char* dual_source_output_name() { return "dualSourceOut"; }
+inline void append_default_precision_qualifier(GrGLShaderVar::Precision p,
+                                               GrGLStandard standard,
+                                               SkString* str) {
+    // Desktop GLSL has added precision qualifiers but they don't do anything.
+    if (kGLES_GrGLStandard == standard) {
+        switch (p) {
+            case GrGLShaderVar::kHigh_Precision:
+                str->append("precision highp float;\n");
+                break;
+            case GrGLShaderVar::kMedium_Precision:
+                str->append("precision mediump float;\n");
+                break;
+            case GrGLShaderVar::kLow_Precision:
+                str->append("precision lowp float;\n");
+                break;
+            case GrGLShaderVar::kDefault_Precision:
+                SkFAIL("Default precision now allowed.");
+            default:
+                SkFAIL("Unknown precision value.");
+        }
+    }
+}
+}
+
+GrGLFragmentShaderBuilder::DstReadKey GrGLFragmentShaderBuilder::KeyForDstRead(
+        const GrTexture* dstCopy, const GrGLCaps& caps) {
+    uint32_t key = kYesDstRead_DstReadKeyBit;
+    if (caps.fbFetchSupport()) {
+        return key;
+    }
+    SkASSERT(NULL != dstCopy);
+    if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
+        // The fact that the config is alpha-only must be considered when generating code.
+        key |= kUseAlphaConfig_DstReadKeyBit;
+    }
+    if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
+        key |= kTopLeftOrigin_DstReadKeyBit;
+    }
+    SkASSERT(static_cast<DstReadKey>(key) == key);
+    return static_cast<DstReadKey>(key);
+}
+
+GrGLFragmentShaderBuilder::FragPosKey GrGLFragmentShaderBuilder::KeyForFragmentPosition(
+        const GrRenderTarget* dst, const GrGLCaps&) {
+    if (kTopLeft_GrSurfaceOrigin == dst->origin()) {
+        return kTopLeftFragPosRead_FragPosKey;
+    } else {
+        return kBottomLeftFragPosRead_FragPosKey;
+    }
+}
+
+GrGLFragmentShaderBuilder::GrGLFragmentShaderBuilder(GrGLProgramBuilder* program,
+                                                     const GrGLProgramDesc& desc)
+    : INHERITED(program)
+    , fHasCustomColorOutput(false)
+    , fHasSecondaryOutput(false)
+    , fSetupFragPosition(false)
+    , fTopLeftFragPosRead(kTopLeftFragPosRead_FragPosKey == desc.getHeader().fFragPosKey){
+}
+
+const char* GrGLFragmentShaderBuilder::dstColor() {
+    if (fProgramBuilder->fCodeStage.inStageCode()) {
+        const GrEffect* effect = fProgramBuilder->fCodeStage.effectStage()->getEffect();
+        if (!effect->willReadDstColor()) {
+            SkDEBUGFAIL("GrGLEffect asked for dst color but its generating GrEffect "
+                        "did not request access.");
+            return "";
+        }
+    }
+
+    GrGpuGL* gpu = fProgramBuilder->gpu();
+    if (gpu->glCaps().fbFetchSupport()) {
+        this->addFeature(1 << (GrGLFragmentShaderBuilder::kLastGLSLPrivateFeature + 1),
+                         gpu->glCaps().fbFetchExtensionString());
+        return gpu->glCaps().fbFetchColorName();
+    } else if (fProgramBuilder->fUniformHandles.fDstCopySamplerUni.isValid()) {
+        return kDstCopyColorName;
+    } else {
+        return "";
+    }
+}
+
+bool GrGLFragmentShaderBuilder::enableFeature(GLSLFeature feature) {
+    switch (feature) {
+        case kStandardDerivatives_GLSLFeature: {
+            GrGpuGL* gpu = fProgramBuilder->gpu();
+            if (!gpu->glCaps().shaderDerivativeSupport()) {
+                return false;
+            }
+            if (kGLES_GrGLStandard == gpu->glStandard()) {
+                this->addFeature(1 << kStandardDerivatives_GLSLFeature,
+                                 "GL_OES_standard_derivatives");
+            }
+            return true;
+        }
+        default:
+            SkFAIL("Unexpected GLSLFeature requested.");
+            return false;
+    }
+}
+
+SkString GrGLFragmentShaderBuilder::ensureFSCoords2D(const TransformedCoordsArray& coords, int index) {
+    if (kVec3f_GrSLType != coords[index].type()) {
+        SkASSERT(kVec2f_GrSLType == coords[index].type());
+        return coords[index].getName();
+    }
+
+    SkString coords2D("coords2D");
+    if (0 != index) {
+        coords2D.appendf("_%i", index);
+    }
+    this->codeAppendf("\tvec2 %s = %s.xy / %s.z;",
+                      coords2D.c_str(), coords[index].c_str(), coords[index].c_str());
+    return coords2D;
+}
+
+const char* GrGLFragmentShaderBuilder::fragmentPosition() {
+    GrGLProgramBuilder::CodeStage* cs = &fProgramBuilder->fCodeStage;
+    if (cs->inStageCode()) {
+        const GrEffect* effect = cs->effectStage()->getEffect();
+        if (!effect->willReadFragmentPosition()) {
+            SkDEBUGFAIL("GrGLEffect asked for frag position but its generating GrEffect "
+                        "did not request access.");
+            return "";
+        }
+    }
+
+    GrGpuGL* gpu = fProgramBuilder->gpu();
+    // We only declare "gl_FragCoord" when we're in the case where we want to use layout qualifiers
+    // to reverse y. Otherwise it isn't necessary and whether the "in" qualifier appears in the
+    // declaration varies in earlier GLSL specs. So it is simpler to omit it.
+    if (fTopLeftFragPosRead) {
+        fSetupFragPosition = true;
+        return "gl_FragCoord";
+    } else if (gpu->glCaps().fragCoordConventionsSupport()) {
+        if (!fSetupFragPosition) {
+            if (gpu->glslGeneration() < k150_GrGLSLGeneration) {
+                this->addFeature(1 << kFragCoordConventions_GLSLPrivateFeature,
+                                 "GL_ARB_fragment_coord_conventions");
+            }
+            fInputs.push_back().set(kVec4f_GrSLType,
+                                    GrGLShaderVar::kIn_TypeModifier,
+                                    "gl_FragCoord",
+                                    GrGLShaderVar::kDefault_Precision,
+                                    GrGLShaderVar::kUpperLeft_Origin);
+            fSetupFragPosition = true;
+        }
+        return "gl_FragCoord";
+    } else {
+        static const char* kCoordName = "fragCoordYDown";
+        if (!fSetupFragPosition) {
+            // temporarily change the stage index because we're inserting non-stage code.
+            GrGLProgramBuilder::CodeStage::AutoStageRestore csar(cs, NULL);
+
+            SkASSERT(!fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
+            const char* rtHeightName;
+
+            fProgramBuilder->fUniformHandles.fRTHeightUni =
+                    fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                         kFloat_GrSLType,
+                                         "RTHeight",
+                                         &rtHeightName);
+
+            // Using glFragCoord.zw for the last two components tickles an Adreno driver bug that
+            // causes programs to fail to link. Making this function return a vec2() didn't fix the
+            // problem but using 1.0 for the last two components does.
+            this->codePrependf("\tvec4 %s = vec4(gl_FragCoord.x, %s - gl_FragCoord.y, 1.0, "
+                               "1.0);\n", kCoordName, rtHeightName);
+            fSetupFragPosition = true;
+        }
+        SkASSERT(fProgramBuilder->fUniformHandles.fRTHeightUni.isValid());
+        return kCoordName;
+    }
+}
+
+void GrGLFragmentShaderBuilder::addVarying(GrSLType type,
+               const char* name,
+               const char** fsInName) {
+    fInputs.push_back().set(type, GrGLShaderVar::kVaryingIn_TypeModifier, name);
+    if (fsInName) {
+        *fsInName = name;
+    }
+}
+
+void GrGLFragmentShaderBuilder::bindProgramLocations(GrGLuint programId) {
+    GrGpuGL* gpu = fProgramBuilder->gpu();
+    if (fHasCustomColorOutput) {
+        GL_CALL(BindFragDataLocation(programId, 0, declared_color_output_name()));
+    }
+    if (fHasSecondaryOutput) {
+        GL_CALL(BindFragDataLocationIndexed(programId, 0, 1, dual_source_output_name()));
+    }
+}
+
+bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
+                                                        SkTDArray<GrGLuint>* shaderIds) const {
+    GrGpuGL* gpu = fProgramBuilder->gpu();
+    SkString fragShaderSrc(GrGetGLSLVersionDecl(gpu->ctxInfo()));
+    fragShaderSrc.append(fExtensions);
+    append_default_precision_qualifier(kDefaultFragmentPrecision,
+                                       gpu->glStandard(),
+                                       &fragShaderSrc);
+    fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kFragment_Visibility, &fragShaderSrc);
+    fProgramBuilder->appendDecls(fInputs, &fragShaderSrc);
+    // We shouldn't have declared outputs on 1.10
+    SkASSERT(k110_GrGLSLGeneration != gpu->glslGeneration() || fOutputs.empty());
+    fProgramBuilder->appendDecls(fOutputs, &fragShaderSrc);
+    fragShaderSrc.append(fFunctions);
+    fragShaderSrc.append("void main() {\n");
+    fragShaderSrc.append(fCode);
+    fragShaderSrc.append("}\n");
+
+    GrGLuint fragShaderId = GrGLCompileAndAttachShader(gpu->glContext(),
+            programId, GR_GL_FRAGMENT_SHADER, fragShaderSrc);
+    if (!fragShaderId) {
+        return false;
+    }
+
+    *shaderIds->append() = fragShaderId;
+
+    return true;
+}
+
+void GrGLFragmentShaderBuilder::emitCodeBeforeEffects() {
+    const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader();
+    GrGpuGL* gpu = fProgramBuilder->gpu();
+
+    ///////////////////////////////////////////////////////////////////////////
+    // emit code to read the dst copy texture, if necessary
+    if (kNoDstRead_DstReadKey != header.fDstReadKey && !gpu->glCaps().fbFetchSupport()) {
+        bool topDown = SkToBool(kTopLeftOrigin_DstReadKeyBit & header.fDstReadKey);
+        const char* dstCopyTopLeftName;
+        const char* dstCopyCoordScaleName;
+        const char* dstCopySamplerName;
+        uint32_t configMask;
+        if (SkToBool(kUseAlphaConfig_DstReadKeyBit & header.fDstReadKey)) {
+            configMask = kA_GrColorComponentFlag;
+        } else {
+            configMask = kRGBA_GrColorComponentFlags;
+        }
+        fProgramBuilder->fUniformHandles.fDstCopySamplerUni =
+            fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                 kSampler2D_GrSLType,
+                                 "DstCopySampler",
+                                 &dstCopySamplerName);
+        fProgramBuilder->fUniformHandles.fDstCopyTopLeftUni =
+            fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                 kVec2f_GrSLType,
+                                 "DstCopyUpperLeft",
+                                 &dstCopyTopLeftName);
+        fProgramBuilder->fUniformHandles.fDstCopyScaleUni =
+            fProgramBuilder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                                 kVec2f_GrSLType,
+                                 "DstCopyCoordScale",
+                                 &dstCopyCoordScaleName);
+        const char* fragPos = fragmentPosition();
+
+        this->codeAppend("// Read color from copy of the destination.\n");
+        this->codeAppendf("vec2 _dstTexCoord = (%s.xy - %s) * %s;",
+                          fragPos, dstCopyTopLeftName, dstCopyCoordScaleName);
+        if (!topDown) {
+            this->codeAppend("_dstTexCoord.y = 1.0 - _dstTexCoord.y;");
+        }
+        this->codeAppendf("vec4 %s = ", kDstCopyColorName);
+        this->appendTextureLookup(dstCopySamplerName,
+                                  "_dstTexCoord",
+                                  configMask,
+                                  "rgba");
+        this->codeAppend(";");
+    }
+
+    if (k110_GrGLSLGeneration != gpu->glslGeneration()) {
+        fOutputs.push_back().set(kVec4f_GrSLType,
+                                 GrGLShaderVar::kOut_TypeModifier,
+                                 declared_color_output_name());
+        fHasCustomColorOutput = true;
+    }
+}
+
+void GrGLFragmentShaderBuilder::emitCodeAfterEffects(const GrGLSLExpr4& inputColor, const GrGLSLExpr4& inputCoverage) {
+    const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader();
+
+    ///////////////////////////////////////////////////////////////////////////
+    // write the secondary color output if necessary
+    if (GrGLProgramDesc::CoverageOutputUsesSecondaryOutput(header.fCoverageOutput)) {
+        const char* secondaryOutputName = this->enableSecondaryOutput();
+
+        // default coeff to ones for kCoverage_DualSrcOutput
+        GrGLSLExpr4 coeff(1);
+        if (GrGLProgramDesc::kSecondaryCoverageISA_CoverageOutput == header.fCoverageOutput) {
+            // Get (1-A) into coeff
+            coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a());
+        } else if (GrGLProgramDesc::kSecondaryCoverageISC_CoverageOutput ==
+                   header.fCoverageOutput){
+            // Get (1-RGBA) into coeff
+            coeff = GrGLSLExpr4(1) - inputColor;
+        }
+        // Get coeff * coverage into modulate and then write that to the dual source output.
+        codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage).c_str());
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+    // combine color and coverage as frag color
+
+    // Get "color * coverage" into fragColor
+    GrGLSLExpr4 fragColor = inputColor * inputCoverage;
+    // Now tack on "+(1-coverage)dst onto the frag color if we were asked to do so.
+    if (GrGLProgramDesc::kCombineWithDst_CoverageOutput == header.fCoverageOutput) {
+        GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage;
+
+        GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(dstColor());
+
+        fragColor = fragColor + dstContribution;
+    }
+    codeAppendf("\t%s = %s;\n", this->getColorOutputName(), fragColor.c_str());
+}
+
+const char* GrGLFragmentShaderBuilder::enableSecondaryOutput() {
+    if (!fHasSecondaryOutput) {
+        fOutputs.push_back().set(kVec4f_GrSLType,
+                                 GrGLShaderVar::kOut_TypeModifier,
+                                 dual_source_output_name());
+        fHasSecondaryOutput = true;
+    }
+    return dual_source_output_name();
+}
+
+const char* GrGLFragmentShaderBuilder::getColorOutputName() const {
+    return fHasCustomColorOutput ? declared_color_output_name() : "gl_FragColor";
+}
+
diff --git a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h
new file mode 100644
index 0000000..0f700bd
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLFragmentShaderBuilder_DEFINED
+#define GrGLFragmentShaderBuilder_DEFINED
+#include "GrGLShaderBuilder.h"
+
+class GrGLProgramBuilder;
+
+class GrGLFragmentShaderBuilder : public GrGLShaderBuilder {
+public:
+    typedef uint8_t DstReadKey;
+    typedef uint8_t FragPosKey;
+
+    /**  Returns a key for adding code to read the copy-of-dst color in service of effects that
+        require reading the dst. It must not return 0 because 0 indicates that there is no dst
+        copy read at all (in which case this function should not be called). */
+    static DstReadKey KeyForDstRead(const GrTexture* dstCopy, const GrGLCaps&);
+
+    /** Returns a key for reading the fragment location. This should only be called if there is an
+       effect that will requires the fragment position. If the fragment position is not required,
+       the key is 0. */
+    static FragPosKey KeyForFragmentPosition(const GrRenderTarget* dst, const GrGLCaps&);
+
+    GrGLFragmentShaderBuilder(GrGLProgramBuilder* program, const GrGLProgramDesc& desc);
+
+    /** Returns the variable name that holds the color of the destination pixel. This may be NULL if
+        no effect advertised that it will read the destination. */
+    const char* dstColor();
+
+    /**
+     * Use of these features may require a GLSL extension to be enabled. Shaders may not compile
+     * if code is added that uses one of these features without calling enableFeature()
+     */
+    enum GLSLFeature {
+        kStandardDerivatives_GLSLFeature = 0,
+        kLastGLSLFeature = kStandardDerivatives_GLSLFeature
+    };
+
+    /**
+     * If the feature is supported then true is returned and any necessary #extension declarations
+     * are added to the shaders. If the feature is not supported then false will be returned.
+     */
+    bool enableFeature(GLSLFeature);
+
+    /**
+     * This returns a variable name to access the 2D, perspective correct version of the coords in
+     * the fragment shader. If the coordinates at index are 3-dimensional, it immediately emits a
+     * perspective divide into the fragment shader (xy / z) to convert them to 2D.
+     */
+    SkString ensureFSCoords2D(const TransformedCoordsArray& coords, int index);
+
+
+    /** Returns a variable name that represents the position of the fragment in the FS. The position
+        is in device space (e.g. 0,0 is the top left and pixel centers are at half-integers). */
+    const char* fragmentPosition();
+
+private:
+    /*
+     * An internal call for GrGLFullProgramBuilder to use to add varyings to the vertex shader
+     */
+    void addVarying(GrSLType type,
+                   const char* name,
+                   const char** fsInName);
+
+    /*
+     * Private functions used by GrGLProgramBuilder for compilation
+    */
+    void bindProgramLocations(GrGLuint programId);
+    bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
+    void emitCodeBeforeEffects();
+    void emitCodeAfterEffects(const GrGLSLExpr4& inputColor, const GrGLSLExpr4& inputCoverage);
+
+    /** Enables using the secondary color output and returns the name of the var in which it is
+        to be stored */
+    const char* enableSecondaryOutput();
+
+    /** Gets the name of the primary color output. */
+    const char* getColorOutputName() const;
+
+    /**
+     * Features that should only be enabled by GrGLFragmentShaderBuilder itself.
+     */
+    enum GLSLPrivateFeature {
+        kFragCoordConventions_GLSLPrivateFeature = kLastGLSLFeature + 1,
+        kLastGLSLPrivateFeature = kFragCoordConventions_GLSLPrivateFeature
+    };
+
+    // Interpretation of DstReadKey when generating code
+    enum {
+        kNoDstRead_DstReadKey           = 0,
+        kYesDstRead_DstReadKeyBit       = 0x1, // Set if we do a dst-copy-read.
+        kUseAlphaConfig_DstReadKeyBit   = 0x2, // Set if dst-copy config is alpha only.
+        kTopLeftOrigin_DstReadKeyBit    = 0x4, // Set if dst-copy origin is top-left.
+    };
+
+    enum {
+        kNoFragPosRead_FragPosKey           = 0,  // The fragment positition will not be needed.
+        kTopLeftFragPosRead_FragPosKey      = 0x1,// Read frag pos relative to top-left.
+        kBottomLeftFragPosRead_FragPosKey   = 0x2,// Read frag pos relative to bottom-left.
+    };
+
+    bool fHasCustomColorOutput;
+    bool fHasSecondaryOutput;
+    bool fSetupFragPosition;
+    bool fTopLeftFragPosRead;
+
+    friend class GrGLProgramBuilder;
+    friend class GrGLFullProgramBuilder;
+
+    typedef GrGLShaderBuilder INHERITED;
+};
+
+#endif
diff --git a/src/gpu/gl/builders/GrGLGeometryShaderBuilder.cpp b/src/gpu/gl/builders/GrGLGeometryShaderBuilder.cpp
new file mode 100644
index 0000000..6cdf2f9
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLGeometryShaderBuilder.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLGeometryShaderBuilder.h"
+#include "GrGLShaderStringBuilder.h"
+#include "GrGLProgramBuilder.h"
+#include "../GrGpuGL.h"
+
+GrGLGeometryShaderBuilder::GrGLGeometryShaderBuilder(GrGLFullProgramBuilder* program)
+    : INHERITED(program) {
+
+}
+
+void GrGLGeometryShaderBuilder::addVarying(GrSLType type,
+               const char* name,
+               const char** gsOutName) {
+    // 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();
+    }
+}
+
+
+bool GrGLGeometryShaderBuilder::compileAndAttachShaders(GrGLuint programId,
+        SkTDArray<GrGLuint>* shaderIds) const {
+    const GrGLContext& glCtx = fProgramBuilder->gpu()->glContext();
+    SkASSERT(fProgramBuilder->ctxInfo().glslGeneration() >= k150_GrGLSLGeneration);
+    SkString geomShaderSrc(GrGetGLSLVersionDecl(fProgramBuilder->ctxInfo()));
+    geomShaderSrc.append("layout(triangles) in;\n"
+                         "layout(triangle_strip, max_vertices = 6) out;\n");
+    fProgramBuilder->appendDecls(fInputs, &geomShaderSrc);
+    fProgramBuilder->appendDecls(fOutputs, &geomShaderSrc);
+    geomShaderSrc.append("void main() {\n");
+    geomShaderSrc.append("\tfor (int i = 0; i < 3; ++i) {\n"
+                         "\t\tgl_Position = gl_in[i].gl_Position;\n");
+    if (fProgramBuilder->desc().getHeader().fEmitsPointSize) {
+        geomShaderSrc.append("\t\tgl_PointSize = 1.0;\n");
+    }
+    SkASSERT(fInputs.count() == fOutputs.count());
+    for (int i = 0; i < fInputs.count(); ++i) {
+        geomShaderSrc.appendf("\t\t%s = %s[i];\n",
+                              fOutputs[i].getName().c_str(),
+                              fInputs[i].getName().c_str());
+    }
+    geomShaderSrc.append("\t\tEmitVertex();\n"
+                         "\t}\n"
+                         "\tEndPrimitive();\n");
+    geomShaderSrc.append("}\n");
+    GrGLuint geomShaderId =
+            GrGLCompileAndAttachShader(glCtx, programId, GR_GL_GEOMETRY_SHADER, geomShaderSrc);
+    if (!geomShaderId) {
+        return false;
+    }
+    *shaderIds->append() = geomShaderId;
+    return true;
+}
diff --git a/src/gpu/gl/builders/GrGLGeometryShaderBuilder.h b/src/gpu/gl/builders/GrGLGeometryShaderBuilder.h
new file mode 100644
index 0000000..833d317
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLGeometryShaderBuilder.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLGeometryShaderBuilder_DEFINED
+#define GrGLGeometryShaderBuilder_DEFINED
+
+#include "GrGLShaderBuilder.h"
+
+class GrGLProgramBuilder;
+
+class GrGLGeometryShaderBuilder : public GrGLFullShaderBuilder {
+public:
+    GrGLGeometryShaderBuilder(GrGLFullProgramBuilder* program);
+private:
+    /*
+     * an internal call for GrGLFullProgramBuilder to add varyings
+     */
+    void addVarying(GrSLType type,
+                   const char* name,
+                   const char** gsOutName);
+
+    bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
+
+    friend class GrGLFullProgramBuilder;
+    typedef GrGLFullShaderBuilder INHERITED;
+};
+
+#endif
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
new file mode 100644
index 0000000..f4ee32b
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -0,0 +1,409 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gl/GrGLProgram.h"
+#include "gl/GrGLSLPrettyPrint.h"
+#include "gl/GrGLUniformHandle.h"
+#include "GrCoordTransform.h"
+#include "GrDrawEffect.h"
+#include "../GrGpuGL.h"
+#include "GrGLFragmentShaderBuilder.h"
+#include "GrGLProgramBuilder.h"
+#include "GrTexture.h"
+#include "GrGLVertexShaderBuilder.h"
+#include "SkRTConf.h"
+#include "SkTraceEvent.h"
+
+namespace {
+#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
+#define GL_CALL_RET(R, X) GR_GL_CALL_RET(this->gpu()->glInterface(), R, X)
+
+// number of each input/output type in a single allocation block
+static const int kVarsPerBlock = 8;
+
+// ES2 FS only guarantees mediump and lowp support
+static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool GrGLProgramBuilder::genProgram(const GrEffectStage* colorStages[],
+                                    const GrEffectStage* coverageStages[]) {
+    const GrGLProgramDesc::KeyHeader& header = this->desc().getHeader();
+
+    fFS.emitCodeBeforeEffects();
+
+    ///////////////////////////////////////////////////////////////////////////
+    // get the initial color and coverage to feed into the first effect in each effect chain
+
+    GrGLSLExpr4 inputColor;
+    GrGLSLExpr4 inputCoverage;
+
+    if (GrGLProgramDesc::kUniform_ColorInput == header.fColorInput) {
+        const char* name;
+        fUniformHandles.fColorUni =
+            this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                             kVec4f_GrSLType,
+                             "Color",
+                             &name);
+        inputColor = GrGLSLExpr4(name);
+    }
+
+    if (GrGLProgramDesc::kUniform_ColorInput == header.fCoverageInput) {
+        const char* name;
+        fUniformHandles.fCoverageUni =
+            this->addUniform(GrGLProgramBuilder::kFragment_Visibility,
+                             kVec4f_GrSLType,
+                             "Coverage",
+                             &name);
+        inputCoverage = GrGLSLExpr4(name);
+    } else if (GrGLProgramDesc::kSolidWhite_ColorInput == header.fCoverageInput) {
+        inputCoverage = GrGLSLExpr4(1);
+    }
+
+    this->emitCodeBeforeEffects(&inputColor, &inputCoverage);
+
+    ///////////////////////////////////////////////////////////////////////////
+    // emit the per-effect code for both color and coverage effects
+
+    GrGLProgramDesc::EffectKeyProvider colorKeyProvider(
+        &this->desc(), GrGLProgramDesc::EffectKeyProvider::kColor_EffectType);
+    fColorEffects.reset(this->createAndEmitEffects(colorStages,
+                                                   this->desc().numColorEffects(),
+                                                   colorKeyProvider,
+                                                   &inputColor));
+
+    GrGLProgramDesc::EffectKeyProvider coverageKeyProvider(
+        &this->desc(), GrGLProgramDesc::EffectKeyProvider::kCoverage_EffectType);
+    fCoverageEffects.reset(this->createAndEmitEffects(coverageStages,
+                                                      this->desc().numCoverageEffects(),
+                                                      coverageKeyProvider,
+                                                      &inputCoverage));
+
+    this->emitCodeAfterEffects();
+
+    fFS.emitCodeAfterEffects(inputColor, inputCoverage);
+
+    if (!this->finish()) {
+        return false;
+    }
+
+    return true;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+GrGLProgramBuilder::GrGLProgramBuilder(GrGpuGL* gpu,
+                                       const GrGLProgramDesc& desc)
+    : fFragOnly(!desc.getHeader().fHasVertexCode && gpu->shouldUseFixedFunctionTexturing())
+    , fTexCoordSetCnt(0)
+    , fProgramID(0)
+    , fFS(this, desc)
+    , fDesc(desc)
+    , fGpu(gpu)
+    , fUniforms(kVarsPerBlock) {
+}
+
+void GrGLProgramBuilder::nameVariable(SkString* out, char prefix, const char* name) {
+    if ('\0' == prefix) {
+        *out = name;
+    } else {
+        out->printf("%c%s", prefix, name);
+    }
+    if (fCodeStage.inStageCode()) {
+        if (out->endsWith('_')) {
+            // Names containing "__" are reserved.
+            out->append("x");
+        }
+        out->appendf("_Stage%d", fCodeStage.stageIndex());
+    }
+}
+
+GrGLProgramDataManager::UniformHandle GrGLProgramBuilder::addUniformArray(uint32_t visibility,
+                                                                          GrSLType type,
+                                                                          const char* name,
+                                                                          int count,
+                                                                          const char** outName) {
+    SkASSERT(name && strlen(name));
+    SkDEBUGCODE(static const uint32_t kVisibilityMask = kVertex_Visibility | kFragment_Visibility);
+    SkASSERT(0 == (~kVisibilityMask & visibility));
+    SkASSERT(0 != visibility);
+
+    UniformInfo& uni = fUniforms.push_back();
+    uni.fVariable.setType(type);
+    uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
+    this->nameVariable(uni.fVariable.accessName(), 'u', name);
+    uni.fVariable.setArrayCount(count);
+    uni.fVisibility = visibility;
+
+    // If it is visible in both the VS and FS, the precision must match.
+    // We declare a default FS precision, but not a default VS. So set the var
+    // to use the default FS precision.
+    if ((kVertex_Visibility | kFragment_Visibility) == visibility) {
+        // the fragment and vertex precisions must match
+        uni.fVariable.setPrecision(kDefaultFragmentPrecision);
+    }
+
+    if (NULL != outName) {
+        *outName = uni.fVariable.c_str();
+    }
+    return GrGLProgramDataManager::UniformHandle::CreateFromUniformIndex(fUniforms.count() - 1);
+}
+
+void GrGLProgramBuilder::appendDecls(const VarArray& vars, SkString* out) const {
+    for (int i = 0; i < vars.count(); ++i) {
+        vars[i].appendDecl(this->ctxInfo(), out);
+        out->append(";\n");
+    }
+}
+
+void GrGLProgramBuilder::appendUniformDecls(ShaderVisibility visibility,
+                                            SkString* out) const {
+    for (int i = 0; i < fUniforms.count(); ++i) {
+        if (fUniforms[i].fVisibility & visibility) {
+            fUniforms[i].fVariable.appendDecl(this->ctxInfo(), out);
+            out->append(";\n");
+        }
+    }
+}
+
+void GrGLProgramBuilder::createAndEmitEffects(GrGLProgramEffectsBuilder* programEffectsBuilder,
+                                              const GrEffectStage* effectStages[],
+                                              int effectCnt,
+                                              const GrGLProgramDesc::EffectKeyProvider& keyProvider,
+                                              GrGLSLExpr4* fsInOutColor) {
+    bool effectEmitted = false;
+
+    GrGLSLExpr4 inColor = *fsInOutColor;
+    GrGLSLExpr4 outColor;
+
+    for (int e = 0; e < effectCnt; ++e) {
+        SkASSERT(NULL != effectStages[e] && NULL != effectStages[e]->getEffect());
+        const GrEffectStage& stage = *effectStages[e];
+
+        CodeStage::AutoStageRestore csar(&fCodeStage, &stage);
+
+        if (inColor.isZeros()) {
+            SkString inColorName;
+
+            // Effects have no way to communicate zeros, they treat an empty string as ones.
+            this->nameVariable(&inColorName, '\0', "input");
+            fFS.codeAppendf("\tvec4 %s = %s;\n", inColorName.c_str(), inColor.c_str());
+            inColor = inColorName;
+        }
+
+        // create var to hold stage result
+        SkString outColorName;
+        this->nameVariable(&outColorName, '\0', "output");
+        fFS.codeAppendf("\tvec4 %s;\n", outColorName.c_str());
+        outColor = outColorName;
+
+
+        programEffectsBuilder->emitEffect(stage,
+                                          keyProvider.get(e),
+                                          outColor.c_str(),
+                                          inColor.isOnes() ? NULL : inColor.c_str(),
+                                          fCodeStage.stageIndex());
+
+        inColor = outColor;
+        effectEmitted = true;
+    }
+
+    if (effectEmitted) {
+        *fsInOutColor = outColor;
+    }
+}
+
+bool GrGLProgramBuilder::finish() {
+    SkASSERT(0 == fProgramID);
+    GL_CALL_RET(fProgramID, CreateProgram());
+    if (!fProgramID) {
+        return false;
+    }
+
+    SkTDArray<GrGLuint> shadersToDelete;
+
+    if (!this->compileAndAttachShaders(fProgramID, &shadersToDelete)) {
+        GL_CALL(DeleteProgram(fProgramID));
+        return false;
+    }
+
+    this->bindProgramLocations(fProgramID);
+
+    GL_CALL(LinkProgram(fProgramID));
+
+    // Calling GetProgramiv is expensive in Chromium. Assume success in release builds.
+    bool checkLinked = !fGpu->ctxInfo().isChromium();
+#ifdef SK_DEBUG
+    checkLinked = true;
+#endif
+    if (checkLinked) {
+        GrGLint linked = GR_GL_INIT_ZERO;
+        GL_CALL(GetProgramiv(fProgramID, GR_GL_LINK_STATUS, &linked));
+        if (!linked) {
+            GrGLint infoLen = GR_GL_INIT_ZERO;
+            GL_CALL(GetProgramiv(fProgramID, GR_GL_INFO_LOG_LENGTH, &infoLen));
+            SkAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
+            if (infoLen > 0) {
+                // retrieve length even though we don't need it to workaround
+                // bug in chrome cmd buffer param validation.
+                GrGLsizei length = GR_GL_INIT_ZERO;
+                GL_CALL(GetProgramInfoLog(fProgramID,
+                                          infoLen+1,
+                                          &length,
+                                          (char*)log.get()));
+                GrPrintf((char*)log.get());
+            }
+            SkDEBUGFAIL("Error linking program");
+            GL_CALL(DeleteProgram(fProgramID));
+            fProgramID = 0;
+            return false;
+        }
+    }
+
+    this->resolveProgramLocations(fProgramID);
+
+    for (int i = 0; i < shadersToDelete.count(); ++i) {
+      GL_CALL(DeleteShader(shadersToDelete[i]));
+    }
+
+    return true;
+}
+
+bool GrGLProgramBuilder::compileAndAttachShaders(GrGLuint programId,
+                                                 SkTDArray<GrGLuint>* shaderIds) const {
+    return fFS.compileAndAttachShaders(programId, shaderIds);
+}
+
+void GrGLProgramBuilder::bindProgramLocations(GrGLuint programId) {
+    fFS.bindProgramLocations(programId);
+
+    // skbug.com/2056
+    bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
+    if (usingBindUniform) {
+        int count = fUniforms.count();
+        for (int i = 0; i < count; ++i) {
+            GL_CALL(BindUniformLocation(programId, i, fUniforms[i].fVariable.c_str()));
+            fUniforms[i].fLocation = i;
+        }
+    }
+}
+
+void GrGLProgramBuilder::resolveProgramLocations(GrGLuint programId) {
+    bool usingBindUniform = fGpu->glInterface()->fFunctions.fBindUniformLocation != NULL;
+    if (!usingBindUniform) {
+        int count = fUniforms.count();
+        for (int i = 0; i < count; ++i) {
+            GrGLint location;
+            GL_CALL_RET(location,
+                        GetUniformLocation(programId, fUniforms[i].fVariable.c_str()));
+            fUniforms[i].fLocation = location;
+        }
+    }
+}
+
+const GrGLContextInfo& GrGLProgramBuilder::ctxInfo() const {
+    return fGpu->ctxInfo();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrGLFullProgramBuilder::GrGLFullProgramBuilder(GrGpuGL* gpu,
+                                              const GrGLProgramDesc& desc)
+    : INHERITED(gpu, desc)
+    , fGS(this)
+    , fVS(this) {
+}
+
+void GrGLFullProgramBuilder::emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) {
+    fVS.emitCodeBeforeEffects(color, coverage);
+}
+
+void GrGLFullProgramBuilder::emitCodeAfterEffects() {
+    fVS.emitCodeAfterEffects();
+}
+
+void GrGLFullProgramBuilder::addVarying(GrSLType type,
+                                        const char* name,
+                                        const char** vsOutName,
+                                        const char** fsInName) {
+    fVS.addVarying(type, name, vsOutName);
+
+    SkString* fsInputName = fVS.fOutputs.back().accessName();
+
+#if GR_GL_EXPERIMENTAL_GS
+    if (desc().getHeader().fExperimentalGS) {
+       // TODO let the caller use these names
+       fGS.addVarying(type, fsInputName->c_str(), NULL);
+       fsInputName = fGS.fOutputs.back().accessName();
+    }
+#endif
+    fFS.addVarying(type, fsInputName->c_str(), fsInName);
+}
+
+GrGLProgramEffects* GrGLFullProgramBuilder::createAndEmitEffects(
+        const GrEffectStage* effectStages[],
+        int effectCnt,
+        const GrGLProgramDesc::EffectKeyProvider& keyProvider,
+        GrGLSLExpr4* inOutFSColor) {
+
+    GrGLVertexProgramEffectsBuilder programEffectsBuilder(this, effectCnt);
+    this->INHERITED::createAndEmitEffects(&programEffectsBuilder,
+                                          effectStages,
+                                          effectCnt,
+                                          keyProvider,
+                                          inOutFSColor);
+    return programEffectsBuilder.finish();
+}
+
+bool GrGLFullProgramBuilder::compileAndAttachShaders(GrGLuint programId,
+                                                     SkTDArray<GrGLuint>* shaderIds) const {
+    return INHERITED::compileAndAttachShaders(programId, shaderIds)
+         && fVS.compileAndAttachShaders(programId, shaderIds)
+#if GR_GL_EXPERIMENTAL_GS
+         && (!desc().getHeader().fExperimentalGS
+                 || fGS.compileAndAttachShaders(programId, shaderIds))
+#endif
+         ;
+}
+
+void GrGLFullProgramBuilder::bindProgramLocations(GrGLuint programId) {
+    fVS.bindProgramLocations(programId);
+    INHERITED::bindProgramLocations(programId);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+GrGLFragmentOnlyProgramBuilder::GrGLFragmentOnlyProgramBuilder(GrGpuGL* gpu,
+                                                               const GrGLProgramDesc& desc)
+    : INHERITED(gpu, desc) {
+    SkASSERT(!desc.getHeader().fHasVertexCode);
+    SkASSERT(gpu->glCaps().pathRenderingSupport());
+    SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fColorInput);
+    SkASSERT(GrGLProgramDesc::kAttribute_ColorInput != desc.getHeader().fCoverageInput);
+}
+
+int GrGLFragmentOnlyProgramBuilder::addTexCoordSets(int count) {
+    int firstFreeCoordSet = fTexCoordSetCnt;
+    fTexCoordSetCnt += count;
+    SkASSERT(gpu()->glCaps().maxFixedFunctionTextureCoords() >= fTexCoordSetCnt);
+    return firstFreeCoordSet;
+}
+
+GrGLProgramEffects* GrGLFragmentOnlyProgramBuilder::createAndEmitEffects(
+        const GrEffectStage* effectStages[], int effectCnt,
+        const GrGLProgramDesc::EffectKeyProvider& keyProvider, GrGLSLExpr4* inOutFSColor) {
+
+    GrGLPathTexGenProgramEffectsBuilder pathTexGenEffectsBuilder(this,
+                                                                 effectCnt);
+    this->INHERITED::createAndEmitEffects(&pathTexGenEffectsBuilder,
+                                          effectStages,
+                                          effectCnt,
+                                          keyProvider,
+                                          inOutFSColor);
+    return pathTexGenEffectsBuilder.finish();
+}
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
new file mode 100644
index 0000000..09f7eba
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLProgramBuilder_DEFINED
+#define GrGLProgramBuilder_DEFINED
+
+#include "GrAllocator.h"
+#include "GrBackendEffectFactory.h"
+#include "GrColor.h"
+#include "GrEffect.h"
+#include "GrGLFragmentShaderBuilder.h"
+#include "GrGLGeometryShaderBuilder.h"
+#include "GrGLVertexShaderBuilder.h"
+#include "SkTypes.h"
+#include "gl/GrGLProgramDesc.h"
+#include "gl/GrGLProgramEffects.h"
+#include "gl/GrGLSL.h"
+#include "gl/GrGLProgramDataManager.h"
+
+#include <stdarg.h>
+
+class GrGLContextInfo;
+class GrEffectStage;
+class GrGLProgramDesc;
+
+/**
+  Contains all the incremental state of a shader as it is being built,as well as helpers to
+  manipulate that state.
+*/
+class GrGLProgramBuilder {
+public:
+    enum ShaderVisibility {
+        kVertex_Visibility   = 0x1,
+        kGeometry_Visibility = 0x2,
+        kFragment_Visibility = 0x4,
+    };
+
+    typedef GrGLProgramDataManager::UniformHandle UniformHandle;
+
+    // Handles for program uniforms (other than per-effect uniforms)
+    struct BuiltinUniformHandles {
+        UniformHandle       fViewMatrixUni;
+        UniformHandle       fRTAdjustmentUni;
+        UniformHandle       fColorUni;
+        UniformHandle       fCoverageUni;
+
+        // We use the render target height to provide a y-down frag coord when specifying
+        // origin_upper_left is not supported.
+        UniformHandle       fRTHeightUni;
+
+        // Uniforms for computing texture coords to do the dst-copy lookup
+        UniformHandle       fDstCopyTopLeftUni;
+        UniformHandle       fDstCopyScaleUni;
+        UniformHandle       fDstCopySamplerUni;
+    };
+
+    struct UniformInfo {
+        GrGLShaderVar fVariable;
+        uint32_t      fVisibility;
+        GrGLint       fLocation;
+    };
+
+    // This uses an allocator rather than array so that the GrGLShaderVars don't move in memory
+    // after they are inserted. Users of GrGLShaderBuilder get refs to the vars and ptrs to their
+    // name strings. Otherwise, we'd have to hand out copies.
+    typedef GrTAllocator<UniformInfo> UniformInfoArray;
+
+    /** Generates a shader program.
+     *
+     * The program implements what is specified in the stages given as input.
+     * After successful generation, the builder result objects are available
+     * to be used.
+     * @return true if generation was successful.
+     */
+    bool genProgram(const GrEffectStage* inColorStages[],
+                    const GrEffectStage* inCoverageStages[]);
+
+    // Below are the results of the shader generation.
+
+    GrGLProgramEffects* getColorEffects() const { SkASSERT(fProgramID); return fColorEffects.get(); }
+    GrGLProgramEffects* getCoverageEffects() const { SkASSERT(fProgramID); return fCoverageEffects.get(); }
+    const BuiltinUniformHandles& getBuiltinUniformHandles() const {
+        SkASSERT(fProgramID);
+        return fUniformHandles;
+    }
+    GrGLuint getProgramID() const { SkASSERT(fProgramID); return fProgramID; }
+    bool hasVertexShader() const { SkASSERT(fProgramID); return !fFragOnly; }
+    int getTexCoordSetCount() const { SkASSERT(fProgramID); return fTexCoordSetCnt; }
+    const UniformInfoArray& getUniformInfos() const { return fUniforms; }
+
+    virtual ~GrGLProgramBuilder() {}
+
+    /** Add a uniform variable to the current program, that has visibility in one or more shaders.
+        visibility is a bitfield of ShaderVisibility values indicating from which shaders the
+        uniform should be accessible. At least one bit must be set. Geometry shader uniforms are not
+        supported at this time. The actual uniform name will be mangled. If outName is not NULL then
+        it will refer to the final uniform name after return. Use the addUniformArray variant to add
+        an array of uniforms. */
+    GrGLProgramDataManager::UniformHandle addUniform(uint32_t visibility,
+                                                     GrSLType type,
+                                                     const char* name,
+                                                     const char** outName = NULL) {
+        return this->addUniformArray(visibility, type, name, GrGLShaderVar::kNonArray, outName);
+    }
+    GrGLProgramDataManager::UniformHandle addUniformArray(uint32_t visibility,
+                                                          GrSLType type,
+                                                          const char* name,
+                                                          int arrayCount,
+                                                          const char** outName = NULL);
+
+    const GrGLShaderVar& getUniformVariable(GrGLProgramDataManager::UniformHandle u) const {
+        return fUniforms[u.toShaderBuilderIndex()].fVariable;
+    }
+
+    /**
+     * Shortcut for getUniformVariable(u).c_str()
+     */
+    const char* getUniformCStr(GrGLProgramDataManager::UniformHandle u) const {
+        return this->getUniformVariable(u).c_str();
+    }
+
+    const GrGLContextInfo& ctxInfo() const;
+
+    GrGLFragmentShaderBuilder* getFragmentShaderBuilder() { return &fFS; }
+
+protected:
+    typedef GrTAllocator<GrGLShaderVar> VarArray;
+    GrGLProgramBuilder(GrGpuGL*, const GrGLProgramDesc&);
+
+    GrGpuGL* gpu() const { return fGpu; }
+
+    const GrGLProgramDesc& desc() const { return fDesc; }
+
+    // Helper for emitEffects().
+    void createAndEmitEffects(GrGLProgramEffectsBuilder*,
+                              const GrEffectStage* effectStages[],
+                              int effectCnt,
+                              const GrGLProgramDesc::EffectKeyProvider&,
+                              GrGLSLExpr4* inOutFSColor);
+
+    // Generates a name for a variable. The generated string will be name prefixed by the prefix
+    // char (unless the prefix is '\0'). It also mangles the name to be stage-specific if we're
+    // generating stage code.
+    void nameVariable(SkString* out, char prefix, const char* name);
+
+    virtual bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
+
+    virtual void bindProgramLocations(GrGLuint programId);
+    void resolveProgramLocations(GrGLuint programId);
+
+    void appendDecls(const VarArray&, SkString*) const;
+    void appendUniformDecls(ShaderVisibility, SkString*) const;
+
+    SkAutoTUnref<GrGLProgramEffects> fColorEffects;
+    SkAutoTUnref<GrGLProgramEffects> fCoverageEffects;
+    BuiltinUniformHandles            fUniformHandles;
+    bool                             fFragOnly;
+    int                              fTexCoordSetCnt;
+    GrGLuint                         fProgramID;
+    GrGLFragmentShaderBuilder        fFS;
+private:
+    class CodeStage : SkNoncopyable {
+    public:
+        CodeStage() : fNextIndex(0), fCurrentIndex(-1), fEffectStage(NULL) {}
+
+        bool inStageCode() const {
+            this->validate();
+            return NULL != fEffectStage;
+        }
+
+        const GrEffectStage* effectStage() const {
+            this->validate();
+            return fEffectStage;
+        }
+
+        int stageIndex() const {
+            this->validate();
+            return fCurrentIndex;
+        }
+
+        class AutoStageRestore : SkNoncopyable {
+        public:
+            AutoStageRestore(CodeStage* codeStage, const GrEffectStage* newStage) {
+                SkASSERT(NULL != codeStage);
+                fSavedIndex = codeStage->fCurrentIndex;
+                fSavedEffectStage = codeStage->fEffectStage;
+
+                if (NULL == newStage) {
+                    codeStage->fCurrentIndex = -1;
+                } else {
+                    codeStage->fCurrentIndex = codeStage->fNextIndex++;
+                }
+                codeStage->fEffectStage = newStage;
+
+                fCodeStage = codeStage;
+            }
+            ~AutoStageRestore() {
+                fCodeStage->fCurrentIndex = fSavedIndex;
+                fCodeStage->fEffectStage = fSavedEffectStage;
+            }
+        private:
+            CodeStage*              fCodeStage;
+            int                     fSavedIndex;
+            const GrEffectStage*    fSavedEffectStage;
+        };
+    private:
+        void validate() const { SkASSERT((NULL == fEffectStage) == (-1 == fCurrentIndex)); }
+        int                     fNextIndex;
+        int                     fCurrentIndex;
+        const GrEffectStage*    fEffectStage;
+    } fCodeStage;
+
+    /**
+     * The base class will emit the fragment code that precedes the per-effect code and then call
+     * this function. The subclass can use it to insert additional fragment code that should
+     * execute before the effects' code and/or emit other shaders (e.g. geometry, vertex).
+     *
+     * The subclass can modify the initial color or coverage 
+     */
+    virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) = 0;
+
+    /**
+    * Adds code for effects and returns a GrGLProgramEffects* object. The caller is responsible for
+    * deleting it when finished. effectStages contains the effects to add. The effect key provider 
+    * is used to communicate the key each effect created in its GenKey function. inOutFSColor
+    * specifies the input color to the first stage and is updated to be the output color of the
+    * last stage. The handles to texture samplers for effectStage[i] are added to
+    * effectSamplerHandles[i].
+    */
+    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
+                                                     int effectCnt,
+                                                     const GrGLProgramDesc::EffectKeyProvider&,
+                                                     GrGLSLExpr4* inOutFSColor) = 0;
+
+    /**
+     * Similar to emitCodeBeforeEffects() but called after per-effect code is emitted.
+     */
+    virtual void emitCodeAfterEffects() = 0;
+
+    /**
+     * Compiles all the shaders, links them into a program, and writes the program id to the output
+     * struct.
+     **/
+    bool finish();
+
+    const GrGLProgramDesc&                  fDesc;
+    GrGpuGL*                                fGpu;
+    UniformInfoArray                        fUniforms;
+
+    friend class GrGLShaderBuilder;
+    friend class GrGLVertexShaderBuilder;
+    friend class GrGLFragmentShaderBuilder;
+    friend class GrGLGeometryShaderBuilder;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class GrGLFullProgramBuilder : public GrGLProgramBuilder {
+public:
+    GrGLFullProgramBuilder(GrGpuGL*, const GrGLProgramDesc&);
+
+   /** Add a varying variable to the current program to pass values between vertex and fragment
+        shaders. If the last two parameters are non-NULL, they are filled in with the name
+        generated. */
+    void addVarying(GrSLType type,
+                    const char* name,
+                    const char** vsOutName = NULL,
+                    const char** fsInName = NULL);
+
+    GrGLVertexShaderBuilder* getVertexShaderBuilder() { return &fVS; }
+
+private:
+    virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE;
+
+    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
+                                                     int effectCnt,
+                                                     const GrGLProgramDesc::EffectKeyProvider&,
+                                                     GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
+
+    virtual void emitCodeAfterEffects() SK_OVERRIDE;
+
+    virtual bool compileAndAttachShaders(GrGLuint programId,
+                                         SkTDArray<GrGLuint>* shaderIds) const SK_OVERRIDE;
+
+    virtual void bindProgramLocations(GrGLuint programId) SK_OVERRIDE;
+
+    GrGLGeometryShaderBuilder fGS;
+    GrGLVertexShaderBuilder   fVS;
+
+    typedef GrGLProgramBuilder INHERITED;
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+class GrGLFragmentOnlyProgramBuilder : public GrGLProgramBuilder {
+public:
+    GrGLFragmentOnlyProgramBuilder(GrGpuGL*, const GrGLProgramDesc&);
+
+    int addTexCoordSets(int count);
+
+private:
+    virtual void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) SK_OVERRIDE {}
+
+    virtual GrGLProgramEffects* createAndEmitEffects(const GrEffectStage* effectStages[],
+                                                     int effectCnt,
+                                                     const GrGLProgramDesc::EffectKeyProvider&,
+                                                     GrGLSLExpr4* inOutFSColor) SK_OVERRIDE;
+
+    virtual void emitCodeAfterEffects() SK_OVERRIDE {}
+
+    typedef GrGLProgramBuilder INHERITED;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGLSLPrettyPrint.cpp b/src/gpu/gl/builders/GrGLSLPrettyPrint.cpp
similarity index 100%
rename from src/gpu/gl/GrGLSLPrettyPrint.cpp
rename to src/gpu/gl/builders/GrGLSLPrettyPrint.cpp
diff --git a/src/gpu/gl/builders/GrGLShaderBuilder.cpp b/src/gpu/gl/builders/GrGLShaderBuilder.cpp
new file mode 100644
index 0000000..4dea142
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLShaderBuilder.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLShaderBuilder.h"
+#include "GrGLProgramBuilder.h"
+#include "../GrGpuGL.h"
+#include "../GrGLShaderVar.h"
+
+namespace {
+inline const char* sample_function_name(GrSLType type, GrGLSLGeneration glslGen) {
+    if (kVec2f_GrSLType == type) {
+        return glslGen >= k130_GrGLSLGeneration ? "texture" : "texture2D";
+    } else {
+        SkASSERT(kVec3f_GrSLType == type);
+        return glslGen >= k130_GrGLSLGeneration ? "textureProj" : "texture2DProj";
+    }
+}
+void append_texture_lookup(SkString* out,
+                           GrGpuGL* gpu,
+                           const char* samplerName,
+                           const char* coordName,
+                           uint32_t configComponentMask,
+                           const char* swizzle,
+                           GrSLType varyingType = kVec2f_GrSLType) {
+    SkASSERT(NULL != coordName);
+
+    out->appendf("%s(%s, %s)",
+                 sample_function_name(varyingType, gpu->glslGeneration()),
+                 samplerName,
+                 coordName);
+
+    char mangledSwizzle[5];
+
+    // The swizzling occurs using texture params instead of shader-mangling if ARB_texture_swizzle
+    // is available.
+    if (!gpu->glCaps().textureSwizzleSupport() &&
+        (kA_GrColorComponentFlag == configComponentMask)) {
+        char alphaChar = gpu->glCaps().textureRedSupport() ? 'r' : 'a';
+        int i;
+        for (i = 0; '\0' != swizzle[i]; ++i) {
+            mangledSwizzle[i] = alphaChar;
+        }
+        mangledSwizzle[i] ='\0';
+        swizzle = mangledSwizzle;
+    }
+    // For shader prettiness we omit the swizzle rather than appending ".rgba".
+    if (memcmp(swizzle, "rgba", 4)) {
+        out->appendf(".%s", swizzle);
+    }
+}
+static const int kVarsPerBlock = 8;
+}
+
+GrGLShaderBuilder::GrGLShaderBuilder(GrGLProgramBuilder* program)
+    : fProgramBuilder(program)
+    , fInputs(kVarsPerBlock)
+    , fOutputs(kVarsPerBlock)
+    , fFeaturesAddedMask(0) {
+}
+
+void GrGLShaderBuilder::emitFunction(GrSLType returnType,
+                                     const char* name,
+                                     int argCnt,
+                                     const GrGLShaderVar* args,
+                                     const char* body,
+                                     SkString* outName) {
+    fFunctions.append(GrGLSLTypeString(returnType));
+    fProgramBuilder->nameVariable(outName, '\0', name);
+    fFunctions.appendf(" %s", outName->c_str());
+    fFunctions.append("(");
+    const GrGLContextInfo& ctxInfo = fProgramBuilder->gpu()->ctxInfo();
+    for (int i = 0; i < argCnt; ++i) {
+        args[i].appendDecl(ctxInfo, &fFunctions);
+        if (i < argCnt - 1) {
+            fFunctions.append(", ");
+        }
+    }
+    fFunctions.append(") {\n");
+    fFunctions.append(body);
+    fFunctions.append("}\n\n");
+}
+
+void GrGLShaderBuilder::appendTextureLookup(SkString* out,
+                                            const TextureSampler& sampler,
+                                            const char* coordName,
+                                            GrSLType varyingType) const {
+    append_texture_lookup(out,
+                          fProgramBuilder->gpu(),
+                          fProgramBuilder->getUniformCStr(sampler.samplerUniform()),
+                          coordName,
+                          sampler.configComponentMask(),
+                          sampler.swizzle(),
+                          varyingType);
+}
+
+void GrGLShaderBuilder::appendTextureLookup(const TextureSampler& sampler,
+                                            const char* coordName,
+                                            GrSLType varyingType) {
+    this->appendTextureLookup(&fCode, sampler, coordName, varyingType);
+}
+
+void GrGLShaderBuilder::appendTextureLookupAndModulate(const char* modulation,
+                                                       const TextureSampler& sampler,
+                                                       const char* coordName,
+                                                       GrSLType varyingType) {
+    SkString lookup;
+    this->appendTextureLookup(&lookup, sampler, coordName, varyingType);
+    this->codeAppend((GrGLSLExpr4(modulation) * GrGLSLExpr4(lookup)).c_str());
+}
+
+
+const GrGLenum* GrGLShaderBuilder::GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps) {
+    if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) {
+        if (caps.textureRedSupport()) {
+            static const GrGLenum gRedSmear[] = { GR_GL_RED, GR_GL_RED, GR_GL_RED, GR_GL_RED };
+            return gRedSmear;
+        } else {
+            static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA,
+                                                    GR_GL_ALPHA, GR_GL_ALPHA };
+            return gAlphaSmear;
+        }
+    } else {
+        static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN, GR_GL_BLUE, GR_GL_ALPHA };
+        return gStraight;
+    }
+}
+
+void GrGLShaderBuilder::addFeature(uint32_t featureBit, const char* extensionName) {
+    if (!(featureBit & fFeaturesAddedMask)) {
+        fExtensions.appendf("#extension %s: require\n", extensionName);
+            fFeaturesAddedMask |= featureBit;
+    }
+}
+
+void GrGLShaderBuilder::appendTextureLookup(const char* samplerName,
+                                            const char* coordName,
+                                            uint32_t configComponentMask,
+                                            const char* swizzle) {
+    append_texture_lookup(&fCode,
+                          fProgramBuilder->gpu(),
+                          samplerName,
+                          coordName,
+                          configComponentMask,
+                          swizzle,
+                          kVec2f_GrSLType);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+GrGLFullShaderBuilder::GrGLFullShaderBuilder(GrGLFullProgramBuilder* program)
+    : INHERITED(program)
+    , fFullProgramBuilder(program) {}
diff --git a/src/gpu/gl/builders/GrGLShaderBuilder.h b/src/gpu/gl/builders/GrGLShaderBuilder.h
new file mode 100644
index 0000000..1d0fa6a
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLShaderBuilder.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLShaderBuilder_DEFINED
+#define GrGLShaderBuilder_DEFINED
+
+#include "gl/GrGLProgramDesc.h"
+#include "gl/GrGLProgramEffects.h"
+#include "gl/GrGLSL.h"
+#include "gl/GrGLProgramDataManager.h"
+#include "GrAllocator.h"
+#include "GrBackendEffectFactory.h"
+#include "GrColor.h"
+#include "GrEffect.h"
+#include "SkTypes.h"
+
+#include <stdarg.h>
+
+class GrGLContextInfo;
+class GrEffectStage;
+class GrGLProgramDesc;
+class GrGLProgramBuilder;
+class GrGLFullProgramBuilder;
+
+/**
+  base class for all shaders builders
+*/
+class GrGLShaderBuilder {
+public:
+    typedef GrGLProgramEffects::TransformedCoordsArray TransformedCoordsArray;
+    typedef GrGLProgramEffects::TextureSampler TextureSampler;
+    GrGLShaderBuilder(GrGLProgramBuilder* program);
+
+    void addInput(GrGLShaderVar i) { fInputs.push_back(i); }
+    void addOutput(GrGLShaderVar i) { fOutputs.push_back(i); }
+
+    /*
+     * We put texture lookups in the base class because it is TECHNICALLY possible to do texture
+     * lookups in any kind of shader.  However, for the time being using these calls on non-fragment
+     * shaders will result in a shader compilation error as texture sampler uniforms are only
+     * visible to the fragment shader.  It would not be hard to change this behavior, if someone
+     * actually wants to do texture lookups in a non-fragment shader
+     *
+     * TODO if append texture lookup is used on a non-fragment shader, sampler uniforms should be
+     * made visible to that shaders
+     */
+    /** 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. */
+    void appendTextureLookup(SkString* out,
+                             const TextureSampler&,
+                             const char* coordName,
+                             GrSLType coordType = kVec2f_GrSLType) const;
+
+    /** Version of above that appends the result to the fragment shader code instead.*/
+    void appendTextureLookup(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(const char* modulation,
+                                        const TextureSampler&,
+                                        const char* coordName,
+                                        GrSLType coordType = kVec2f_GrSLType);
+
+    /** If texture swizzling is available using tex parameters then it is preferred over mangling
+        the generated shader code. This potentially allows greater reuse of cached shaders. */
+    static const GrGLenum* GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps);
+
+    /**
+    * Called by GrGLEffects to add code to one of the shaders.
+    */
+    void codeAppendf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
+       va_list args;
+       va_start(args, format);
+       fCode.appendVAList(format, args);
+       va_end(args);
+    }
+
+    void codeAppend(const char* str) { fCode.append(str); }
+
+    void codePrependf(const char format[], ...) SK_PRINTF_LIKE(2, 3) {
+       va_list args;
+       va_start(args, format);
+       fCode.prependVAList(format, args);
+       va_end(args);
+    }
+
+    /** Emits a helper function outside of main() in the fragment shader. */
+    void emitFunction(GrSLType returnType,
+                      const char* name,
+                      int argCnt,
+                      const GrGLShaderVar* args,
+                      const char* body,
+                      SkString* outName);
+
+    /*
+     * Get parent builder for adding uniforms
+     */
+    GrGLProgramBuilder* getProgramBuilder() { return fProgramBuilder; }
+
+    /**
+     * Helper for begining and ending a block in the fragment code.
+     */
+    class ShaderBlock {
+    public:
+        ShaderBlock(GrGLShaderBuilder* builder) : fBuilder(builder) {
+            SkASSERT(NULL != builder);
+            fBuilder->codeAppend("{");
+        }
+
+        ~ShaderBlock() {
+            fBuilder->codeAppend("}");
+        }
+    private:
+        GrGLShaderBuilder* fBuilder;
+    };
+protected:
+
+    /*
+     * this super low level function is just for use internally to builders
+     */
+    void appendTextureLookup(const char* samplerName,
+                             const char* coordName,
+                             uint32_t configComponentMask,
+                             const char* swizzle);
+
+    /*
+     * A general function which enables an extension in a shader if the feature bit is not present
+     */
+    void addFeature(uint32_t featureBit, const char* extensionName);
+
+    typedef GrTAllocator<GrGLShaderVar> VarArray;
+
+    GrGLProgramBuilder* fProgramBuilder;
+
+    SkString fCode;
+    SkString fFunctions;
+    SkString fExtensions;
+
+    VarArray fInputs;
+    VarArray fOutputs;
+    uint32_t fFeaturesAddedMask;
+};
+
+
+/*
+ * Full Shader builder is the base class for shaders which are only accessible through full program
+ * builder, ie vertex, geometry, and later TCU / TES.  Using this base class, they can access the
+ * full program builder functionality through the full program pointer
+ */
+class GrGLFullShaderBuilder : public GrGLShaderBuilder {
+public:
+    GrGLFullShaderBuilder(GrGLFullProgramBuilder* program);
+
+    GrGLFullProgramBuilder* fullProgramBuilder() { return fFullProgramBuilder; }
+protected:
+    GrGLFullProgramBuilder* fFullProgramBuilder;
+private:
+    typedef GrGLShaderBuilder INHERITED;
+};
+#endif
diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
new file mode 100644
index 0000000..dff8c7e
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLShaderStringBuilder.h"
+#include "../GrGpuGL.h"
+#include "gl/GrGLSLPrettyPrint.h"
+#include "SkRTConf.h"
+#include "SkTraceEvent.h"
+
+#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
+#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
+
+SK_CONF_DECLARE(bool, c_PrintShaders, "gpu.printShaders", false,
+                "Print the source code for all shaders generated.");
+
+GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
+                                    GrGLuint programId,
+                                    GrGLenum type,
+                                    const SkString& shaderSrc) {
+    const GrGLInterface* gli = glCtx.interface();
+
+     GrGLuint shaderId;
+     GR_GL_CALL_RET(gli, shaderId, CreateShader(type));
+     if (0 == shaderId) {
+         return 0;
+     }
+
+ #ifdef SK_DEBUG
+     SkString prettySource = GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, false);
+     const GrGLchar* sourceStr = prettySource.c_str();
+     GrGLint sourceLength = static_cast<GrGLint>(prettySource.size());
+ #else
+     GrGLint sourceLength = static_cast<GrGLint>(shaderSrc.size());
+     const GrGLchar* sourceStr = shaderSrc.c_str();
+ #endif
+     GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength));
+     GR_GL_CALL(gli, CompileShader(shaderId));
+
+     // Calling GetShaderiv in Chromium is quite expensive. Assume success in release builds.
+     bool checkCompiled = !glCtx.isChromium();
+ #ifdef SK_DEBUG
+     checkCompiled = true;
+ #endif
+     if (checkCompiled) {
+         GrGLint compiled = GR_GL_INIT_ZERO;
+         GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_COMPILE_STATUS, &compiled));
+
+         if (!compiled) {
+             GrGLint infoLen = GR_GL_INIT_ZERO;
+             GR_GL_CALL(gli, GetShaderiv(shaderId, GR_GL_INFO_LOG_LENGTH, &infoLen));
+             SkAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
+             if (infoLen > 0) {
+                 // retrieve length even though we don't need it to workaround bug in Chromium cmd
+                 // buffer param validation.
+                 GrGLsizei length = GR_GL_INIT_ZERO;
+                 GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1,
+                                                  &length, (char*)log.get()));
+                 GrPrintf(GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, true).c_str());
+                 GrPrintf("\n%s", log.get());
+             }
+             SkDEBUGFAIL("Shader compilation failed!");
+             GR_GL_CALL(gli, DeleteShader(shaderId));
+             return 0;
+         }
+     }
+
+     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "skia_gpu::GLShader",
+                          TRACE_EVENT_SCOPE_THREAD, "shader", TRACE_STR_COPY(shaderSrc.c_str()));
+     if (c_PrintShaders) {
+         GrPrintf(GrGLSLPrettyPrint::PrettyPrintGLSL(shaderSrc, true).c_str());
+         GrPrintf("\n");
+     }
+
+     // Attach the shader, but defer deletion until after we have linked the program.
+     // This works around a bug in the Android emulator's GLES2 wrapper which
+     // will immediately delete the shader object and free its memory even though it's
+     // attached to a program, which then causes glLinkProgram to fail.
+     GR_GL_CALL(gli, AttachShader(programId, shaderId));
+
+     return shaderId;
+}
diff --git a/src/gpu/gl/builders/GrGLShaderStringBuilder.h b/src/gpu/gl/builders/GrGLShaderStringBuilder.h
new file mode 100644
index 0000000..8c18fa5
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLShaderStringBuilder.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLShaderStringBuilder_DEFINED
+#define GrGLShaderStringBuilder_DEFINED
+
+#include "GrAllocator.h"
+#include "gl/GrGLContext.h"
+#include "SkTypes.h"
+
+GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
+                                    GrGLuint programId,
+                                    GrGLenum type,
+                                    const SkString& shaderSrc);
+
+#endif
diff --git a/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp b/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
new file mode 100644
index 0000000..6abc085
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLVertexShaderBuilder.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGLVertexShaderBuilder.h"
+#include "GrGLProgramBuilder.h"
+#include "GrGLShaderStringBuilder.h"
+#include "../GrGpuGL.h"
+
+#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
+#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
+
+namespace {
+inline const char* color_attribute_name() { return "aColor"; }
+inline const char* coverage_attribute_name() { return "aCoverage"; }
+}
+
+GrGLVertexShaderBuilder::GrGLVertexShaderBuilder(GrGLFullProgramBuilder* program)
+    : INHERITED(program)
+    , fPositionVar(NULL)
+    , fLocalCoordsVar(NULL) {
+}
+bool GrGLVertexShaderBuilder::addAttribute(GrSLType type, const char* name) {
+    for (int i = 0; i < fInputs.count(); ++i) {
+        const GrGLShaderVar& attr = fInputs[i];
+        // if attribute already added, don't add it again
+        if (attr.getName().equals(name)) {
+            return false;
+        }
+    }
+    fInputs.push_back().set(type, GrGLShaderVar::kAttribute_TypeModifier, name);
+    return true;
+}
+
+bool GrGLVertexShaderBuilder::addEffectAttribute(int attributeIndex,
+                                               GrSLType type,
+                                               const SkString& name) {
+    if (!this->addAttribute(type, name.c_str())) {
+        return false;
+    }
+
+    fEffectAttributes.push_back().set(attributeIndex, name);
+    return true;
+}
+
+void GrGLVertexShaderBuilder::emitAttributes(const GrEffectStage& stage) {
+    int numAttributes = stage.getVertexAttribIndexCount();
+    const int* attributeIndices = stage.getVertexAttribIndices();
+    for (int a = 0; a < numAttributes; ++a) {
+        // TODO: Make addAttribute mangle the name.
+        SkString attributeName("aAttr");
+        attributeName.appendS32(attributeIndices[a]);
+        this->addEffectAttribute(attributeIndices[a],
+                                 stage.getEffect()->vertexAttribType(a),
+                                 attributeName);
+    }
+}
+
+const SkString* GrGLVertexShaderBuilder::getEffectAttributeName(int attributeIndex) const {
+    const AttributePair* attribEnd = fEffectAttributes.end();
+    for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) {
+        if (attrib->fIndex == attributeIndex) {
+            return &attrib->fName;
+        }
+    }
+
+    return NULL;
+}
+
+void GrGLVertexShaderBuilder::addVarying(GrSLType type, const char* name, const char** vsOutName) {
+    fOutputs.push_back();
+    fOutputs.back().setType(type);
+    fOutputs.back().setTypeModifier(GrGLShaderVar::kVaryingOut_TypeModifier);
+    fProgramBuilder->nameVariable(fOutputs.back().accessName(), 'v', name);
+
+    if (vsOutName) {
+        *vsOutName = fOutputs.back().getName().c_str();
+    }
+}
+
+
+void GrGLVertexShaderBuilder::bindProgramLocations(GrGLuint programId) {
+    const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader();
+    GrGpuGL* gpu = fProgramBuilder->gpu();
+
+    // Bind the attrib locations to same values for all shaders
+    SkASSERT(-1 != header.fPositionAttributeIndex);
+    GL_CALL(BindAttribLocation(programId,
+                               header.fPositionAttributeIndex,
+                               fPositionVar->c_str()));
+    if (-1 != header.fLocalCoordAttributeIndex) {
+        GL_CALL(BindAttribLocation(programId,
+                                   header.fLocalCoordAttributeIndex,
+                                   fLocalCoordsVar->c_str()));
+    }
+    if (-1 != header.fColorAttributeIndex) {
+        GL_CALL(BindAttribLocation(programId,
+                                   header.fColorAttributeIndex,
+                                   color_attribute_name()));
+    }
+    if (-1 != header.fCoverageAttributeIndex) {
+        GL_CALL(BindAttribLocation(programId,
+                                   header.fCoverageAttributeIndex,
+                                   coverage_attribute_name()));
+    }
+
+    const AttributePair* attribEnd = fEffectAttributes.end();
+    for (const AttributePair* attrib = fEffectAttributes.begin(); attrib != attribEnd; ++attrib) {
+         GL_CALL(BindAttribLocation(programId, attrib->fIndex, attrib->fName.c_str()));
+    }
+}
+
+bool GrGLVertexShaderBuilder::compileAndAttachShaders(GrGLuint programId,
+        SkTDArray<GrGLuint>* shaderIds) const {
+    GrGpuGL* gpu = fProgramBuilder->gpu();
+    const GrGLContext& glCtx = gpu->glContext();
+    const GrGLContextInfo& ctxInfo = gpu->ctxInfo();
+    SkString vertShaderSrc(GrGetGLSLVersionDecl(ctxInfo));
+    fProgramBuilder->appendUniformDecls(GrGLProgramBuilder::kVertex_Visibility, &vertShaderSrc);
+    fProgramBuilder->appendDecls(fInputs, &vertShaderSrc);
+    fProgramBuilder->appendDecls(fOutputs, &vertShaderSrc);
+    vertShaderSrc.append("void main() {\n");
+    vertShaderSrc.append(fCode);
+    vertShaderSrc.append("}\n");
+    GrGLuint vertShaderId = GrGLCompileAndAttachShader(glCtx, programId,
+            GR_GL_VERTEX_SHADER, vertShaderSrc);
+    if (!vertShaderId) {
+        return false;
+    }
+    *shaderIds->append() = vertShaderId;
+    return true;
+}
+
+void GrGLVertexShaderBuilder::emitCodeAfterEffects() {
+    const char* rtAdjustName;
+    fProgramBuilder->fUniformHandles.fRTAdjustmentUni =
+        fProgramBuilder->addUniform(GrGLProgramBuilder::kVertex_Visibility,
+                             kVec4f_GrSLType,
+                             "rtAdjustment",
+                             &rtAdjustName);
+
+    // Transform from Skia's device coords to GL's normalized device coords.
+    this->codeAppendf(
+        "\tgl_Position = vec4(dot(pos3.xz, %s.xy), dot(pos3.yz, %s.zw), 0, pos3.z);\n",
+        rtAdjustName, rtAdjustName);
+}
+
+void GrGLVertexShaderBuilder::emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage) {
+    const GrGLProgramDesc::KeyHeader& header = fProgramBuilder->desc().getHeader();
+
+    fPositionVar = &fInputs.push_back();
+    fPositionVar->set(kVec2f_GrSLType, GrGLShaderVar::kAttribute_TypeModifier, "aPosition");
+    if (-1 != header.fLocalCoordAttributeIndex) {
+        fLocalCoordsVar = &fInputs.push_back();
+        fLocalCoordsVar->set(kVec2f_GrSLType,
+                             GrGLShaderVar::kAttribute_TypeModifier,
+                             "aLocalCoords");
+    } else {
+        fLocalCoordsVar = fPositionVar;
+    }
+
+    const char* viewMName;
+    fProgramBuilder->fUniformHandles.fViewMatrixUni =
+            fProgramBuilder->addUniform(GrGLProgramBuilder::kVertex_Visibility,
+                                 kMat33f_GrSLType,
+                                 "ViewM",
+                                 &viewMName);
+
+    // Transform the position into Skia's device coords.
+    this->codeAppendf("\tvec3 pos3 = %s * vec3(%s, 1);\n",
+                      viewMName, fPositionVar->c_str());
+
+    // we output point size in the GS if present
+    if (header.fEmitsPointSize
+#if GR_GL_EXPERIMENTAL_GS
+        && !header.fExperimentalGS
+#endif
+        ) {
+        this->codeAppend("\tgl_PointSize = 1.0;\n");
+    }
+
+    if (GrGLProgramDesc::kAttribute_ColorInput == header.fColorInput) {
+        this->addAttribute(kVec4f_GrSLType, color_attribute_name());
+        const char *vsName, *fsName;
+        fFullProgramBuilder->addVarying(kVec4f_GrSLType, "Color", &vsName, &fsName);
+        this->codeAppendf("\t%s = %s;\n", vsName, color_attribute_name());
+        *color = fsName;
+    }
+
+    if (GrGLProgramDesc::kAttribute_ColorInput == header.fCoverageInput) {
+        this->addAttribute(kVec4f_GrSLType, coverage_attribute_name());
+        const char *vsName, *fsName;
+        fFullProgramBuilder->addVarying(kVec4f_GrSLType, "Coverage", &vsName, &fsName);
+        this->codeAppendf("\t%s = %s;\n", vsName, coverage_attribute_name());
+        *coverage = fsName;
+    }
+}
diff --git a/src/gpu/gl/builders/GrGLVertexShaderBuilder.h b/src/gpu/gl/builders/GrGLVertexShaderBuilder.h
new file mode 100644
index 0000000..c576f57
--- /dev/null
+++ b/src/gpu/gl/builders/GrGLVertexShaderBuilder.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLVertexShader_DEFINED
+#define GrGLVertexShader_DEFINED
+#include "GrGLShaderBuilder.h"
+
+class GrGLProgramBuilder;
+
+class GrGLVertexShaderBuilder : public GrGLFullShaderBuilder {
+public:
+    GrGLVertexShaderBuilder(GrGLFullProgramBuilder* program);
+
+    /*
+     * Add attribute will push a new attribute onto the end.  It will also assert if there is
+     * a duplicate attribute
+     */
+    bool addAttribute(GrSLType type, const char* name);
+
+    bool addEffectAttribute(int attributeIndex, GrSLType type, const SkString& name);
+
+    /*
+     * this call is only for GrGLProgramEffects' internal use
+     */
+    void emitAttributes(const GrEffectStage& stage);
+
+    /**
+     * Are explicit local coordinates provided as input to the vertex shader.
+     */
+    bool hasExplicitLocalCoords() const { return (fLocalCoordsVar != fPositionVar); }
+
+    const SkString* getEffectAttributeName(int attributeIndex) const;
+
+    /** Returns a vertex attribute that represents the local coords in the VS. This may be the same
+        as positionAttribute() or it may not be. It depends upon whether the rendering code
+        specified explicit local coords or not in the GrDrawState. */
+    const GrGLShaderVar& localCoordsAttribute() const { return *fLocalCoordsVar; }
+
+    /** Returns a vertex attribute that represents the vertex position in the VS. This is the
+        pre-matrix position and is commonly used by effects to compute texture coords via a matrix.
+      */
+    const GrGLShaderVar& positionAttribute() const { return *fPositionVar; }
+
+private:
+    /*
+     * Internal call for GrGLFullProgramBuilder.addVarying
+     */
+    void addVarying(GrSLType type,
+                   const char* name,
+                   const char** vsOutName);
+
+    /*
+     * private helpers for compilation by GrGLProgramBuilder
+     */
+    void bindProgramLocations(GrGLuint programId);
+    bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
+    void emitCodeBeforeEffects(GrGLSLExpr4* color, GrGLSLExpr4* coverage);
+    void emitCodeAfterEffects();
+
+    struct AttributePair {
+        void set(int index, const SkString& name) {
+            fIndex = index; fName = name;
+        }
+        int      fIndex;
+        SkString fName;
+    };
+
+    SkSTArray<10, AttributePair, true>  fEffectAttributes;
+    GrGLShaderVar*                      fPositionVar;
+    GrGLShaderVar*                      fLocalCoordsVar;
+
+    friend class GrGLFullProgramBuilder;
+
+    typedef GrGLFullShaderBuilder INHERITED;
+};
+
+#endif
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 5763211..3ab17d4 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -102,13 +102,13 @@
     header->fCoverageEffectCnt = numCoverageStages;
 
     if (dstRead) {
-        header->fDstReadKey = SkToU8(GrGLShaderBuilder::KeyForDstRead(dstCopyTexture,
+        header->fDstReadKey = SkToU8(GrGLFragmentShaderBuilder::KeyForDstRead(dstCopyTexture,
                                                                       gpu->glCaps()));
     } else {
         header->fDstReadKey = 0;
     }
     if (fragPos) {
-        header->fFragPosKey = SkToU8(GrGLShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
+        header->fFragPosKey = SkToU8(GrGLFragmentShaderBuilder::KeyForFragmentPosition(dstRenderTarget,
                                                                                gpu->glCaps()));
     } else {
         header->fFragPosKey = 0;