Revert 2289. GLSL version detection not robust enough. May think we don't have GLSL 1.50 support based on OpenGL version. We have to look at the available extensions, not just GL version.




git-svn-id: http://skia.googlecode.com/svn/trunk@2290 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index 07a2e04..0efb99f 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -9,8 +9,8 @@
 
 #include "GrGLProgram.h"
 
-#include "GrAllocator.h"
-#include "GrGLShaderVar.h"
+#include "GrGLConfig.h"
+
 #include "SkTrace.h"
 #include "SkXfermode.h"
 
@@ -36,32 +36,6 @@
 
 #define PRINT_SHADERS 0
 
-typedef GrTAllocator<GrGLShaderVar> VarArray;
-
-// number of each input/output type in a single allocation block
-static const int gVarsPerBlock = 8;
-// except FS outputs where we expect 2 at most.
-static const int gMaxFSOutputs = 2;
-
-struct ShaderCodeSegments {
-    ShaderCodeSegments() 
-    : fVSUnis(gVarsPerBlock)
-    , fVSAttrs(gVarsPerBlock)
-    , fVaryings(gVarsPerBlock)
-    , fFSUnis(gVarsPerBlock)
-    , fFSOutputs(gMaxFSOutputs) {}
-    GrStringBuilder fHeader; // VS+FS, GLSL version, etc
-    VarArray        fVSUnis;
-    VarArray        fVSAttrs;
-    VarArray        fVaryings;
-    VarArray        fFSUnis;
-    VarArray        fFSOutputs;
-    GrStringBuilder fFSFunctions;
-    GrStringBuilder fVSCode;
-    GrStringBuilder fFSCode;
-};
-
-
 #if GR_GL_ATTRIBUTE_MATRICES
     #define VIEW_MATRIX_NAME "aViewM"
 #else
@@ -75,61 +49,53 @@
 #define EDGES_UNI_NAME "uEdges"
 #define COL_FILTER_UNI_NAME "uColorFilter"
 
-namespace {
-inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
+static inline void tex_attr_name(int coordIdx, GrStringBuilder* s) {
     *s = "aTexCoord";
     s->appendS32(coordIdx);
 }
 
-inline GrGLShaderVar::Type float_vector_type(int count) {
-    GR_STATIC_ASSERT(GrGLShaderVar::kFloat_Type == 0);
-    GR_STATIC_ASSERT(GrGLShaderVar::kVec2f_Type == 1);
-    GR_STATIC_ASSERT(GrGLShaderVar::kVec3f_Type == 2);
-    GR_STATIC_ASSERT(GrGLShaderVar::kVec4f_Type == 3);
-    GrAssert(count > 0 && count <= 4);
-    return (GrGLShaderVar::Type)(count - 1);
+static inline const char* float_vector_type(int count) {
+    static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
+    GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(FLOAT_VECS));
+    return FLOAT_VECS[count];
 }
 
-inline const char* float_vector_type_str(int count) {
-    return GrGLShaderVar::TypeString(float_vector_type(count));
-}
-
-inline const char* vector_homog_coord(int count) {
+static inline const char* vector_homog_coord(int count) {
     static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS));
     return HOMOGS[count];
 }
 
-inline const char* vector_nonhomog_coords(int count) {
+static inline const char* vector_nonhomog_coords(int count) {
     static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
     return NONHOMOGS[count];
 }
 
-inline const char* vector_all_coords(int count) {
+static inline const char* vector_all_coords(int count) {
     static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ALL));
     return ALL[count];
 }
 
-inline const char* all_ones_vec(int count) {
+static inline const char* all_ones_vec(int count) {
     static const char* ONESVEC[] = {"ERROR", "1.0", "vec2(1,1)",
                                     "vec3(1,1,1)", "vec4(1,1,1,1)"};
     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ONESVEC));
     return ONESVEC[count];
 }
 
-inline const char* all_zeros_vec(int count) {
+static inline const char* all_zeros_vec(int count) {
     static const char* ZEROSVEC[] = {"ERROR", "0.0", "vec2(0,0)",
                                     "vec3(0,0,0)", "vec4(0,0,0,0)"};
     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(ZEROSVEC));
     return ZEROSVEC[count];
 }
 
-inline const char* declared_color_output_name() { return "fsColorOut"; }
-inline const char* dual_source_output_name() { return "dualSourceOut"; }
+static inline const char* declared_color_output_name() { return "fsColorOut"; }
+static inline const char* dual_source_output_name() { return "dualSourceOut"; }
 
-inline void tex_matrix_name(int stage, GrStringBuilder* s) {
+static void tex_matrix_name(int stage, GrStringBuilder* s) {
 #if GR_GL_ATTRIBUTE_MATRICES
     *s = "aTexM";
 #else
@@ -138,43 +104,42 @@
     s->appendS32(stage);
 }
 
-inline void normalized_texel_size_name(int stage, GrStringBuilder* s) {
+static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
     *s = "uTexelSize";
     s->appendS32(stage);
 }
 
-inline void sampler_name(int stage, GrStringBuilder* s) {
+static void sampler_name(int stage, GrStringBuilder* s) {
     *s = "uSampler";
     s->appendS32(stage);
 }
 
-inline void stage_varying_name(int stage, GrStringBuilder* s) {
+static void stage_varying_name(int stage, GrStringBuilder* s) {
     *s = "vStage";
     s->appendS32(stage);
 }
 
-inline void radial2_param_name(int stage, GrStringBuilder* s) {
+static void radial2_param_name(int stage, GrStringBuilder* s) {
     *s = "uRadial2Params";
     s->appendS32(stage);
 }
 
-inline void radial2_varying_name(int stage, GrStringBuilder* s) {
+static void radial2_varying_name(int stage, GrStringBuilder* s) {
     *s = "vB";
     s->appendS32(stage);
 }
 
-inline void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i) {
+static void convolve_param_names(int stage, GrStringBuilder* k, GrStringBuilder* i) {
     *k = "uKernel";
     k->appendS32(stage);
     *i = "uImageIncrement";
     i->appendS32(stage);
 }
 
-inline void tex_domain_name(int stage, GrStringBuilder* s) {
+static void tex_domain_name(int stage, GrStringBuilder* s) {
     *s = "uTexDom";
     s->appendS32(stage);
 }
-}
 
 GrGLProgram::GrGLProgram() {
 }
@@ -356,39 +321,15 @@
     add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
 }
 
-namespace {
-
-const char* glsl_version_string(const GrGLInterface* gl,
-                                GrGLProgram::GLSLVersion v) {
-    switch (v) {
-        case GrGLProgram::k120_GLSLVersion:
-            if (gl->supportsES()) {
-                // ES2s shader language is based on version 1.20 but is version
-                // 1.00 of the ES language.
-                return "#version 100\n";
-            } else {
-                return "#version 120\n";
-            }
-        case GrGLProgram::k150_GLSLVersion:
-            GrAssert(!gl->supportsES());
-            return "#version 150\n";
-        default:
-            GrCrash("Unknown GL version.");
-            return ""; // suppress warning
-    }
-}
-
-}
-
 void GrGLProgram::genEdgeCoverage(const GrGLInterface* gl,
                                   GrVertexLayout layout,
                                   CachedData* programData,
                                   GrStringBuilder* coverageVar,
                                   ShaderCodeSegments* segments) const {
     if (fProgramDesc.fEdgeAANumEdges > 0) {
-        segments->fFSUnis.push_back().set(GrGLShaderVar::kVec3f_Type,
-                                          EDGES_UNI_NAME,
-                                          fProgramDesc.fEdgeAANumEdges);
+        segments->fFSUnis.append("uniform vec3 " EDGES_UNI_NAME "[");
+        segments->fFSUnis.appendS32(fProgramDesc.fEdgeAANumEdges);
+        segments->fFSUnis.append("];\n");
         programData->fUniLocations.fEdgesUni = kUseUniform;
         int count = fProgramDesc.fEdgeAANumEdges;
         segments->fFSCode.append(
@@ -435,8 +376,8 @@
         }
         *coverageVar = "edgeAlpha";
     } else  if (layout & GrDrawTarget::kEdge_VertexLayoutBit) {
-        segments->fVaryings.push_back().set(GrGLShaderVar::kVec4f_Type, "vEdge");
-        segments->fVSAttrs.push_back().set(GrGLShaderVar::kVec4f_Type, EDGE_ATTR_NAME);
+        segments->fVSAttrs.append("attribute vec4 " EDGE_ATTR_NAME ";\n");
+        segments->fVaryings.append("varying vec4 vEdge;\n");
         segments->fVSCode.append("\tvEdge = " EDGE_ATTR_NAME ";\n");
         if (GrDrawTarget::kHairLine_EdgeType == fProgramDesc.fVertexEdgeType) {
             segments->fFSCode.append("\tfloat edgeAlpha = abs(dot(vec3(gl_FragCoord.xy,1), vEdge.xyz));\n");
@@ -461,33 +402,7 @@
     }
 }
 
-namespace {
-
-// returns true if the color output was explicitly declared or not.
-bool decl_and_get_fs_color_output(GrGLProgram::GLSLVersion v,
-                                  VarArray* fsOutputs,
-                                  const char** name) {
-    switch (v) {
-        case GrGLProgram::k120_GLSLVersion:
-            *name = "gl_FragColor";
-            return false;
-            break;
-        case GrGLProgram::k150_GLSLVersion:
-            *name = declared_color_output_name();
-            fsOutputs->push_back().set(GrGLShaderVar::kVec4f_Type,
-                                       declared_color_output_name());
-            return true;
-            break;
-        default:
-            GrCrash("Unknown GLSL version.");
-            return false; // suppress warning
-    }
-}
-
-}
-
-bool GrGLProgram::genProgram(const GrGLInterface* gl,
-                             GLSLVersion glslVersion,
+bool GrGLProgram::genProgram(const GrGLInterface* gl, 
                              GrGLProgram::CachedData* programData) const {
 
     ShaderCodeSegments segments;
@@ -517,19 +432,25 @@
     // declare an output, which is incompatible with gl_FragColor/gl_FragData.
     const char* fsColorOutput;
     bool dualSourceOutputWritten = false;
-    segments.fHeader.printf(glsl_version_string(gl, glslVersion));
-    bool isColorDeclared = decl_and_get_fs_color_output(glslVersion,
-                                                        &segments.fFSOutputs,
-                                                        &fsColorOutput);
+    bool usingDeclaredOutputs = ProgramDesc::kNone_DualSrcOutput !=
+                                fProgramDesc.fDualSrcOutput;
+    if (usingDeclaredOutputs) {
+        GrAssert(0 == segments.fHeader.size());
+        segments.fHeader.printf("#version 150\n");
+        fsColorOutput = declared_color_output_name();
+        segments.fFSOutputs.appendf("out vec4 %s;\n", fsColorOutput);
+    } else {
+        fsColorOutput = "gl_FragColor";
+    }
 
 #if GR_GL_ATTRIBUTE_MATRICES
-    segments.fVSAttrs.push_back().set(GrGLShaderVar::kMat33f_Type, VIEW_MATRIX_NAME);
+    segments.fVSAttrs += "attribute mat3 " VIEW_MATRIX_NAME ";\n";
     programData->fUniLocations.fViewMatrixUni = kSetAsAttribute;
 #else
-    segments.fVSUnis.push_back().set(GrGLShaderVar::kMat33f_Type, VIEW_MATRIX_NAME);
+    segments.fVSUnis  += "uniform mat3 " VIEW_MATRIX_NAME ";\n";
     programData->fUniLocations.fViewMatrixUni = kUseUniform;
 #endif
-    segments.fVSAttrs.push_back().set(GrGLShaderVar::kVec2f_Type, POS_ATTR_NAME);
+    segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
 
     segments.fVSCode.append(
         "void main() {\n"
@@ -542,16 +463,13 @@
     if (needComputedColor) {
         switch (fProgramDesc.fColorType) {
             case ProgramDesc::kAttribute_ColorType:
-                segments.fVSAttrs.push_back().set(GrGLShaderVar::kVec4f_Type,
-                                                  COL_ATTR_NAME);
-                segments.fVaryings.push_back().set(GrGLShaderVar::kVec4f_Type,
-                                                   "vColor");
-                segments.fVSCode.append("\tvColor = " COL_ATTR_NAME ";\n");
+                segments.fVSAttrs.append( "attribute vec4 " COL_ATTR_NAME ";\n");
+                segments.fVaryings.append("varying vec4 vColor;\n");
+                segments.fVSCode.append(    "\tvColor = " COL_ATTR_NAME ";\n");
                 inColor = "vColor";
                 break;
             case ProgramDesc::kUniform_ColorType:
-                segments.fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
-                                                 COL_UNI_NAME);
+                segments.fFSUnis.append(  "uniform vec4 " COL_UNI_NAME ";\n");
                 programData->fUniLocations.fColorUni = kUseUniform;
                 inColor = COL_UNI_NAME;
                 break;
@@ -572,8 +490,7 @@
     for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
         if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
             tex_attr_name(t, texCoordAttrs + t);
-            segments.fVSAttrs.push_back().set(GrGLShaderVar::kVec2f_Type,
-                                              texCoordAttrs[t].c_str());
+            segments.fVSAttrs.appendf("attribute vec2 %s;\n", texCoordAttrs[t].c_str());
         }
     }
 
@@ -604,8 +521,7 @@
                     inCoords = texCoordAttrs[tcIdx].c_str();
                 }
 
-                genStageCode(gl,
-                             s,
+                genStageCode(gl, s,
                              fProgramDesc.fStages[s],
                              inColor.size() ? inColor.c_str() : NULL,
                              outColor.c_str(),
@@ -628,8 +544,7 @@
                           &needColorFilterUniform, &bogus);
     }
     if (needColorFilterUniform) {
-        segments.fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type,
-                                         COL_FILTER_UNI_NAME);
+        segments.fFSUnis.append(  "uniform vec4 " COL_FILTER_UNI_NAME ";\n");
         programData->fUniLocations.fColorFilterUni = kUseUniform;
     }
 
@@ -693,8 +608,8 @@
             }
         }
         if (ProgramDesc::kNone_DualSrcOutput != fProgramDesc.fDualSrcOutput) {
-            segments.fFSOutputs.push_back().set(GrGLShaderVar::kVec4f_Type,
-                                                dual_source_output_name());
+            segments.fFSOutputs.appendf("out vec4 %s;\n",
+                                        dual_source_output_name());
             bool outputIsZero = false;
             GrStringBuilder coeff;
             if (ProgramDesc::kCoverage_DualSrcOutput !=
@@ -729,9 +644,9 @@
 
     if (!wroteFragColorZero) {
         modulate_helper(fsColorOutput,
-                        inColor.c_str(),
-                        inCoverage.c_str(),
-                        &segments.fFSCode);
+                         inColor.c_str(),
+                         inCoverage.c_str(),
+                         &segments.fFSCode);
     }
 
     segments.fVSCode.append("}\n");
@@ -740,12 +655,12 @@
     ///////////////////////////////////////////////////////////////////////////
     // compile and setup attribs and unis
 
-    if (!CompileFSAndVS(gl, glslVersion, segments, programData)) {
+    if (!CompileFSAndVS(gl, segments, programData)) {
         return false;
     }
 
     if (!this->bindOutputsAttribsAndLinkProgram(gl, texCoordAttrs,
-                                                isColorDeclared,
+                                                usingDeclaredOutputs,
                                                 dualSourceOutputWritten,
                                                 programData)) {
         return false;
@@ -756,36 +671,7 @@
     return true;
 }
 
-namespace {
-
-void expand_decls(const VarArray& unis,
-                  const GrGLInterface* gl,
-                  const char* prefix,
-                  GrStringBuilder* string) {
-    const int count = unis.count();
-    for (int i = 0; i < count; ++i) {
-        string->append(prefix);
-        string->append(" ");
-        unis[i].appendDecl(gl, string);
-        string->append(";\n");
-    }
-}
-
-void print_shader(int stringCnt,
-                  const char** strings,
-                  int* stringLengths) {
-    for (int i = 0; i < stringCnt; ++i) {
-        if (NULL == stringLengths || stringLengths[i] < 0) {
-            GrPrintf(strings[i]);
-        } else {
-            GrPrintf("%.*s", stringLengths[i], strings[i]);
-        }
-    }
-}
-}
-
 bool GrGLProgram::CompileFSAndVS(const GrGLInterface* gl,
-                                 GLSLVersion glslVersion,
                                  const ShaderCodeSegments& segments,
                                  CachedData* programData) {
 
@@ -793,41 +679,25 @@
     const char* strings[MAX_STRINGS];
     int lengths[MAX_STRINGS];
     int stringCnt = 0;
-    GrStringBuilder attrs;
-    GrStringBuilder varyings;
-    GrStringBuilder unis;
-    GrStringBuilder fsOutputs;
-
-    static const char* gVaryingPrefixes[2][2] = {{"varying", "varying"},
-                                                 {"out", "in"}};
-    const char** varyingPrefixes = glslVersion == k120_GLSLVersion ?
-                                                    gVaryingPrefixes[0] :
-                                                    gVaryingPrefixes[1];
-    const char* attributePrefix = glslVersion == k120_GLSLVersion ?
-                                                    "attribute" :
-                                                    "in";
 
     if (segments.fHeader.size()) {
         strings[stringCnt] = segments.fHeader.c_str();
         lengths[stringCnt] = segments.fHeader.size();
         ++stringCnt;
     }
-    expand_decls(segments.fVSUnis, gl, "uniform", &unis);
-    if (unis.size()) {
-        strings[stringCnt] = unis.c_str();
-        lengths[stringCnt] = unis.size();
+    if (segments.fVSUnis.size()) {
+        strings[stringCnt] = segments.fVSUnis.c_str();
+        lengths[stringCnt] = segments.fVSUnis.size();
         ++stringCnt;
     }
-    expand_decls(segments.fVSAttrs, gl, attributePrefix, &attrs);
-    if (attrs.size()) {
-        strings[stringCnt] = attrs.c_str();
-        lengths[stringCnt] = attrs.size();
+    if (segments.fVSAttrs.size()) {
+        strings[stringCnt] = segments.fVSAttrs.c_str();
+        lengths[stringCnt] = segments.fVSAttrs.size();
         ++stringCnt;
     }
-    expand_decls(segments.fVaryings, gl, varyingPrefixes[0], &varyings);
-    if (varyings.size()) {
-        strings[stringCnt] = varyings.c_str();
-        lengths[stringCnt] = varyings.size();
+    if (segments.fVaryings.size()) {
+        strings[stringCnt] = segments.fVaryings.c_str();
+        lengths[stringCnt] = segments.fVaryings.size();
         ++stringCnt;
     }
 
@@ -837,10 +707,13 @@
     ++stringCnt;
 
 #if PRINT_SHADERS
-    print_shader(stringCnt, strings, lengths);
+    GrPrintf(segments.fHeader.c_str());
+    GrPrintf(segments.fVSUnis.c_str());
+    GrPrintf(segments.fVSAttrs.c_str());
+    GrPrintf(segments.fVaryings.c_str());
+    GrPrintf(segments.fVSCode.c_str());
     GrPrintf("\n");
 #endif
-
     GrAssert(stringCnt <= MAX_STRINGS);
     programData->fVShaderID = CompileShader(gl, GR_GL_VERTEX_SHADER,
                                             stringCnt, strings, lengths);
@@ -861,26 +734,19 @@
         lengths[stringCnt] = strlen(GrShaderPrecision(gl));
         ++stringCnt;
     }
-    unis.reset();
-    expand_decls(segments.fFSUnis, gl, "uniform", &unis);
-    if (unis.size()) {
-        strings[stringCnt] = unis.c_str();
-        lengths[stringCnt] = unis.size();
+    if (segments.fFSUnis.size()) {
+        strings[stringCnt] = segments.fFSUnis.c_str();
+        lengths[stringCnt] = segments.fFSUnis.size();
         ++stringCnt;
     }
-    varyings.reset();
-    expand_decls(segments.fVaryings, gl, varyingPrefixes[1], &varyings);
-    if (varyings.size()) {
-        strings[stringCnt] = varyings.c_str();
-        lengths[stringCnt] = varyings.size();
+    if (segments.fVaryings.size()) {
+        strings[stringCnt] = segments.fVaryings.c_str();
+        lengths[stringCnt] = segments.fVaryings.size();
         ++stringCnt;
     }
-    expand_decls(segments.fFSOutputs, gl, "out", &fsOutputs);
-    if (fsOutputs.size()) {
-        // We shouldn't have declared outputs on 1.2
-        GrAssert(k120_GLSLVersion != glslVersion);
-        strings[stringCnt] = fsOutputs.c_str();
-        lengths[stringCnt] = fsOutputs.size();
+    if (segments.fFSOutputs.size()) {
+        strings[stringCnt] = segments.fFSOutputs.c_str();
+        lengths[stringCnt] = segments.fFSOutputs.size();
         ++stringCnt;
     }
     if (segments.fFSFunctions.size()) {
@@ -895,10 +761,15 @@
     ++stringCnt;
 
 #if PRINT_SHADERS
-    print_shader(stringCnt, strings, lengths);
+    GrPrintf(segments.fHeader.c_str());
+    GrPrintf(GrShaderPrecision(gl));
+    GrPrintf(segments.fFSUnis.c_str());
+    GrPrintf(segments.fVaryings.c_str());
+    GrPrintf(segments.fFSOutputs.c_str());
+    GrPrintf(segments.fFSFunctions.c_str());
+    GrPrintf(segments.fFSCode.c_str());
     GrPrintf("\n");
 #endif
-
     GrAssert(stringCnt <= MAX_STRINGS);
     programData->fFShaderID = CompileShader(gl, GR_GL_FRAGMENT_SHADER,
                                             stringCnt, strings, lengths);
@@ -939,7 +810,13 @@
             GrGLsizei length = GR_GL_INIT_ZERO;
             GR_GL_CALL(gl, GetShaderInfoLog(shader, infoLen+1, 
                                             &length, (char*)log.get()));
-            print_shader(stringCnt, strings, stringLengths);
+            for (int i = 0; i < stringCnt; ++i) {
+                if (NULL == stringLengths || stringLengths[i] < 0) {
+                    GrPrintf(strings[i]);
+                } else {
+                    GrPrintf("%.*s", stringLengths[i], strings[i]);
+                }
+            }
             GrPrintf("\n%s", log.get());
         }
         GrAssert(!"Shader compilation failed!");
@@ -1150,6 +1027,9 @@
 
     GrAssert(stageNum >= 0 && stageNum <= 9);
 
+    GrStringBuilder varyingName;
+    stage_varying_name(stageNum, &varyingName);
+
     // First decide how many coords are needed to access the texture
     // Right now it's always 2 but we could start using 1D textures for
     // gradients.
@@ -1159,22 +1039,18 @@
 
     // decide whether we need a matrix to transform texture coords
     // and whether the varying needs a perspective coord.
-    const char* matName = NULL;
+    GrStringBuilder texMName;
+    tex_matrix_name(stageNum, &texMName);
     if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
         varyingDims = coordDims;
     } else {
-        GrGLShaderVar* mat;
     #if GR_GL_ATTRIBUTE_MATRICES
-        mat = &segments->fVSAttrs.push_back();
+        segments->fVSAttrs.appendf("attribute mat3 %s;\n", texMName.c_str());
         locations->fTextureMatrixUni = kSetAsAttribute;
     #else
-        mat = &segments->fVSUnis.push_back();
+        segments->fVSUnis.appendf("uniform mat3 %s;\n", texMName.c_str());
         locations->fTextureMatrixUni = kUseUniform;
     #endif
-        tex_matrix_name(stageNum, mat->accessName());
-        mat->setType(GrGLShaderVar::kMat33f_Type);
-        matName = mat->getName().c_str();
-
         if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
             varyingDims = coordDims;
         } else {
@@ -1182,93 +1058,75 @@
         }
     }
 
-    segments->fFSUnis.push_back().setType(GrGLShaderVar::kSampler2D_Type);
-    sampler_name(stageNum, segments->fFSUnis.back().accessName());
+    GrStringBuilder samplerName;
+    sampler_name(stageNum, &samplerName);
+    segments->fFSUnis.appendf("uniform sampler2D %s;\n", samplerName.c_str());
     locations->fSamplerUni = kUseUniform;
-    const char* samplerName = segments->fFSUnis.back().getName().c_str();
 
-    const char* texelSizeName = NULL;
+    GrStringBuilder texelSizeName;
     if (StageDesc::k2x2_FetchMode == desc.fFetchMode) {
-        segments->fFSUnis.push_back().setType(GrGLShaderVar::kVec2f_Type);
-        normalized_texel_size_name(stageNum, segments->fFSUnis.back().accessName());
-        texelSizeName = segments->fFSUnis.back().getName().c_str();
+        normalized_texel_size_name(stageNum, &texelSizeName);
+        segments->fFSUnis.appendf("uniform vec2 %s;\n", texelSizeName.c_str());
     }
 
-    const char* varyingName;
-    GrGLShaderVar* varying = &segments->fVaryings.push_back();
-    stage_varying_name(stageNum, varying->accessName());
-    varying->setType(float_vector_type(varyingDims));
-    varyingName = varying->getName().c_str();
+    segments->fVaryings.appendf("varying %s %s;\n",
+                                float_vector_type(varyingDims), varyingName.c_str());
 
-    if (!matName) {
+    if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
         GrAssert(varyingDims == coordDims);
-        segments->fVSCode.appendf("\t%s = %s;\n", varyingName, vsInCoord);
+        segments->fVSCode.appendf("\t%s = %s;\n", varyingName.c_str(), vsInCoord);
     } else {
         // varying = texMatrix * texCoord
         segments->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
-                                  varyingName, matName, vsInCoord,
-                                  vector_all_coords(varyingDims));
+                                  varyingName.c_str(), texMName.c_str(),
+                                  vsInCoord, vector_all_coords(varyingDims));
     }
 
-    const char* radial2ParamsName = NULL;
-    const char* radial2VaryingName = NULL;
+    GrStringBuilder radial2ParamsName;
+    radial2_param_name(stageNum, &radial2ParamsName);
+    // for radial grads without perspective we can pass the linear
+    // part of the quadratic as a varying.
+    GrStringBuilder radial2VaryingName;
+    radial2_varying_name(stageNum, &radial2VaryingName);
 
-    if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping ||
+    if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping || 
         StageDesc::kRadial2GradientDegenerate_CoordMapping == desc.fCoordMapping) {
 
-        GrGLShaderVar* radial2FSParams = &segments->fFSUnis.push_back();
-        radial2FSParams->setType(GrGLShaderVar::kFloat_Type);
-        radial2FSParams->setArrayCount(6);
-        radial2_param_name(stageNum, radial2FSParams->accessName());
-        segments->fVSUnis.push_back(*radial2FSParams).setEmitPrecision(true);
-        radial2ParamsName = radial2FSParams->getName().c_str();
-
+        segments->fVSUnis.appendf("uniform %s float %s[6];\n",
+                                  GrPrecision(gl), radial2ParamsName.c_str());
+        segments->fFSUnis.appendf("uniform float %s[6];\n",
+                                  radial2ParamsName.c_str());
         locations->fRadial2Uni = kUseUniform;
 
-        // for radial grads without perspective we can pass the linear
-        // part of the quadratic as a varying.
+        // if there is perspective we don't interpolate this
         if (varyingDims == coordDims) {
             GrAssert(2 == coordDims);
-
-            GrGLShaderVar* radial2Varying = &segments->fVaryings.push_back();
-            radial2Varying->setType(GrGLShaderVar::kFloat_Type);
-            radial2_varying_name(stageNum, radial2Varying->accessName());
-            radial2VaryingName = radial2Varying->getName().c_str();
+            segments->fVaryings.appendf("varying float %s;\n", radial2VaryingName.c_str());
 
             // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
-            const char* r2ParamName = radial2FSParams->getName().c_str();
-            const char* r2VarName = radial2Varying->getName().c_str();
             segments->fVSCode.appendf("\t%s = 2.0 *(%s[2] * %s.x - %s[3]);\n",
-                                      r2VarName, r2ParamName, varyingName,
-                                      r2ParamName);
+                                      radial2VaryingName.c_str(), radial2ParamsName.c_str(),
+                                      varyingName.c_str(), radial2ParamsName.c_str());
         }
     }
 
-    const char* kernelName = NULL;
-    const char* imageIncrementName = NULL;
+    GrStringBuilder kernelName, kernelWidthName, imageIncrementName;
+    convolve_param_names(stageNum, &kernelName, &imageIncrementName);
+
     if (ProgramDesc::StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
-
-        GrGLShaderVar* kernel = &segments->fFSUnis.push_back();
-        kernel->setType(GrGLShaderVar::kFloat_Type);
-        kernel->setArrayCount(desc.fKernelWidth);
-        GrGLShaderVar* imgInc = &segments->fFSUnis.push_back();
-        imgInc->setType(GrGLShaderVar::kVec2f_Type);
-
-        convolve_param_names(stageNum,
-                             kernel->accessName(),
-                             imgInc->accessName());
-        kernelName = kernel->getName().c_str();
-        imageIncrementName = imgInc->getName().c_str();
-
-        // need image increment in both VS and FS
-        segments->fVSUnis.push_back(*imgInc).setEmitPrecision(true);
-
+        segments->fFSUnis.appendf("uniform float %s[%d];\n",
+                                  kernelName.c_str(), desc.fKernelWidth);
+        segments->fFSUnis.appendf("uniform vec2 %s;\n",
+                                  imageIncrementName.c_str());
+        segments->fVSUnis.appendf("uniform %s vec2 %s;\n",
+                                  GrPrecision(gl),
+                                  imageIncrementName.c_str());
         locations->fKernelUni = kUseUniform;
         locations->fImageIncrementUni = kUseUniform;
         float scale = (desc.fKernelWidth - 1) * 0.5f;
         segments->fVSCode.appendf("\t%s -= vec2(%g, %g) * %s;\n",
-                                  varyingName, scale, scale,
-                                  imageIncrementName);
+                                  varyingName.c_str(), scale, scale,
+                                  imageIncrementName.c_str());
     }
 
     /// Fragment Shader Stuff
@@ -1291,12 +1149,12 @@
             fsCoordName = "inCoord";
             fsCoordName.appendS32(stageNum);
             segments->fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
-                                GrGLShaderVar::TypeString(float_vector_type(coordDims)),
-                                fsCoordName.c_str(),
-                                varyingName,
-                                vector_nonhomog_coords(varyingDims),
-                                varyingName,
-                                vector_homog_coord(varyingDims));
+                                       float_vector_type(coordDims),
+                                       fsCoordName.c_str(),
+                                       varyingName.c_str(),
+                                       vector_nonhomog_coords(varyingDims),
+                                       varyingName.c_str(),
+                                       vector_homog_coord(varyingDims));
         }
     }
 
@@ -1334,18 +1192,18 @@
             bVar = "b";
             bVar.appendS32(stageNum);
             segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
-                                        bVar.c_str(), radial2ParamsName,
-                                        fsCoordName.c_str(), radial2ParamsName);
+                                        bVar.c_str(), radial2ParamsName.c_str(),
+                                        fsCoordName.c_str(), radial2ParamsName.c_str());
         }
 
         // c = (x^2)+(y^2) - params[4]
         segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
                                   cName.c_str(), fsCoordName.c_str(),
                                   fsCoordName.c_str(),
-                                  radial2ParamsName);
+                                  radial2ParamsName.c_str());
         // ac4 = 4.0 * params[0] * c
         segments->fFSCode.appendf("\tfloat %s = %s[0] * 4.0 * %s;\n",
-                                  ac4Name.c_str(), radial2ParamsName,
+                                  ac4Name.c_str(), radial2ParamsName.c_str(),
                                   cName.c_str());
 
         // root = sqrt(b^2-4ac)
@@ -1357,8 +1215,8 @@
         // x coord is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
         // y coord is 0.5 (texture is effectively 1D)
         sampleCoords.printf("vec2((-%s + %s[5] * %s) * %s[1], 0.5)",
-                            bVar.c_str(), radial2ParamsName,
-                            rootName.c_str(), radial2ParamsName);
+                            bVar.c_str(), radial2ParamsName.c_str(),
+                            rootName.c_str(), radial2ParamsName.c_str());
         complexCoord = true;
         break;}
     case StageDesc::kRadial2GradientDegenerate_CoordMapping: {
@@ -1377,15 +1235,15 @@
             bVar = "b";
             bVar.appendS32(stageNum);
             segments->fFSCode.appendf("\tfloat %s = 2.0 * (%s[2] * %s.x - %s[3]);\n",
-                                        bVar.c_str(), radial2ParamsName,
-                                        fsCoordName.c_str(), radial2ParamsName);
+                                        bVar.c_str(), radial2ParamsName.c_str(),
+                                        fsCoordName.c_str(), radial2ParamsName.c_str());
         }
 
         // c = (x^2)+(y^2) - params[4]
         segments->fFSCode.appendf("\tfloat %s = dot(%s, %s) - %s[4];\n",
                                   cName.c_str(), fsCoordName.c_str(),
                                   fsCoordName.c_str(),
-                                  radial2ParamsName);
+                                  radial2ParamsName.c_str());
 
         // x coord is: -c/b
         // y coord is 0.5 (texture is effectively 1D)
@@ -1409,10 +1267,12 @@
         StageDesc::kCustomTextureDomain_OptFlagBit) {
         GrStringBuilder texDomainName;
         tex_domain_name(stageNum, &texDomainName);
-        segments->fFSUnis.push_back().set(GrGLShaderVar::kVec4f_Type, texDomainName);
+        segments->fFSUnis.appendf("uniform %s %s;\n",
+                                  float_vector_type(4),
+                                  texDomainName.c_str());
         GrStringBuilder coordVar("clampCoord");
         segments->fFSCode.appendf("\t%s %s = clamp(%s, %s.xy, %s.zw);\n",
-                                  float_vector_type_str(coordDims),
+                                  float_vector_type(coordDims),
                                   coordVar.c_str(),
                                   sampleCoords.c_str(),
                                   texDomainName.c_str(),
@@ -1428,17 +1288,17 @@
             GrStringBuilder coordVar("tCoord");
             coordVar.appendS32(stageNum);
             segments->fFSCode.appendf("\t%s %s = %s;\n",
-                                float_vector_type_str(coordDims),
-                                coordVar.c_str(), sampleCoords.c_str());
+                                      float_vector_type(coordDims),
+                                      coordVar.c_str(), sampleCoords.c_str());
             sampleCoords = coordVar;
         }
         GrAssert(2 == coordDims);
         GrStringBuilder accumVar("accum");
         accumVar.appendS32(stageNum);
-        segments->fFSCode.appendf("\tvec4 %s  = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords.c_str(), texelSizeName, texelSizeName, smear);
-        segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords.c_str(), texelSizeName, texelSizeName, smear);
-        segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords.c_str(), texelSizeName, texelSizeName, smear);
-        segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, sampleCoords.c_str(), texelSizeName, texelSizeName, smear);
+        segments->fFSCode.appendf("\tvec4 %s  = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
+        segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
+        segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
+        segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName.c_str(), sampleCoords.c_str(), texelSizeName.c_str(), texelSizeName.c_str(), smear);
         segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
     } else if (ProgramDesc::StageDesc::kConvolution_FetchMode == desc.fFetchMode) {
         GrStringBuilder sumVar("sum");
@@ -1455,18 +1315,18 @@
                                   desc.fKernelWidth);
         segments->fFSCode.appendf("\t\t%s += %s(%s, %s)%s * %s[i];\n",
                                   sumVar.c_str(), texFunc.c_str(),
-                                  samplerName, coordVar.c_str(), smear,
-                                  kernelName);
+                                  samplerName.c_str(), coordVar.c_str(), smear,
+                                  kernelName.c_str());
         segments->fFSCode.appendf("\t\t%s += %s;\n",
                                   coordVar.c_str(),
-                                  imageIncrementName);
+                                  imageIncrementName.c_str());
         segments->fFSCode.appendf("\t}\n");
         segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor,
                                   sumVar.c_str(), modulate.c_str());
     } else {
         segments->fFSCode.appendf("\t%s = %s(%s, %s)%s%s;\n",
                                   fsOutColor, texFunc.c_str(), 
-                                  samplerName, sampleCoords.c_str(),
+                                  samplerName.c_str(), sampleCoords.c_str(),
                                   smear, modulate.c_str());
     }
 }
diff --git a/gpu/src/GrGLProgram.h b/gpu/src/GrGLProgram.h
index e37d0a2..90e515f 100644
--- a/gpu/src/GrGLProgram.h
+++ b/gpu/src/GrGLProgram.h
@@ -18,7 +18,17 @@
 
 class GrBinHashKeyBuilder;
 
-struct ShaderCodeSegments;
+struct ShaderCodeSegments {
+    GrStringBuilder fHeader; // VS+FS, GLSL version, etc
+    GrStringBuilder fVSUnis;
+    GrStringBuilder fVSAttrs;
+    GrStringBuilder fVaryings;
+    GrStringBuilder fFSUnis;
+    GrStringBuilder fFSOutputs;
+    GrStringBuilder fFSFunctions;
+    GrStringBuilder fVSCode;
+    GrStringBuilder fFSCode;
+};
 
 /**
  * This class manages a GPU program and records per-program information.
@@ -31,11 +41,6 @@
  */
 class GrGLProgram {
 public:
-    enum GLSLVersion {
-        k120_GLSLVersion, // Desktop GLSL 1.2 and ES2 shading lang
-        k150_GLSLVersion  // Desktop GLSL 1.5
-    };
-
     class CachedData;
 
     GrGLProgram();
@@ -47,7 +52,6 @@
      *  but in a separate cacheable container.
      */
     bool genProgram(const GrGLInterface* gl,
-                    GLSLVersion glslVersion,
                     CachedData* programData) const;
 
      /**
@@ -282,7 +286,7 @@
                       const char* vsInCoord,
                       ShaderCodeSegments* segments,
                       StageUniLocations* locations) const;
-
+    
     // generates code to compute coverage based on edge AA.
     void genEdgeCoverage(const GrGLInterface* gl,
                          GrVertexLayout layout,
@@ -291,7 +295,6 @@
                          ShaderCodeSegments* segments) const;
 
     static bool CompileFSAndVS(const GrGLInterface* gl,
-                               GLSLVersion glslVersion,
                                const ShaderCodeSegments& segments, 
                                CachedData* programData);
 
diff --git a/gpu/src/GrGLShaderVar.h b/gpu/src/GrGLShaderVar.h
deleted file mode 100644
index 5c50079..0000000
--- a/gpu/src/GrGLShaderVar.h
+++ /dev/null
@@ -1,217 +0,0 @@
-
-/*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrGLShaderVar_DEFINED
-#define GrGLShaderVar_DEFINED
-
-#include "GrGLInterface.h"
-
-/**
- * Represents a variable in a shader
- */
-class GrGLShaderVar {
-public:
-
-    enum Type {
-        kFloat_Type,
-        kVec2f_Type,
-        kVec3f_Type,
-        kVec4f_Type,
-        kMat33f_Type,
-        kSampler2D_Type,
-    };
-
-    /**
-     * Defaults to a float with no precision specifier
-     */
-    GrGLShaderVar() {
-        fType = kFloat_Type;
-        fCount = kNonArray;
-        fEmitPrecision = false;
-    }
-
-    GrGLShaderVar(const GrGLShaderVar& var)
-        : fType(var.fType)
-        , fName(var.fName)
-        , fCount(var.fCount)
-        , fEmitPrecision(var.fEmitPrecision) {}
-
-    /**
-     * Values for array count that have special meaning. We allow 1-sized arrays.
-     */
-    enum {
-        kNonArray     =  0, // not an array
-        kUnsizedArray = -1, // an unsized array (declared with [])
-    };
-
-    /**
-     * Sets as a non-array.
-     */
-    void set(Type type,
-             const GrStringBuilder& name,
-             bool emitPrecision = false) {
-        fType = type;
-        fName = name;
-        fCount = kNonArray;
-        fEmitPrecision = emitPrecision;
-    }
-
-    /**
-     * Sets as a non-array.
-     */
-    void set(Type type,
-             const char* name,
-             bool specifyPrecision = false) {
-        fType = type;
-        fName = name;
-        fCount = kNonArray;
-        fEmitPrecision = specifyPrecision;
-    }
-
-    /**
-     * Set all var options
-     */
-    void set(Type type,
-             const GrStringBuilder& name,
-             int count,
-             bool specifyPrecision = false) {
-        fType = type;
-        fName = name;
-        fCount = count;
-        fEmitPrecision = specifyPrecision;
-    }
-
-    /**
-     * Set all var options
-     */
-    void set(Type type,
-             const char* name,
-             int count,
-             bool specifyPrecision = false) {
-        fType = type;
-        fName = name;
-        fCount = count;
-        fEmitPrecision = specifyPrecision;
-    }
-
-    /**
-     * Is the var an array.
-     */
-    bool isArray() const { return kNonArray != fCount; }
-    /**
-     * Is this an unsized array, (i.e. declared with []).
-     */
-    bool isUnsizedArray() const { return kUnsizedArray == fCount; }
-    /**
-     * Get the array length of the var.
-     */
-    int getArrayCount() const { return fCount; }
-    /**
-     * Set the array length of the var
-     */
-    void setArrayCount(int count) { fCount = count; }
-    /**
-     * Set to be a non-array.
-     */
-    void setNonArray() { fCount = kNonArray; }
-    /**
-     * Set to be an unsized array.
-     */
-    void setUnsizedArray() { fCount = kUnsizedArray; }
-
-    /**
-     * Access the var name as a writable string
-     */
-    GrStringBuilder* accessName() { return &fName; }
-    /**
-     * Set the var name
-     */
-    void setName(const GrStringBuilder& n) { fName = n; }
-    void setName(const char* n) { fName = n; }
-    /**
-     * Get the var name.
-     */
-    const GrStringBuilder& getName() const { return fName; }
-
-    /**
-     * Get the type of the var
-     */
-    Type getType() const { return fType; }
-    /**
-     * Set the type of the var
-     */
-    void setType(Type type) { fType = type; }
-
-    /**
-     * Must the variable declaration emit a precision specifier
-     */
-    bool emitsPrecision() const { return fEmitPrecision; }
-    /**
-     * Specify whether the declaration should specify precision
-     */
-    void setEmitPrecision(bool p) { fEmitPrecision = p; }
-
-    /**
-     * Write a declaration of this variable to out.
-     */
-    void appendDecl(const GrGLInterface* gl, GrStringBuilder* out) const {
-        if (this->emitsPrecision()) {
-            out->append(PrecisionString(gl));
-            out->append(" ");
-        }
-        if (this->isArray()) {
-            if (this->isUnsizedArray()) {
-                out->appendf("%s %s[]", 
-                             TypeString(this->getType()), 
-                             this->getName().c_str());
-            } else {
-                GrAssert(this->getArrayCount() > 0);
-                out->appendf("%s %s[%d]", 
-                             TypeString(this->getType()),
-                             this->getName().c_str(),
-                             this->getArrayCount());
-            }
-        } else {
-            out->appendf("%s %s",
-                         TypeString(this->getType()),
-                         this->getName().c_str());
-        }
-    }
-
-    static const char* TypeString(Type t) {
-        switch (t) {
-            case kFloat_Type:
-                return "float";
-            case kVec2f_Type:
-                return "vec2";
-            case kVec3f_Type:
-                return "vec3";
-            case kVec4f_Type:
-                return "vec4";
-            case kMat33f_Type:
-                return "mat3";
-            case kSampler2D_Type:
-                return "sampler2D";
-            default:
-                GrCrash("Unknown shader var type.");
-                return ""; // suppress warning
-        }
-    }
-
-private:
-    static const char* PrecisionString(const GrGLInterface* gl) {
-        return gl->supportsDesktop() ? "" : "mediump";
-    }
-
-    Type            fType;
-    GrStringBuilder fName;
-    int             fCount;
-    bool            fEmitPrecision;
-};
-
-#endif
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index 67df419..b1accf6 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -26,7 +26,6 @@
 
     const GrGLInterface* glInterface() const { return fGL; }
     GrGLBinding glBinding() const { return fGLBinding; }
-    float glVersion() const { return fGLVersion; }
 
 protected:
     GrGpuGL(const GrGLInterface* glInterface, GrGLBinding glBinding);
@@ -47,6 +46,10 @@
     DrState   fHWDrawState;
     bool      fHWStencilClip;
 
+    // read these once at begining and then never again
+    SkString fExtensionString;
+    float fGLVersion;
+
     // As flush of GL state proceeds it updates fHDrawState
     // to reflect the new state. Later parts of the state flush
     // may perform cascaded changes but cannot refer to fHWDrawState.
@@ -190,16 +193,13 @@
     friend class GrGLTexture;
     friend class GrGLRenderTarget;
 
-    // read these once at begining and then never again
-    SkString fExtensionString;
-    float fGLVersion;
 
     SkTArray<GrGLStencilBuffer::Format, true> fStencilFormats;
     // we want to clear stencil buffers when they are created. We want to clear
     // the entire buffer even if it is larger than the color attachment. We
     // attach it to this fbo with no color attachment to do the initial clear.
     GrGLuint fStencilClearFBO;
-
+    
     bool fHWBlendDisabled;
 
     GrGLuint fAASamples[4];
diff --git a/gpu/src/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
index f894f1c..a9a3953 100644
--- a/gpu/src/GrGpuGLShaders.cpp
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -51,19 +51,15 @@
     enum {
         kMaxEntries = 32
     };
-    Entry                       fEntries[kMaxEntries];
-    int                         fCount;
-    unsigned int                fCurrLRUStamp;
-    const GrGLInterface*        fGL;
-    GrGLProgram::GLSLVersion    fGLSLVersion;
-
+    Entry                 fEntries[kMaxEntries];
+    int                   fCount;
+    unsigned int          fCurrLRUStamp;
+    const GrGLInterface*  fGL;
 public:
-    ProgramCache(const GrGLInterface* gl,
-                 GrGLProgram::GLSLVersion glslVersion) 
+    ProgramCache(const GrGLInterface* gl) 
         : fCount(0)
         , fCurrLRUStamp(0)
-        , fGL(gl)
-        , fGLSLVersion(glslVersion) {
+        , fGL(gl) {
     }
 
     ~ProgramCache() {
@@ -89,7 +85,7 @@
         
         Entry* entry = fHashCache.find(newEntry.fKey);
         if (NULL == entry) {
-            if (!desc.genProgram(fGL, fGLSLVersion, &newEntry.fProgramData)) {
+            if (!desc.genProgram(fGL, &newEntry.fProgramData)) {
                 return NULL;
             }
             if (fCount < kMaxEntries) {
@@ -140,32 +136,14 @@
 #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X)
 
 namespace {
-
-GrGLProgram::GLSLVersion get_glsl_version(GrGLBinding binding, float glVersion) {
-    switch (binding) {
-        case kDesktop_GrGLBinding:
-            return (glVersion >= 3.2) ? GrGLProgram::k150_GLSLVersion :
-                                        GrGLProgram::k120_GLSLVersion;
-        case kES2_GrGLBinding:
-            return GrGLProgram::k120_GLSLVersion;
-        default:
-            GrCrash("Attempting to get GLSL version in unknown or fixed-"
-                     "function GL binding.");
-            return GrGLProgram::k120_GLSLVersion; // suppress warning
+    template <typename T>
+    T random_val(GrRandom* r, T count) {
+        return (T)(int)(r->nextF() * count);
     }
-}
-
-template <typename T>
-T random_val(GrRandom* r, T count) {
-    return (T)(int)(r->nextF() * count);
-}
-
-}
+};
 
 bool GrGpuGLShaders::programUnitTest() {
 
-    GrGLProgram::GLSLVersion glslVersion = 
-            get_glsl_version(this->glBinding(), this->glVersion());
     static const int STAGE_OPTS[] = {
         0,
         StageDesc::kNoPerspective_OptFlagBit,
@@ -264,12 +242,15 @@
             stage.fKernelWidth = 4 * random.nextF() + 2;
         }
         CachedData cachedData;
-        if (!program.genProgram(this->glInterface(),
-                                glslVersion,
-                                &cachedData)) {
+        if (!program.genProgram(this->glInterface(), &cachedData)) {
             return false;
         }
         DeleteProgram(this->glInterface(), &cachedData);
+        bool again = false;
+        if (again) {
+            program.genProgram(this->glInterface(), &cachedData);
+            DeleteProgram(this->glInterface(), &cachedData);
+        }
     }
     return true;
 }
@@ -291,8 +272,7 @@
     fShaderSupport = true;
     if (kDesktop_GrGLBinding == this->glBinding()) {
         fDualSourceBlendingSupport =
-                            this->glVersion() >= 3.25f || // TODO: when resolving Issue 387 change 
-                                                          // this back to 3.3
+                            fGLVersion >= 3.3f ||
                             this->hasExtension("GL_ARB_blend_func_extended");
         fShaderDerivativeSupport = true;
     } else {
@@ -302,9 +282,7 @@
     }
 
     fProgramData = NULL;
-    GrGLProgram::GLSLVersion glslVersion =
-        get_glsl_version(this->glBinding(), this->glVersion());
-    fProgramCache = new ProgramCache(gl, glslVersion);
+    fProgramCache = new ProgramCache(gl);
 
 #if 0
     this->programUnitTest();