add gpu backend (not hooked up yet)



git-svn-id: http://skia.googlecode.com/svn/trunk@649 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGpuGLShaders2.cpp b/gpu/src/GrGpuGLShaders2.cpp
new file mode 100644
index 0000000..0a15be1
--- /dev/null
+++ b/gpu/src/GrGpuGLShaders2.cpp
@@ -0,0 +1,1388 @@
+/*
+    Copyright 2010 Google Inc.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+
+#include "GrGLConfig.h"
+
+#if GR_SUPPORT_GLES2 || GR_SUPPORT_GLDESKTOP
+
+#include "GrGpuGLShaders2.h"
+#include "GrGpuVertex.h"
+#include "GrMemory.h"
+#include "GrStringBuilder.h"
+
+
+#define ATTRIBUTE_MATRIX        0
+
+#define SKIP_COLOR_MODULATE_OPT 0
+
+#define PRINT_SHADERS           0
+
+#define SKIP_CACHE_CHECK    true
+
+#if GR_SUPPORT_GLES2
+    #define GR_PRECISION                "mediump"
+    const char GR_SHADER_PRECISION[] =  "precision mediump float;\n";
+#else
+    #define GR_PRECISION                ""
+    const char GR_SHADER_PRECISION[] =  "";
+#endif
+
+#define POS_ATTR_LOCATION 0
+#define TEX_ATTR_LOCATION 1
+#define COL_ATTR_LOCATION 2
+#if ATTRIBUTE_MATRIX
+#define VIEWMAT_ATTR_LOCATION 3
+#define TEXMAT_ATTR_LOCATION(X) (6 + 3 * (X))
+#define BOGUS_MATRIX_UNI_LOCATION 1000
+#endif
+
+const int GrGpuGLShaders2::NUM_STAGES = 1;
+
+struct GrGpuGLShaders2::StageUniLocations {
+    GLint fTextureMatrixUni;
+    GLint fSamplerUni;
+    GLint fRadial2Uni;
+};
+
+struct GrGpuGLShaders2::UniLocations {
+    GLint fViewMatrixUni;
+    StageUniLocations fStages[NUM_STAGES];
+};
+
+// Records per-program information
+// we can specify the attribute locations so that they are constant
+// across our shaders. But the driver determines the uniform locations
+// at link time. We don't need to remember the sampler uniform location
+// because we will bind a texture slot to it and never change it
+// Uniforms are program-local so we can't rely on fHWState to hold the
+// previous uniform state after a program change.
+struct  GrGpuGLShaders2::Program {
+    // IDs
+    GLuint    fVShaderID;
+    GLuint    fFShaderID;
+    GLuint    fProgramID;
+
+    // shader uniform locations (-1 if shader doesn't use them)
+    UniLocations fUniLocations;
+
+    // these reflect the current values of uniforms
+    // (GL uniform values travel with program)
+    GrMatrix                    fViewMatrix;
+    GrMatrix                    fTextureMatrix[NUM_STAGES];
+    GrGLTexture::Orientation    fTextureOrientation[NUM_STAGES];
+    GrScalar                    fRadial2CenterX1[NUM_STAGES];
+    GrScalar                    fRadial2Radius0[NUM_STAGES];
+    bool                        fRadial2PosRoot[NUM_STAGES];
+
+};
+
+// must be tightly packed
+struct GrGpuGLShaders2::StageDesc {
+    enum OptFlagBits {
+        kNoPerspective_OptFlagBit  = 0x1,
+        kIdentityMatrix_OptFlagBit = 0x2,
+    };
+    int fOptFlags : 8;
+    bool fEnabled;
+    enum Modulation {
+        kColor_Modulation,
+        kAlpha_Modulation,
+    } fModulation : 8;
+    enum CoordMapping {
+        kIdentity_CoordMapping,
+        kRadialGradient_CoordMapping,
+        kSweepGradient_CoordMapping,
+        kRadial2Gradient_CoordMapping,
+    } fCoordMapping : 8;
+};
+
+// must be tightly packed
+struct GrGpuGLShaders2::ProgramDesc {
+    GrVertexLayout fVertexLayout;
+    enum {
+        kNotPoints_OptFlagBit = 0x1,
+        kVertexColorAllOnes_OptFlagBit = 0x2,
+    };
+    // we're assuming optflags and layout pack into 32 bits
+    GR_STATIC_ASSERT(2 == sizeof(GrVertexLayout));
+    int fOptFlags : 16;
+
+    StageDesc fStages[NUM_STAGES];
+
+    bool operator == (const ProgramDesc& desc) const {
+        // keep 4-byte aligned and tightly packed
+        GR_STATIC_ASSERT(4 == sizeof(StageDesc));
+        GR_STATIC_ASSERT(2 + 2 + 4 * NUM_STAGES == sizeof(ProgramDesc));
+        return 0 == memcmp(this, &desc, sizeof(ProgramDesc));
+    }
+};
+
+#include "GrTHashCache.h"
+
+class GrGpuGLShaders2::ProgramCache : public ::GrNoncopyable {
+private:
+    struct Entry;
+    class HashKey {
+    public:
+        HashKey();
+        HashKey(const ProgramDesc& desc);
+        static const HashKey& GetKey(const Entry&);
+        static bool EQ(const Entry&, const HashKey&);
+        static bool LT(const Entry&, const HashKey&);
+        bool operator <(const HashKey& key) const;
+        bool operator ==(const HashKey& key) const;
+        uint32_t getHash() const;
+    private:
+        ProgramDesc fDesc;
+        uint32_t fHash;
+    };
+
+    struct Entry {
+        Program     fProgram;
+        HashKey     fKey;
+        uint32_t    fLRUStamp;
+    };
+
+    // if hash bits is changed, need to change hash function
+    GrTHashTable<Entry, HashKey, 8> fHashCache;
+
+    static const int MAX_ENTRIES = 16;
+    Entry        fEntries[MAX_ENTRIES];
+    int          fCount;
+    uint32_t     fCurrLRUStamp;
+
+public:
+    ProgramCache() {
+        fCount        = 0;
+        fCurrLRUStamp = 0;
+    }
+
+    ~ProgramCache() {
+        for (int i = 0; i < fCount; ++i) {
+            GrGpuGLShaders2::DeleteProgram(&fEntries[i].fProgram);
+        }
+    }
+
+    void abandon() {
+        fCount = 0;
+    }
+
+    void invalidateViewMatrices() {
+        for (int i = 0; i < fCount; ++i) {
+            // set to illegal matrix
+            fEntries[i].fProgram.fViewMatrix.setScale(GR_ScalarMax,
+                                                      GR_ScalarMax);
+        }
+    }
+
+    Program* getProgram(const ProgramDesc& desc) {
+        HashKey key(desc);
+        Entry* entry = fHashCache.find(key);
+        if (NULL == entry) {
+            if (fCount < MAX_ENTRIES) {
+                entry = fEntries + fCount;
+                ++fCount;
+            } else {
+                GrAssert(MAX_ENTRIES == fCount);
+                entry = fEntries;
+                for (int i = 1; i < MAX_ENTRIES; ++i) {
+                    if (fEntries[i].fLRUStamp < entry->fLRUStamp) {
+                        entry = fEntries + i;
+                    }
+                }
+                fHashCache.remove(entry->fKey, entry);
+                GrGpuGLShaders2::DeleteProgram(&entry->fProgram);
+            }
+            entry->fKey = key;
+            GrGpuGLShaders2::GenProgram(desc, &entry->fProgram);
+            fHashCache.insert(entry->fKey, entry);
+        }
+
+        entry->fLRUStamp = fCurrLRUStamp;
+        if (UINT32_MAX == fCurrLRUStamp) {
+            // wrap around! just trash our LRU, one time hit.
+            for (int i = 0; i < fCount; ++i) {
+                fEntries[i].fLRUStamp = 0;
+            }
+        }
+        ++fCurrLRUStamp;
+        return &entry->fProgram;
+    }
+};
+
+GrGpuGLShaders2::ProgramCache::HashKey::HashKey() {
+}
+
+static uint32_t ror(uint32_t x) {
+    return (x >> 8) | (x << 24);
+}
+
+
+GrGpuGLShaders2::ProgramCache::HashKey::HashKey(const ProgramDesc& desc) {
+    fDesc = desc;
+    // if you change the size of the desc, need to update the hash function
+    GR_STATIC_ASSERT(8 == sizeof(ProgramDesc));
+
+    uint32_t* d = (uint32_t*) &fDesc;
+    fHash = d[0] ^ ror(d[1]);
+}
+
+bool GrGpuGLShaders2::ProgramCache::HashKey::EQ(const Entry& entry,
+                                                const HashKey& key) {
+    return entry.fKey == key;
+}
+
+bool GrGpuGLShaders2::ProgramCache::HashKey::LT(const Entry& entry,
+                                                const HashKey& key) {
+    return entry.fKey < key;
+}
+
+bool GrGpuGLShaders2::ProgramCache::HashKey::operator ==(const HashKey& key) const {
+    return fDesc == key.fDesc;
+}
+
+bool GrGpuGLShaders2::ProgramCache::HashKey::operator <(const HashKey& key) const {
+    return memcmp(&fDesc, &key.fDesc, sizeof(HashKey)) < 0;
+}
+
+uint32_t GrGpuGLShaders2::ProgramCache::HashKey::getHash() const {
+    return fHash;
+}
+
+
+struct GrGpuGLShaders2::ShaderCodeSegments {
+    GrSStringBuilder<256> fVSUnis;
+    GrSStringBuilder<256> fVSAttrs;
+    GrSStringBuilder<256> fVaryings;
+    GrSStringBuilder<256> fFSUnis;
+    GrSStringBuilder<512> fVSCode;
+    GrSStringBuilder<512> fFSCode;
+};
+// for variable names etc
+typedef GrSStringBuilder<16> GrTokenString;
+
+#if ATTRIBUTE_MATRIX
+    #define VIEW_MATRIX_NAME "aViewM"
+#else
+    #define VIEW_MATRIX_NAME "uViewM"
+#endif
+
+#define POS_ATTR_NAME "aPosition"
+#define COL_ATTR_NAME "aColor"
+#define TEX_ATTR_NAME "aTexture"
+
+static inline const char* float_vector_type(int count) {
+    static const char* FLOAT_VECS[] = {"ERROR", "float", "vec2", "vec3", "vec4"};
+    GrAssert(count >= 1 && count < GR_ARRAY_COUNT(FLOAT_VECS));
+    return FLOAT_VECS[count];
+}
+
+static inline const char* vector_homog_coord(int count) {
+    static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"};
+    GrAssert(count >= 1 && count < GR_ARRAY_COUNT(HOMOGS));
+    return HOMOGS[count];
+}
+
+static inline const char* vector_nonhomog_coords(int count) {
+    static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
+    GrAssert(count >= 1 && count < GR_ARRAY_COUNT(NONHOMOGS));
+    return NONHOMOGS[count];
+}
+
+static inline const char* vector_all_coords(int count) {
+    static const char* ALL[] = {"ERROR", "", ".xy", ".xyz", ".xyzw"};
+    GrAssert(count >= 1 && count < GR_ARRAY_COUNT(ALL));
+    return ALL[count];
+}
+
+static void tex_matrix_name(int stage, GrStringBuilder* s) {
+#if ATTRIBUTE_MATRIX
+    *s = "aTexM";
+#else
+    *s = "uTexM";
+#endif
+    s->appendInt(stage);
+}
+
+static void sampler_name(int stage, GrStringBuilder* s) {
+    *s = "uSampler";
+    s->appendInt(stage);
+}
+
+static void stage_varying_name(int stage, GrStringBuilder* s) {
+    *s = "vStage";
+    s->appendInt(stage);
+}
+
+static void radial2_param_name(int stage, GrStringBuilder* s) {
+    *s = "uRadial2Params";
+    s->appendInt(stage);
+}
+
+static void radial2_varying_name(int stage, GrStringBuilder* s) {
+    *s = "vB";
+    s->appendInt(stage);
+}
+
+#include "GrRandom.h"
+
+void GrGpuGLShaders2::ProgramUnitTest() {
+    static const uint16_t VFORMATS[] = {
+        0,
+        kSeparateTexCoord_VertexLayoutBit,
+        kPositionAsTexCoord_VertexLayoutBit,
+        kSeparateTexCoord_VertexLayoutBit | kColor_VertexLayoutBit,
+        kPositionAsTexCoord_VertexLayoutBit | kColor_VertexLayoutBit,
+        kTextFormat_VertexLayoutBit
+    };
+    static const int PROG_OPTS[] = {
+        0,
+        ProgramDesc::kNotPoints_OptFlagBit,
+        ProgramDesc::kVertexColorAllOnes_OptFlagBit,
+        ProgramDesc::kNotPoints_OptFlagBit | ProgramDesc::kVertexColorAllOnes_OptFlagBit
+    };
+    static const int STAGE_OPTS[] = {
+        0,
+        StageDesc::kNoPerspective_OptFlagBit,
+        StageDesc::kIdentity_CoordMapping
+    };
+    static const int STAGE_MODULATES[] = {
+        StageDesc::kColor_Modulation,
+        StageDesc::kAlpha_Modulation
+    };
+    static const int STAGE_COORD_MAPPINGS[] = {
+        StageDesc::kIdentity_CoordMapping,
+        StageDesc::kRadialGradient_CoordMapping,
+        StageDesc::kSweepGradient_CoordMapping,
+        StageDesc::kRadial2Gradient_CoordMapping
+    };
+    ProgramDesc pdesc;
+    memset(&pdesc, 0, sizeof(pdesc));
+
+    static const int NUM_TESTS = 1024;
+
+    // GrRandoms nextU() values have patterns in the low bits
+    // So using nextU() % array_count might never take some values.
+    GrRandom random;
+    for (int t = 0; t < NUM_TESTS; ++t) {
+        int x = (int)(random.nextF() * GR_ARRAY_COUNT(VFORMATS));
+        pdesc.fVertexLayout = VFORMATS[x];
+        x = (int)(random.nextF() * GR_ARRAY_COUNT(PROG_OPTS));
+        pdesc.fOptFlags = PROG_OPTS[x];
+        for (int s = 0; s < NUM_STAGES; ++s) {
+            x = (int)(random.nextF() * 2.f);
+            pdesc.fStages[s].fEnabled = x;
+            x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_OPTS));
+            pdesc.fStages[s].fOptFlags = STAGE_OPTS[x];
+            x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_MODULATES));
+            pdesc.fStages[s].fModulation = STAGE_MODULATES[x];
+            x = (int)(random.nextF() * GR_ARRAY_COUNT(STAGE_COORD_MAPPINGS));
+            pdesc.fStages[s].fCoordMapping = STAGE_COORD_MAPPINGS[x];
+        }
+        Program program;
+        GenProgram(pdesc, &program);
+        DeleteProgram(&program);
+    }
+}
+
+void GrGpuGLShaders2::GenStageCode(int stageNum,
+                                   const StageDesc& desc,
+                                   const char* fsInColor, // NULL means no incoming color
+                                   const char* fsOutColor,
+                                   const char* vsInCoord,
+                                   ShaderCodeSegments* segments,
+                                   StageUniLocations* locations) {
+
+    GrAssert(stageNum >= 0 && stageNum <= 9);
+
+    GrTokenString 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.
+    static const int coordDims = 2;
+    int varyingDims;
+    /// Vertex Shader Stuff
+
+    // decide whether we need a matrix to transform texture coords
+    // and whether the varying needs a perspective coord.
+    GrTokenString texMName;
+    tex_matrix_name(stageNum, &texMName);
+    if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
+        varyingDims = coordDims;
+    } else {
+    #if ATTRIBUTE_MATRIX
+        segments->fVSAttrs += "attribute mat3 ";
+        segments->fVSAttrs += texMName;
+        segments->fVSAttrs += ";\n";
+    #else
+        segments->fVSUnis += "uniform mat3 ";
+        segments->fVSUnis += texMName;
+        segments->fVSUnis += ";\n";
+        locations->fTextureMatrixUni = 1;
+    #endif
+        if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
+            varyingDims = coordDims;
+        } else {
+            varyingDims = coordDims + 1;
+        }
+    }
+
+    GrTokenString samplerName;
+    sampler_name(stageNum, &samplerName);
+    segments->fFSUnis += "uniform sampler2D ";
+    segments->fFSUnis += samplerName;
+    segments->fFSUnis += ";\n";
+    locations->fSamplerUni = 1;
+
+    segments->fVaryings += "varying ";
+    segments->fVaryings += float_vector_type(varyingDims);
+    segments->fVaryings += " ";
+    segments->fVaryings += varyingName;
+    segments->fVaryings += ";\n";
+
+    if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
+        GrAssert(varyingDims == coordDims);
+        segments->fVSCode += "\t";
+        segments->fVSCode += varyingName;
+        segments->fVSCode += " = ";
+        segments->fVSCode += vsInCoord;
+        segments->fVSCode += ";\n";
+    } else {
+        segments->fVSCode += "\t";
+        segments->fVSCode += varyingName;
+        segments->fVSCode += " = (";
+        segments->fVSCode += texMName;
+        segments->fVSCode += " * vec3(";
+        segments->fVSCode += vsInCoord;
+        segments->fVSCode += ", 1))";
+        segments->fVSCode += vector_all_coords(varyingDims);
+        segments->fVSCode += ";\n";
+    }
+
+    GrTokenString radial2ParamsName;
+    radial2_param_name(stageNum, &radial2ParamsName);
+    // for radial grads without perspective we can pass the linear
+    // part of the quadratic as a varying.
+    GrTokenString radial2VaryingName;
+    radial2_varying_name(stageNum, &radial2VaryingName);
+
+    if (StageDesc::kRadial2Gradient_CoordMapping == desc.fCoordMapping) {
+
+        segments->fVSUnis += "uniform " GR_PRECISION " float ";
+        segments->fVSUnis += radial2ParamsName;
+        segments->fVSUnis += "[6];\n";
+
+        segments->fFSUnis += "uniform " GR_PRECISION " float ";
+        segments->fFSUnis += radial2ParamsName;
+        segments->fFSUnis += "[6];\n";
+        locations->fRadial2Uni = 1;
+
+        // if there is perspective we don't interpolate this
+        if (varyingDims == coordDims) {
+            GrAssert(2 == coordDims);
+            segments->fVaryings += "varying float ";
+            segments->fVaryings += radial2VaryingName;
+            segments->fVaryings += ";\n";
+
+            segments->fVSCode += "\t";
+            segments->fVSCode += radial2VaryingName;
+            segments->fVSCode += " = 2.0 * (";
+            segments->fVSCode += radial2ParamsName;
+            segments->fVSCode += "[2] * ";
+            segments->fVSCode += varyingName;
+            segments->fVSCode += ".x ";
+            segments->fVSCode += " - ";
+            segments->fVSCode += radial2ParamsName;
+            segments->fVSCode += "[3]);\n";
+        }
+    }
+
+    /// Fragment Shader Stuff
+    GrTokenString fsCoordName;
+    // function used to access the shader, may be made projective
+    GrTokenString texFunc("texture2D");
+    if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
+                          StageDesc::kNoPerspective_OptFlagBit)) {
+        GrAssert(varyingDims == coordDims);
+        fsCoordName = varyingName;
+    } else {
+        // if we have to do some non-matrix op on the varyings to get
+        // our final tex coords then when in perspective we have to
+        // do an explicit divide
+        if  (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) {
+            texFunc += "Proj";
+            fsCoordName = varyingName;
+        } else {
+            fsCoordName = "tCoord";
+            fsCoordName.appendInt(stageNum);
+
+            segments->fFSCode += "\t";
+            segments->fFSCode += float_vector_type(coordDims);
+            segments->fFSCode += " ";
+            segments->fFSCode += fsCoordName;
+            segments->fFSCode += " = ";
+            segments->fFSCode += varyingName;
+            segments->fFSCode += vector_nonhomog_coords(varyingDims);
+            segments->fFSCode += " / ";
+            segments->fFSCode += varyingName;
+            segments->fFSCode += vector_homog_coord(varyingDims);
+            segments->fFSCode += ";\n";
+        }
+    }
+
+    GrSStringBuilder<96> sampleCoords;
+    switch (desc.fCoordMapping) {
+    case StageDesc::kIdentity_CoordMapping:
+        sampleCoords = fsCoordName;
+        break;
+    case StageDesc::kSweepGradient_CoordMapping:
+        sampleCoords = "vec2(atan(-";
+        sampleCoords += fsCoordName;
+        sampleCoords += ".y, -";
+        sampleCoords += fsCoordName;
+        sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
+        break;
+    case StageDesc::kRadialGradient_CoordMapping:
+        sampleCoords = "vec2(length(";
+        sampleCoords += fsCoordName;
+        sampleCoords += ".xy), 0.5)";
+        break;
+    case StageDesc::kRadial2Gradient_CoordMapping: {
+        GrTokenString cName    = "c";
+        GrTokenString ac4Name  = "ac4";
+        GrTokenString rootName = "root";
+
+        cName.appendInt(stageNum);
+        ac4Name.appendInt(stageNum);
+        rootName.appendInt(stageNum);
+
+        GrTokenString bVar;
+        if (coordDims == varyingDims) {
+            bVar = radial2VaryingName;
+            GrAssert(2 == varyingDims);
+        } else {
+            GrAssert(3 == varyingDims);
+            bVar = "b";
+            bVar.appendInt(stageNum);
+            segments->fFSCode += "\tfloat ";
+            segments->fFSCode += bVar;
+            segments->fFSCode += " = 2.0 * (";
+            segments->fFSCode += radial2ParamsName;
+            segments->fFSCode += "[2] * ";
+            segments->fFSCode += fsCoordName;
+            segments->fFSCode += ".x ";
+            segments->fFSCode += " - ";
+            segments->fFSCode += radial2ParamsName;
+            segments->fFSCode += "[3]);\n";
+        }
+
+        segments->fFSCode += "\tfloat ";
+        segments->fFSCode += cName;
+        segments->fFSCode += " = dot(";
+        segments->fFSCode += fsCoordName;
+        segments->fFSCode += ", ";
+        segments->fFSCode += fsCoordName;
+        segments->fFSCode += ") + ";
+        segments->fFSCode += " - ";
+        segments->fFSCode += radial2ParamsName;
+        segments->fFSCode += "[4];\n";
+
+        segments->fFSCode += "\tfloat ";
+        segments->fFSCode += ac4Name;
+        segments->fFSCode += " = ";
+        segments->fFSCode += radial2ParamsName;
+        segments->fFSCode += "[0] * 4.0 * ";
+        segments->fFSCode += cName;
+        segments->fFSCode += ";\n";
+
+        segments->fFSCode += "\tfloat ";
+        segments->fFSCode += rootName;
+        segments->fFSCode += " = sqrt(abs(";
+        segments->fFSCode += bVar;
+        segments->fFSCode += " * ";
+        segments->fFSCode += bVar;
+        segments->fFSCode += " - ";
+        segments->fFSCode += ac4Name;
+        segments->fFSCode += "));\n";
+
+        sampleCoords = "vec2((-";
+        sampleCoords += bVar;
+        sampleCoords += " + ";
+        sampleCoords += radial2ParamsName;
+        sampleCoords += "[5] * ";
+        sampleCoords += rootName;
+        sampleCoords += ") * ";
+        sampleCoords += radial2ParamsName;
+        sampleCoords += "[1], 0.5)\n";
+        break;}
+    };
+
+    segments->fFSCode += "\t";
+    segments->fFSCode += fsOutColor;
+    segments->fFSCode += " = ";
+    if (NULL != fsInColor) {
+        segments->fFSCode += fsInColor;
+        segments->fFSCode += " * ";
+    }
+    segments->fFSCode += texFunc;
+    segments->fFSCode += "(";
+    segments->fFSCode += samplerName;
+    segments->fFSCode += ", ";
+    segments->fFSCode += sampleCoords;
+    segments->fFSCode += ")";
+    if (desc.fModulation == StageDesc::kAlpha_Modulation) {
+        segments->fFSCode += ".aaaa";
+    }
+    segments->fFSCode += ";\n";
+
+}
+
+void GrGpuGLShaders2::GenProgram(const ProgramDesc& desc,
+                                 Program* program) {
+
+    ShaderCodeSegments segments;
+    const uint32_t& layout = desc.fVertexLayout;
+
+    memset(&program->fUniLocations, 0, sizeof(UniLocations));
+
+    bool haveColor = !(ProgramDesc::kVertexColorAllOnes_OptFlagBit &
+                       desc.fOptFlags);
+
+#if ATTRIBUTE_MATRIX
+    segments.fVSAttrs = "attribute mat3 " VIEW_MATRIX_NAME ";\n"
+#else
+    segments.fVSUnis  = "uniform mat3 " VIEW_MATRIX_NAME ";\n";
+    segments.fVSAttrs = "";
+#endif
+    segments.fVSAttrs += "attribute vec2 " POS_ATTR_NAME ";\n";
+    if (haveColor) {
+        segments.fVSAttrs += "attribute vec4 " COL_ATTR_NAME ";\n";
+        segments.fVaryings = "varying vec4 vColor;\n";
+    } else {
+        segments.fVaryings = "";
+    }
+
+    segments.fVSCode   = "void main() {\n"
+                         "\tvec3 pos3 = " VIEW_MATRIX_NAME " * vec3(" POS_ATTR_NAME ", 1);\n"
+                         "\tgl_Position = vec4(pos3.xy, 0, pos3.z);\n";
+    if (haveColor) {
+        segments.fVSCode += "\tvColor = " COL_ATTR_NAME ";\n";
+    }
+
+    if (!(desc.fOptFlags & ProgramDesc::kNotPoints_OptFlagBit)){
+        segments.fVSCode += "\tgl_PointSize = 1.0;\n";
+    }
+    segments.fFSCode   = "void main() {\n";
+
+    bool textureCoordAttr = false;
+    static const char* IN_COORDS[] = {POS_ATTR_NAME, TEX_ATTR_NAME};
+    const char* inCoords = NULL;
+    if ((kSeparateTexCoord_VertexLayoutBit | kTextFormat_VertexLayoutBit) &
+        layout) {
+        segments.fVSAttrs += "attribute vec2 " TEX_ATTR_NAME ";\n";
+        inCoords = IN_COORDS[1];
+        textureCoordAttr = true;
+    } else if (kPositionAsTexCoord_VertexLayoutBit & layout) {
+        inCoords = IN_COORDS[0];
+    }
+
+    GrTokenString inColor = "vColor";
+    GR_STATIC_ASSERT(NUM_STAGES <= 9);
+    int numActiveStages = 0;
+    for (int i = 0; i < NUM_STAGES; ++i) {
+        if (desc.fStages[i].fEnabled) {
+            ++numActiveStages;
+        }
+    }
+    if (NULL != inCoords && numActiveStages) {
+        int currActiveStage = 0;
+        for (int i = 0; i < NUM_STAGES; ++i) {
+            if (desc.fStages[i].fEnabled) {
+                GrTokenString outColor;
+                if (currActiveStage < (numActiveStages - 1)) {
+                    outColor = "color";
+                    outColor.appendInt(currActiveStage);
+                    segments.fFSCode += "\tvec4 ";
+                    segments.fFSCode += outColor;
+                    segments.fFSCode += ";\n";
+                } else {
+                    outColor = "gl_FragColor";
+                }
+                GenStageCode(i,
+                             desc.fStages[i],
+                             haveColor ? inColor.cstr() : NULL,
+                             outColor.cstr(),
+                             inCoords,
+                             &segments,
+                             &program->fUniLocations.fStages[i]);
+                ++currActiveStage;
+                inColor = outColor;
+                haveColor = true;
+            }
+        }
+    } else {
+        segments.fFSCode += "\tgl_FragColor = ";
+        if (haveColor) {
+            segments.fFSCode += inColor;
+        } else {
+            segments.fFSCode += "vec4(1,1,1,1)";
+        }
+        segments.fFSCode += ";\n";
+    }
+    segments.fFSCode += "}\n";
+    segments.fVSCode += "}\n";
+
+
+    const char* strings[4];
+    int lengths[4];
+    int stringCnt = 0;
+
+    if (segments.fVSUnis.length()) {
+        strings[stringCnt] = segments.fVSUnis.cstr();
+        lengths[stringCnt] = segments.fVSUnis.length();
+        ++stringCnt;
+    }
+    if (segments.fVSAttrs.length()) {
+        strings[stringCnt] = segments.fVSAttrs.cstr();
+        lengths[stringCnt] = segments.fVSAttrs.length();
+        ++stringCnt;
+    }
+    if (segments.fVaryings.length()) {
+        strings[stringCnt] = segments.fVaryings.cstr();
+        lengths[stringCnt] = segments.fVaryings.length();
+        ++stringCnt;
+    }
+
+    GrAssert(segments.fVSCode.length());
+    strings[stringCnt] = segments.fVSCode.cstr();
+    lengths[stringCnt] = segments.fVSCode.length();
+    ++stringCnt;
+
+#if PRINT_SHADERS
+    GrPrintf("%s%s%s%s\n",
+             segments.fVSUnis.cstr(),
+             segments.fVSAttrs.cstr(),
+             segments.fVaryings.cstr(),
+             segments.fVSCode.cstr());
+#endif
+    program->fVShaderID = CompileShader(GL_VERTEX_SHADER,
+                                        stringCnt,
+                                        strings,
+                                        lengths);
+
+    stringCnt = 0;
+
+    if (GR_ARRAY_COUNT(GR_SHADER_PRECISION) > 1) {
+        strings[stringCnt] = GR_SHADER_PRECISION;
+        lengths[stringCnt] = GR_ARRAY_COUNT(GR_SHADER_PRECISION) - 1;
+        ++stringCnt;
+    }
+    if (segments.fFSUnis.length()) {
+        strings[stringCnt] = segments.fFSUnis.cstr();
+        lengths[stringCnt] = segments.fFSUnis.length();
+        ++stringCnt;
+    }
+    if (segments.fVaryings.length()) {
+        strings[stringCnt] = segments.fVaryings.cstr();
+        lengths[stringCnt] = segments.fVaryings.length();
+        ++stringCnt;
+    }
+
+    GrAssert(segments.fFSCode.length());
+    strings[stringCnt] = segments.fFSCode.cstr();
+    lengths[stringCnt] = segments.fFSCode.length();
+    ++stringCnt;
+
+#if PRINT_SHADERS
+    GrPrintf("%s%s%s%s\n",
+             GR_SHADER_PRECISION,
+             segments.fFSUnis.cstr(),
+             segments.fVaryings.cstr(),
+             segments.fFSCode.cstr());
+#endif
+    program->fFShaderID = CompileShader(GL_FRAGMENT_SHADER,
+                                        stringCnt,
+                                        strings,
+                                        lengths);
+
+    program->fProgramID = GR_GL(CreateProgram());
+    const GLint& progID = program->fProgramID;
+
+    GR_GL(AttachShader(progID, program->fVShaderID));
+    GR_GL(AttachShader(progID, program->fFShaderID));
+
+    // Bind the attrib locations to same values for all shaders
+    GR_GL(BindAttribLocation(progID, POS_ATTR_LOCATION, POS_ATTR_NAME));
+    if (textureCoordAttr) {
+        GR_GL(BindAttribLocation(progID, TEX_ATTR_LOCATION, TEX_ATTR_NAME));
+    }
+
+#if ATTRIBUTE_MATRIX
+    // set unis to a bogus value so that checks against -1 before
+    // flushing will pass.
+    GR_GL(BindAttribLocation(progID,
+                             VIEWMAT_ATTR_LOCATION,
+                             VIEW_MATRIX_NAME));
+
+    program->fUniLocations.fViewMatrixUni = BOGUS_MATRIX_UNI_LOCATION;
+
+    for (int i = 0; i < NUM_STAGES; ++i) {
+        if (desc.fStages[i].fEnabled) {
+            GR_GL(BindAttribLocation(progID,
+                                     TEXMAT_ATTR_LOCATION(i),
+                                     tex_matrix_name(i).cstr()));
+            program->fUniLocations.fStages[i].fTextureMatrixUni =
+                                                    BOGUS_MATRIX_UNI_LOCATION;
+        }
+    }
+#endif
+
+    GR_GL(BindAttribLocation(progID, COL_ATTR_LOCATION, COL_ATTR_NAME));
+
+    GR_GL(LinkProgram(progID));
+
+    GLint linked;
+    GR_GL(GetProgramiv(progID, GL_LINK_STATUS, &linked));
+    if (!linked) {
+        GLint infoLen;
+        GR_GL(GetProgramiv(progID, GL_INFO_LOG_LENGTH, &infoLen));
+        GrAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
+        if (infoLen > 0) {
+            GR_GL(GetProgramInfoLog(progID,
+                                    infoLen+1,
+                                    NULL,
+                                    (char*)log.get()));
+            GrPrintf((char*)log.get());
+        }
+        GrAssert(!"Error linking program");
+        GR_GL(DeleteProgram(progID));
+        program->fProgramID = 0;
+        return;
+    }
+
+    // Get uniform locations
+#if !ATTRIBUTE_MATRIX
+    program->fUniLocations.fViewMatrixUni =
+                    GR_GL(GetUniformLocation(progID, VIEW_MATRIX_NAME));
+    GrAssert(-1 != program->fUniLocations.fViewMatrixUni);
+#endif
+    for (int i = 0; i < NUM_STAGES; ++i) {
+        StageUniLocations& locations = program->fUniLocations.fStages[i];
+        if (desc.fStages[i].fEnabled) {
+#if !ATTRIBUTE_MATRIX
+            if (locations.fTextureMatrixUni) {
+                GrTokenString texMName;
+                tex_matrix_name(i, &texMName);
+                locations.fTextureMatrixUni = GR_GL(GetUniformLocation(
+                                                progID,
+                                                texMName.cstr()));
+                GrAssert(-1 != locations.fTextureMatrixUni);
+            } else {
+                locations.fTextureMatrixUni = -1;
+
+            }
+#endif
+
+            if (locations.fSamplerUni) {
+                GrTokenString samplerName;
+                sampler_name(i, &samplerName);
+                locations.fSamplerUni = GR_GL(GetUniformLocation(
+                                                     progID,
+                                                     samplerName.cstr()));
+                GrAssert(-1 != locations.fSamplerUni);
+            } else {
+                locations.fSamplerUni = -1;
+            }
+
+            if (locations.fRadial2Uni) {
+                GrTokenString radial2ParamName;
+                radial2_param_name(i, &radial2ParamName);
+                locations.fRadial2Uni = GR_GL(GetUniformLocation(
+                                             progID,
+                                             radial2ParamName.cstr()));
+                GrAssert(-1 != locations.fRadial2Uni);
+            } else {
+                locations.fRadial2Uni = -1;
+            }
+        } else {
+            locations.fSamplerUni = -1;
+            locations.fRadial2Uni = -1;
+            locations.fTextureMatrixUni = -1;
+        }
+    }
+    GR_GL(UseProgram(progID));
+
+    // init sampler unis and set bogus values for state tracking
+    for (int i = 0; i < NUM_STAGES; ++i) {
+        if (-1 != program->fUniLocations.fStages[i].fSamplerUni) {
+            GR_GL(Uniform1i(program->fUniLocations.fStages[i].fSamplerUni, i));
+        }
+        program->fTextureMatrix[i].setScale(GR_ScalarMax, GR_ScalarMax);
+        program->fRadial2CenterX1[i] = GR_ScalarMax;
+        program->fRadial2Radius0[i] = -GR_ScalarMax;
+    }
+    program->fViewMatrix.setScale(GR_ScalarMax, GR_ScalarMax);
+}
+
+void GrGpuGLShaders2::getProgramDesc(PrimitiveType primType, ProgramDesc* desc) {
+
+    // Must initialize all fields or cache will have false negatives!
+    desc->fVertexLayout = fGeometrySrc.fVertexLayout;
+    desc->fStages[0].fEnabled = VertexHasTexCoords(fGeometrySrc.fVertexLayout);
+    for (int i = 1; i < NUM_STAGES; ++i) {
+        desc->fStages[i].fEnabled       = false;
+        desc->fStages[i].fOptFlags      = 0;
+        desc->fStages[i].fCoordMapping  = 0;
+        desc->fStages[i].fModulation    = 0;
+    }
+
+    if (primType != kPoints_PrimitiveType) {
+        desc->fOptFlags = ProgramDesc::kNotPoints_OptFlagBit;
+    } else {
+        desc->fOptFlags = 0;
+    }
+#if SKIP_COLOR_MODULATE_OPT
+    if (!(desc->fVertexLayout & kColor_VertexLayoutBit) &&
+        (0xffffffff == fCurrDrawState.fColor)) {
+        desc->fOptFlags |= ProgramDesc::kVertexColorAllOnes_OptFlagBit;
+    }
+#endif
+
+    StageDesc& stage = desc->fStages[0];
+
+    if (stage.fEnabled) {
+        GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTexture;
+        GrAssert(NULL != texture);
+        // we matrix to invert when orientation is TopDown, so make sure
+        // we aren't in that case before flagging as identity.
+        if (fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode].isIdentity() &&
+            GrGLTexture::kTopDown_Orientation == texture->orientation()) {
+            stage.fOptFlags = StageDesc::kIdentityMatrix_OptFlagBit;
+        } else if (!fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode].hasPerspective()) {
+            stage.fOptFlags = StageDesc::kNoPerspective_OptFlagBit;
+        } else {
+            stage.fOptFlags = 0;
+        }
+        switch (fCurrDrawState.fSamplerState.getSampleMode()) {
+        case GrSamplerState::kNormal_SampleMode:
+            stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
+            stage.fModulation = StageDesc::kColor_Modulation;
+            break;
+        case GrSamplerState::kAlphaMod_SampleMode:
+            stage.fCoordMapping = StageDesc::kIdentity_CoordMapping;
+            stage.fModulation = StageDesc::kAlpha_Modulation;
+            break;
+        case GrSamplerState::kRadial_SampleMode:
+            stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping;
+            stage.fModulation = StageDesc::kColor_Modulation;
+            break;
+        case GrSamplerState::kRadial2_SampleMode:
+            stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping;
+            stage.fModulation = StageDesc::kColor_Modulation;
+            break;
+        case GrSamplerState::kSweep_SampleMode:
+            stage.fCoordMapping = StageDesc::StageDesc::kSweepGradient_CoordMapping;
+            stage.fModulation = StageDesc::kColor_Modulation;
+            break;
+        default:
+            GrAssert(!"Unexpected sample mode!");
+            break;
+        }
+    } else {
+        stage.fOptFlags     = 0;
+        stage.fCoordMapping = 0;
+        stage.fModulation   = 0;
+    }
+}
+
+GLuint GrGpuGLShaders2::CompileShader(GLenum type,
+                                      int stringCnt,
+                                      const char** strings,
+                                      int* stringLengths) {
+    GLuint shader = GR_GL(CreateShader(type));
+    if (0 == shader) {
+        return 0;
+    }
+
+    GLint compiled;
+    GR_GL(ShaderSource(shader, stringCnt, strings, stringLengths));
+    GR_GL(CompileShader(shader));
+    GR_GL(GetShaderiv(shader, GL_COMPILE_STATUS, &compiled));
+
+    if (!compiled) {
+        GLint infoLen;
+        GR_GL(GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen));
+        GrAutoMalloc log(sizeof(char)*(infoLen+1)); // outside if for debugger
+        if (infoLen > 0) {
+            GR_GL(GetShaderInfoLog(shader, infoLen+1, NULL, (char*)log.get()));
+            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!");
+        GR_GL(DeleteShader(shader));
+        return 0;
+    }
+    return shader;
+}
+
+void GrGpuGLShaders2::DeleteProgram(Program* program) {
+    GR_GL(DeleteShader(program->fVShaderID));
+    GR_GL(DeleteShader(program->fFShaderID));
+    GR_GL(DeleteProgram(program->fProgramID));
+    GR_DEBUGCODE(memset(program, 0, sizeof(Program)));
+}
+
+
+GrGpuGLShaders2::GrGpuGLShaders2() {
+
+    resetContextHelper();
+
+    fProgram = NULL;
+    fProgramCache = new ProgramCache();
+
+#if GR_DEBUG
+    ProgramUnitTest();
+#endif
+}
+
+GrGpuGLShaders2::~GrGpuGLShaders2() {
+    delete fProgramCache;
+}
+
+void GrGpuGLShaders2::resetContext() {
+    INHERITED::resetContext();
+    resetContextHelper();
+}
+
+void GrGpuGLShaders2::resetContextHelper() {
+    fTextureOrientation = (GrGLTexture::Orientation)-1; // illegal
+
+    fHWGeometryState.fVertexLayout = 0;
+    fHWGeometryState.fPositionPtr  = (void*) ~0;
+    GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
+    GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION));
+    GR_GL(EnableVertexAttribArray(POS_ATTR_LOCATION));
+
+    fHWProgramID = 0;
+}
+
+void GrGpuGLShaders2::flushViewMatrix() {
+    GrAssert(NULL != fCurrDrawState.fRenderTarget);
+    GrMatrix m (
+        GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
+        0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
+        0, 0, GrMatrix::I()[8]);
+    m.setConcat(m, fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode]);
+
+    // ES doesn't allow you to pass true to the transpose param,
+    // so do our own transpose
+    GrScalar mt[]  = {
+        m[GrMatrix::kScaleX],
+        m[GrMatrix::kSkewY],
+        m[GrMatrix::kPersp0],
+        m[GrMatrix::kSkewX],
+        m[GrMatrix::kScaleY],
+        m[GrMatrix::kPersp1],
+        m[GrMatrix::kTransX],
+        m[GrMatrix::kTransY],
+        m[GrMatrix::kPersp2]
+    };
+#if ATTRIBUTE_MATRIX
+    glVertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0);
+    glVertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3);
+    glVertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6);
+#else
+    GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fViewMatrixUni,1,false,mt));
+#endif
+}
+
+void GrGpuGLShaders2::flushTextureMatrix() {
+
+    GrAssert(NULL != fCurrDrawState.fTexture);
+    GrGLTexture::Orientation orientation =
+         ((GrGLTexture*)fCurrDrawState.fTexture)->orientation();
+
+    GrMatrix* m;
+    GrMatrix temp;
+    if (GrGLTexture::kBottomUp_Orientation == orientation) {
+        temp.setAll(
+            GR_Scalar1, 0, 0,
+            0, -GR_Scalar1, GR_Scalar1,
+            0, 0, GrMatrix::I()[8]
+        );
+        temp.preConcat(fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode]);
+        m = &temp;
+    } else {
+        GrAssert(GrGLTexture::kTopDown_Orientation == orientation);
+        m = &fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode];
+    }
+
+    // ES doesn't allow you to pass true to the transpose param,
+    // so do our own transpose
+    GrScalar mt[]  = {
+        (*m)[GrMatrix::kScaleX],
+        (*m)[GrMatrix::kSkewY],
+        (*m)[GrMatrix::kPersp0],
+        (*m)[GrMatrix::kSkewX],
+        (*m)[GrMatrix::kScaleY],
+        (*m)[GrMatrix::kPersp1],
+        (*m)[GrMatrix::kTransX],
+        (*m)[GrMatrix::kTransY],
+        (*m)[GrMatrix::kPersp2]
+    };
+#if ATTRIBUTE_MATRIX
+    glVertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+0, mt+0);
+    glVertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+1, mt+3);
+    glVertexAttrib4fv(TEXMAT_ATTR_LOCATION(0)+2, mt+6);
+#else
+    GR_GL(UniformMatrix3fv(fProgram->fUniLocations.fStages[0].fTextureMatrixUni,
+                           1,
+                           false,
+                           mt));
+#endif
+}
+
+void GrGpuGLShaders2::flushRadial2() {
+
+    const GrSamplerState& sampler = fCurrDrawState.fSamplerState;
+
+    GrScalar centerX1 = sampler.getRadial2CenterX1();
+    GrScalar radius0 = sampler.getRadial2Radius0();
+
+    GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
+
+    float unis[6] = {
+        GrScalarToFloat(a),
+        1 / (2.f * unis[0]),
+        GrScalarToFloat(centerX1),
+        GrScalarToFloat(radius0),
+        GrScalarToFloat(GrMul(radius0, radius0)),
+        sampler.isRadial2PosRoot() ? 1.f : -1.f
+    };
+    GR_GL(Uniform1fv(fProgram->fUniLocations.fStages[0].fRadial2Uni, 6, unis));
+}
+
+void GrGpuGLShaders2::flushProgram(PrimitiveType type) {
+    ProgramDesc desc;
+    getProgramDesc(type, &desc);
+    fProgram = fProgramCache->getProgram(desc);
+
+    if (fHWProgramID != fProgram->fProgramID) {
+        GR_GL(UseProgram(fProgram->fProgramID));
+        fHWProgramID = fProgram->fProgramID;
+#if GR_COLLECT_STATS
+        ++fStats.fProgChngCnt;
+#endif
+    }
+}
+
+bool GrGpuGLShaders2::flushGraphicsState(PrimitiveType type) {
+
+    flushGLStateCommon(type);
+
+    if (fRenderTargetChanged) {
+        // our coords are in pixel space and the GL matrices map to NDC
+        // so if the viewport changed, our matrix is now wrong.
+#if ATTRIBUTE_MATRIX
+        fHWDrawState.fMatrixModeCache[kModelView_MatrixMode].setScale(GR_ScalarMax,
+                                                                      GR_ScalarMax);
+#else
+        // we assume all shader matrices may be wrong after viewport changes
+        fProgramCache->invalidateViewMatrices();
+#endif
+        fRenderTargetChanged = false;
+    }
+
+    flushProgram(type);
+
+    if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
+        // invalidate the immediate mode color
+        fHWDrawState.fColor = GrColor_ILLEGAL;
+    } else {
+        if (fHWDrawState.fColor != fCurrDrawState.fColor) {
+            // OpenGL ES only supports the float varities of glVertexAttrib
+            float c[] = {
+                GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
+                GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
+                GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
+                GrColorUnpackA(fCurrDrawState.fColor) / 255.f
+            };
+            GR_GL(VertexAttrib4fv(COL_ATTR_LOCATION, c));
+            fHWDrawState.fColor = fCurrDrawState.fColor;
+        }
+    }
+
+#if ATTRIBUTE_MATRIX
+    GrMatrix& currViewMatrix = fHWDrawState.fMatrixModeCache[kModelView_MatrixMode];
+    GrMatrix& currTextureMatrix = fHWDrawState.fMatrixModeCache[kTexture_MatrixMode];
+    GrGLTexture::Orientation& orientation = fTextureOrientation;
+#else
+    GrMatrix& currViewMatrix = fProgram->fViewMatrix;
+    GrMatrix& currTextureMatrix = fProgram->fTextureMatrix[0];
+    GrGLTexture::Orientation& orientation =  fProgram->fTextureOrientation[0];
+#endif
+
+    if (currViewMatrix != fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode]) {
+        flushViewMatrix();
+        currViewMatrix = fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode];
+    }
+
+    GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTexture;
+    if (NULL != texture) {
+        if (-1 != fProgram->fUniLocations.fStages[0].fTextureMatrixUni &&
+            (currTextureMatrix !=
+                        fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode] ||
+             orientation != texture->orientation())) {
+            flushTextureMatrix();
+            currTextureMatrix = fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode];
+            orientation = texture->orientation();
+        }
+    }
+
+    const GrSamplerState& sampler = fCurrDrawState.fSamplerState;
+    if (-1 != fProgram->fUniLocations.fStages[0].fRadial2Uni &&
+        (fProgram->fRadial2CenterX1[0] != sampler.getRadial2CenterX1() ||
+         fProgram->fRadial2Radius0[0]  != sampler.getRadial2Radius0()  ||
+         fProgram->fRadial2PosRoot[0]  != sampler.isRadial2PosRoot())) {
+
+        flushRadial2();
+
+        fProgram->fRadial2CenterX1[0] = sampler.getRadial2CenterX1();
+        fProgram->fRadial2Radius0[0]  = sampler.getRadial2Radius0();
+        fProgram->fRadial2PosRoot[0]  = sampler.isRadial2PosRoot();
+    }
+
+    return true;
+}
+
+void GrGpuGLShaders2::setupGeometry(uint32_t startVertex,
+                                   uint32_t startIndex,
+                                   uint32_t vertexCount,
+                                   uint32_t indexCount) {
+
+    int newColorOffset, newTexCoordOffset;
+
+    GLsizei newStride = VertexSizeAndOffsets(fGeometrySrc.fVertexLayout,
+                                             &newTexCoordOffset,
+                                             &newColorOffset);
+    int oldColorOffset, oldTexCoordOffset;
+    GLsizei oldStride = VertexSizeAndOffsets(fHWGeometryState.fVertexLayout,
+                                             &oldTexCoordOffset,
+                                             &oldColorOffset);
+
+    const GLvoid* posPtr = (GLvoid*)(newStride * startVertex);
+
+    if (kBuffer_GeometrySrcType == fGeometrySrc.fVertexSrc) {
+        GrAssert(NULL != fGeometrySrc.fVertexBuffer);
+        GrAssert(!fGeometrySrc.fVertexBuffer->isLocked());
+        if (fHWGeometryState.fVertexBuffer != fGeometrySrc.fVertexBuffer) {
+            GrGLVertexBuffer* buf =
+            (GrGLVertexBuffer*)fGeometrySrc.fVertexBuffer;
+            GR_GL(BindBuffer(GL_ARRAY_BUFFER, buf->bufferID()));
+            fHWGeometryState.fVertexBuffer = fGeometrySrc.fVertexBuffer;
+        }
+    } else {
+        if (kArray_GeometrySrcType == fGeometrySrc.fVertexSrc) {
+            posPtr = (void*)((intptr_t)fGeometrySrc.fVertexArray +
+                             (intptr_t)posPtr);
+        } else {
+            GrAssert(kReserved_GeometrySrcType == fGeometrySrc.fVertexSrc);
+            posPtr = (void*)((intptr_t)fVertices.get() + (intptr_t)posPtr);
+        }
+        if (NULL != fHWGeometryState.fVertexBuffer) {
+            GR_GL(BindBuffer(GL_ARRAY_BUFFER, 0));
+            fHWGeometryState.fVertexBuffer = NULL;
+        }
+    }
+
+    if (kBuffer_GeometrySrcType == fGeometrySrc.fIndexSrc) {
+        GrAssert(NULL != fGeometrySrc.fIndexBuffer);
+        GrAssert(!fGeometrySrc.fIndexBuffer->isLocked());
+        if (fHWGeometryState.fIndexBuffer != fGeometrySrc.fIndexBuffer) {
+            GrGLIndexBuffer* buf =
+            (GrGLIndexBuffer*)fGeometrySrc.fIndexBuffer;
+            GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf->bufferID()));
+            fHWGeometryState.fIndexBuffer = fGeometrySrc.fIndexBuffer;
+        }
+    } else if (NULL != fHWGeometryState.fIndexBuffer) {
+        GR_GL(BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
+        fHWGeometryState.fIndexBuffer = NULL;
+    }
+
+    GLenum scalarType;
+    bool texCoordNorm;
+    if (fGeometrySrc.fVertexLayout & kTextFormat_VertexLayoutBit) {
+        scalarType = GrGLTextType;
+        texCoordNorm = GR_GL_TEXT_TEXTURE_NORMALIZED;
+    } else {
+        scalarType = GrGLType;
+        texCoordNorm = false;
+    }
+
+    bool baseChange = posPtr != fHWGeometryState.fPositionPtr;
+    bool scalarChange = (GrGLTextType != GrGLType) &&
+                        (kTextFormat_VertexLayoutBit &
+                         (fHWGeometryState.fVertexLayout ^
+                          fGeometrySrc.fVertexLayout));
+    bool strideChange = newStride != oldStride;
+    bool posChange = baseChange || scalarChange || strideChange;
+
+    if (posChange) {
+        GR_GL(VertexAttribPointer(POS_ATTR_LOCATION, 2, scalarType,
+                                  false, newStride, posPtr));
+        fHWGeometryState.fPositionPtr = posPtr;
+    }
+
+    if (newTexCoordOffset > 0) {
+        GLvoid* texCoordPtr = (int8_t*)posPtr + newTexCoordOffset;
+        if (oldTexCoordOffset <= 0) {
+            GR_GL(EnableVertexAttribArray(TEX_ATTR_LOCATION));
+        }
+        if (posChange || newTexCoordOffset != oldTexCoordOffset) {
+            GR_GL(VertexAttribPointer(TEX_ATTR_LOCATION, 2, scalarType,
+                                      texCoordNorm, newStride, texCoordPtr));
+        }
+    } else if (oldTexCoordOffset > 0) {
+        GR_GL(DisableVertexAttribArray(TEX_ATTR_LOCATION));
+    }
+
+    if (newColorOffset > 0) {
+        GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
+        if (oldColorOffset <= 0) {
+            GR_GL(EnableVertexAttribArray(COL_ATTR_LOCATION));
+        }
+        if (posChange || newColorOffset != oldColorOffset) {
+            GR_GL(VertexAttribPointer(COL_ATTR_LOCATION, 4,
+                                      GL_UNSIGNED_BYTE,
+                                      true, newStride, colorPtr));
+        }
+    } else if (oldColorOffset > 0) {
+        GR_GL(DisableVertexAttribArray(COL_ATTR_LOCATION));
+    }
+
+    fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
+}
+#endif
+