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/GrGpuGLShaders.cpp b/gpu/src/GrGpuGLShaders.cpp
new file mode 100644
index 0000000..8f4bfaf
--- /dev/null
+++ b/gpu/src/GrGpuGLShaders.cpp
@@ -0,0 +1,937 @@
+/*
+    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 "GrGpuGLShaders.h"
+#include "GrGpuVertex.h"
+#include "GrMemory.h"
+
+#define ATTRIBUTE_MATRIX        0
+
+#define ATTRIBUTE_TEXT_COLOR    1
+
+#if ATTRIBUTE_MATRIX
+    #define DECL_MATRIX(name) "attribute mat3 " #name ";\n"
+#else
+    #define DECL_MATRIX(name) "uniform mat3 " #name ";\n"
+#endif
+
+#define SKIP_CACHE_CHECK    true
+
+#if GR_SUPPORT_GLES2
+    #define GR_PRECISION            "mediump"
+    #define GR_SHADER_PRECISION     "precision mediump float;\n"
+#else
+    #define GR_PRECISION            ""
+    #define GR_SHADER_PRECISION     ""
+#endif
+
+static const char* gvshad[] = {
+    // 0: kTextureVertCoords_Program, kTextureVertCoordsProj_Program,
+    //    kRadialTextureVertCoords_Program, kSweepTextureVertCoords_Program
+    "attribute vec2 aPosition;\n"
+    "attribute vec4 aColor;\n"
+    "varying vec3 vTexture;\n"
+    "varying vec4 vColor;\n"
+    DECL_MATRIX(viewM)
+    DECL_MATRIX(texM)
+    "void main() {\n"
+    "   vec3 pos3 = viewM*vec3(aPosition,1);\n"
+    "   gl_Position = vec4(pos3.xy,0,pos3.z);\n"
+    "   gl_PointSize = 1.0;\n"
+    "   vTexture = texM * vec3(aPosition,1);\n"
+    "   vColor = aColor;\n"
+    "}\n",
+
+    // 1: kTextureTexCoords_Program, kTextureTexCoordsProj_Program,
+    //    kRadialTextureTexCoords_Program, kSweepTextureTexCoords_Program
+    "attribute vec2 aPosition;\n"
+    "attribute vec2 aTexture;\n"
+    "attribute vec4 aColor;\n"
+    "varying vec3 vTexture;\n"
+    "varying vec4 vColor;\n"
+    DECL_MATRIX(viewM)
+    DECL_MATRIX(texM)
+    "void main() {\n"
+    "   vec3 pos3 = viewM*vec3(aPosition,1);\n"
+    "   gl_Position = vec4(pos3.xy,0,pos3.z);\n"
+    "   gl_PointSize = 1.0;\n"
+    "   vTexture = texM * vec3(aTexture,1);\n"
+    "   vColor = aColor;\n"
+    "}\n",
+
+     // 2: kText_Program
+    "attribute vec2 aPosition;\n"
+    "attribute vec2 aTexture;\n"    
+    "varying vec2 vTexture;\n"
+    DECL_MATRIX(viewM)
+#if ATTRIBUTE_TEXT_COLOR
+    "varying vec4 vColor;\n"
+    "attribute vec4 aColor;\n"
+#endif
+    "void main() {\n"
+    "   vec3 pos3 = viewM*vec3(aPosition,1);\n"
+    "   gl_Position = vec4(pos3.xy,0,pos3.z);\n"
+    "   vTexture = aTexture;\n"
+#if ATTRIBUTE_TEXT_COLOR
+    "   vColor = aColor;\n"
+#endif
+    "}\n",
+
+    // 3: kNoTexture_Program
+    "attribute vec2 aPosition;\n"
+    "attribute vec4 aColor;\n"
+    "varying vec4 vColor;\n"
+    DECL_MATRIX(viewM)
+    "void main() {\n"
+    "   vec3 pos3 = viewM*vec3(aPosition,1);\n"
+    "   gl_Position = vec4(pos3.xy,0,pos3.z);\n"
+    "   gl_PointSize = 1.0;\n"
+    "   vColor = aColor;\n"
+    "}\n",
+
+    // 4: kTextureVertCoordsNoColor_Program
+    "attribute vec2 aPosition;\n"
+    "attribute vec4 aColor;\n"
+    "varying vec3 vTexture;\n"
+    DECL_MATRIX(viewM)
+    DECL_MATRIX(texM)
+    "void main() {\n"
+    "   vec3 pos3 = viewM*vec3(aPosition,1);\n"
+    "   gl_Position = vec4(pos3.xy,0,pos3.z);\n"
+    "   vTexture = texM * vec3(aPosition,1);\n"
+    "}\n",
+
+    // 5: kTextureTexCoordsNoColor_Program
+    "attribute vec2 aPosition;\n"
+    "attribute vec2 aTexture;\n"
+    "varying vec3 vTexture;\n"
+    DECL_MATRIX(viewM)
+    DECL_MATRIX(texM)
+    "void main() {\n"
+    "   vec3 pos3 = viewM*vec3(aPosition,1);\n"
+    "   gl_Position = vec4(pos3.xy,0,pos3.z);\n"
+    "   gl_PointSize = 1.0;\n"
+    "   vTexture = texM * vec3(aTexture,1);\n"
+    "}\n",
+
+    // 6: kTwoPointRadialTextureVertCoords_Program
+    "uniform " GR_PRECISION " float uParams[6];\n" 
+        // 0 is t^2 term of quadratic 
+        // 1 is one-half the inverse of above
+        // 2 is x offset of the second circle (post tex-matrix)
+        // 3 is the radius of the first circle (post tex-matrix)
+        // 4 is the first circle radius squared
+        // 5 is 1 to use + in the quadratic eq or -1 to use -
+    DECL_MATRIX(viewM)
+    DECL_MATRIX(texM)
+    "attribute vec2 aPosition;\n"
+    "attribute vec4 aColor;\n"
+    "varying vec4 vColor;\n"
+    "varying float vB;\n"           // t coeffecient of quadratic.
+    "varying vec2 t;\n"             // coordinates in canonical space
+    "void main() {\n"
+    "    vec3 pos3 = viewM*vec3(aPosition,1);\n"
+    "    gl_Position = vec4(pos3.xy,0,pos3.z);\n"
+    "    t = vec2(texM * vec3(aPosition,1));\n"
+    "    vColor = aColor;\n"
+    "    vB = 2.0 * (uParams[2] * t.x - uParams[3]);\n"
+    "}\n",
+
+    // 6: kTwoPointRadialTextureVertCoords_Program
+    "uniform " GR_PRECISION " float uParams[6];\n" 
+    DECL_MATRIX(viewM)
+    DECL_MATRIX(texM)
+    "attribute vec2 aPosition;\n"
+    "attribute vec2 aTexture;\n"
+    "attribute vec4 aColor;\n"
+    "varying vec4 vColor;\n"
+    "varying float vB;\n"           // t coeffecient of quadratic.
+    "varying vec2 t;\n"             // coordinates in canonical space
+    "void main() {\n"
+    "    vec3 pos3 = viewM*vec3(aPosition,1);\n"
+    "    gl_Position = vec4(pos3.xy,0,pos3.z);\n"
+    "    t = vec2(texM * vec3(aTexture,1));\n"
+    "    vColor = aColor;\n"
+    "    vB = 2.0 * (uParams[2] * t.x - uParams[3]);\n"
+    "}\n",
+};
+
+static const char* gfshad[] = {
+    // 0: kTextureVertCoords_Program, kTextureTexCoords_Program
+    GR_SHADER_PRECISION
+    "varying vec3 vTexture;\n"
+    "varying vec4 vColor;\n"
+    "uniform sampler2D sTexture;\n"
+    "void main() {\n"
+    "   gl_FragColor = vColor * texture2D(sTexture, vTexture.xy);\n"
+    "}\n",
+
+    // 1: kTextureVertCoordsProj_Program, kTextureTexCoordsProj_Program
+    GR_SHADER_PRECISION
+    "varying vec3 vTexture;\n"
+    "varying vec4 vColor;\n"
+    "uniform sampler2D sTexture;\n"
+    "void main() {\n"
+    // On Brian's PC laptop with Intel Gfx texture2DProj seems to be broken
+    // but it works everywhere else tested.
+#if GR_GLSL_2DPROJ_BROKEN
+    "   gl_FragColor = vColor * texture2D(sTexture, vTexture.xy / vTexture.z);\n"
+#else
+    "   gl_FragColor = vColor * texture2DProj(sTexture, vTexture);\n"
+#endif
+    
+    "}\n",
+
+    // 2: kText_Program
+    GR_SHADER_PRECISION
+    "varying vec2 vTexture;\n"
+#if ATTRIBUTE_TEXT_COLOR
+    "varying vec4 vColor;\n"
+#else
+    "uniform vec4 uColor;\n"
+#endif
+    "uniform sampler2D sTexture;\n"
+    "void main() {\n"
+#if ATTRIBUTE_TEXT_COLOR
+    "   gl_FragColor = vColor * texture2D(sTexture, vTexture).a;\n"
+#else
+    "   gl_FragColor = uColor * texture2D(sTexture, vTexture).a;\n"
+#endif
+    "}\n",
+
+    // 3: kNoTexture_Program
+    GR_SHADER_PRECISION
+    "varying vec4 vColor;\n"
+    "void main() {\n"
+    "   gl_FragColor = vColor;\n"
+    "}\n",
+
+    // 4: kTextureVertCoordsNoColor_Program
+    GR_SHADER_PRECISION
+    "varying vec3 vTexture;\n"
+    "uniform sampler2D sTexture;\n"
+    "void main() {\n"
+    "   gl_FragColor = texture2D(sTexture, vTexture.xy);\n"
+    "}\n",
+
+    // 5: kRadialTextureVertCoords_Program, kRadialTextureTexCoords_Program
+    GR_SHADER_PRECISION
+    "varying vec3 vTexture;\n"
+    "varying vec4 vColor;\n"
+    "uniform sampler2D sTexture;\n"
+    "void main() {\n"
+    "   gl_FragColor = vColor * texture2D(sTexture, vec2(length(vTexture.xy), 0.5));\n"
+    "}\n",
+
+    // 6: kSweepTextureVertCoords_Program, kSweepTextureTexCoords_Program
+    GR_SHADER_PRECISION
+    "varying vec3 vTexture;\n"
+    "varying vec4 vColor;\n"
+    "uniform sampler2D sTexture;\n"
+    "void main() {\n"
+    "   vec2 t = vec2(atan(-vTexture.y, -vTexture.x)*0.1591549430918 + 0.5,\n"
+    "                 0.5);\n"
+    "   gl_FragColor = vColor * texture2D(sTexture, t);\n"
+    "}\n",
+    
+    // 7: kTwoPointRadialTextureVertCoords_Program, kTwoPointRadialTextureTexCoords_Program
+    GR_SHADER_PRECISION
+    "varying vec4 vColor;\n"
+    "varying float vB;\n"             // t coeffecient of quadratic.
+    "varying vec2 t;\n"               // coordinates in canonical radial gradient space
+    "uniform sampler2D sTexture;\n"
+    "uniform float uParams[6];\n" 
+    "void main() {\n"
+        "float c = t.x*t.x + t.y*t.y - uParams[4];\n"
+        "float ac4 = uParams[0] * c * 4.0;\n"
+        "float root = sqrt(abs(vB * vB - ac4));\n"
+        "float t = (-vB + uParams[5] * root) * uParams[1];\n"
+        "gl_FragColor = vColor * texture2D(sTexture, vec2(t,0.5))\n;"
+    "}\n",
+};
+
+// determines which frag/vert shaders are used for each program in Programs enum
+
+static const struct {
+    int fVShaderIdx;
+    int fFShaderIdx;
+    bool fHasTexMatrix;
+    bool fHasTexCoords;
+    bool fTwoPointRadial;
+    GrGpuGLShaders::ColorType fColorType;    
+} gProgramLoadData[] = {
+    // kTextureVertCoords_Program
+    {0, 0, true,  false, false, GrGpuGLShaders::kAttrib_ColorType }, 
+    // kTextureVertCoordsProj_Program
+    {0, 1, true,  false, false, GrGpuGLShaders::kAttrib_ColorType }, 
+    // kTextureTexCoords_Program
+    {1, 0, true,  true,  false, GrGpuGLShaders::kAttrib_ColorType }, 
+    // kTextureTexCoordsProj_Program
+    {1, 1, true,  true,  false, GrGpuGLShaders::kAttrib_ColorType }, 
+    // kTextureVertCoordsNoColor_Program
+    {4, 4, true,  false, false, GrGpuGLShaders::kNone_ColorType },
+    // kTextureTexCoordsNoColor_Program
+    {5, 4, true,  false, false, GrGpuGLShaders::kNone_ColorType },
+    // kText_Program
+#if ATTRIBUTE_TEXT_COLOR
+    {2, 2, false, true,  false, GrGpuGLShaders::kAttrib_ColorType },
+#else
+    {2, 2, false, true,  false, GrGpuGLShaders::kUniform_ColorType },
+#endif
+    // kRadialTextureVertCoords_Program
+    {0, 5, true,  false, false, GrGpuGLShaders::kAttrib_ColorType }, 
+    // kRadialTextureTexCoords_Program
+    {1, 5, true,  true,  false, GrGpuGLShaders::kAttrib_ColorType },
+    // kSweepTextureVertCoords_Program
+    {0, 6, true,  false, false, GrGpuGLShaders::kAttrib_ColorType }, 
+    // kSweepTextureTexCoords_Program
+    {1, 6, true,  true,  false, GrGpuGLShaders::kAttrib_ColorType },
+    // kTwoPointRadialTextureVertCoords_Program
+    {6, 7, true,  false, true,  GrGpuGLShaders::kAttrib_ColorType },
+    // kTwoPointRadialTextureTexCoords_Program
+    {7, 7, true,  true,  true,  GrGpuGLShaders::kAttrib_ColorType },
+    // kNoTexture_Program
+    {3, 3, false, false, false, GrGpuGLShaders::kAttrib_ColorType },
+};
+
+#define GR_GL_POS_ATTR_LOCATION 0
+#define GR_GL_TEX_ATTR_LOCATION 1
+#define GR_GL_COL_ATTR_LOCATION 2
+#if ATTRIBUTE_MATRIX
+    #define GR_GL_MAT_ATTR_LOCATION 3
+    #define GR_GL_TEXMAT_ATTR_LOCATION 6
+#endif
+
+GLuint GrGpuGLShaders::loadShader(GLenum type, const char* src) {
+    GLuint shader = GR_GL(CreateShader(type));
+    if (0 == shader) {
+        return 0;
+    }
+
+    GLint compiled;
+    GR_GL(ShaderSource(shader, 1, &src, NULL));
+    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()));
+            GrPrintf((char*)log.get());
+        }
+        GrAssert(!"Shader compilation failed!");
+        GR_GL(DeleteShader(shader));
+        return 0;
+    }
+    return shader;
+}
+
+bool GrGpuGLShaders::createProgram(GLuint vshader, GLuint fshader,
+                                   bool hasTexMatrix,
+                                   bool hasTexCoords,
+                                   GrGpuGLShaders::ColorType colorType,
+                                   bool twoPointRadial,
+                                   ProgramData* program) {
+    program->fProgramID = GR_GL(CreateProgram());
+    program->fVShaderID = vshader;
+    program->fFShaderID = fshader;
+
+    GrAssert(0 != program->fProgramID);
+    
+    GR_GL(AttachShader(program->fProgramID, vshader));
+    GR_GL(AttachShader(program->fProgramID, fshader));
+
+    GR_GL(BindAttribLocation(program->fProgramID, 
+                             GR_GL_POS_ATTR_LOCATION, 
+                             "aPosition"));
+    if (hasTexCoords) {
+        GR_GL(BindAttribLocation(program->fProgramID, 
+                                 GR_GL_TEX_ATTR_LOCATION, 
+                                 "aTexture"));
+    }
+#if ATTRIBUTE_MATRIX
+    if (hasTexMatrix) {
+        GR_GL(BindAttribLocation(program->fProgramID, 
+                                 GR_GL_TEXMAT_ATTR_LOCATION, 
+                                 "texM"));
+        // set to something arbitrary to signal to flush that program
+        // uses the texture matrix.
+        program->fTexMatrixLocation = 1000;
+    }
+#endif
+    if (colorType == kAttrib_ColorType) {
+        GR_GL(BindAttribLocation(program->fProgramID, 
+                                 GR_GL_COL_ATTR_LOCATION, 
+                                 "aColor"));
+    }
+#if ATTRIBUTE_MATRIX
+    GR_GL(BindAttribLocation(program->fProgramID,
+                             GR_GL_MAT_ATTR_LOCATION, 
+                             "viewM"));
+#endif
+
+    GR_GL(LinkProgram(program->fProgramID));
+
+    GLint linked;
+    GR_GL(GetProgramiv(program->fProgramID, GL_LINK_STATUS, &linked));
+    if (!linked) {
+        GLint infoLen;
+        GR_GL(GetProgramiv(program->fProgramID, GL_INFO_LOG_LENGTH, &infoLen));
+        GrAutoMalloc log(sizeof(char)*(infoLen+1));  // outside if for debugger
+        if (infoLen > 0) {            
+            GR_GL(GetProgramInfoLog(program->fProgramID,
+                                    infoLen+1, 
+                                    NULL, 
+                                    (char*)log.get()));
+            GrPrintf((char*)log.get());
+        }
+        GrAssert(!"Error linking program");
+        GR_GL(DeleteProgram(program->fProgramID));
+        program->fProgramID = 0;
+        return false;
+    }
+    program->fColorType = colorType;
+
+#if !ATTRIBUTE_MATRIX
+    program->fMatrixLocation =
+        GR_GL(GetUniformLocation(program->fProgramID, "viewM"));
+    program->fTexMatrixLocation = 
+        GR_GL(GetUniformLocation(program->fProgramID, "texM"));
+#endif
+    program->fColorLocation = 
+        GR_GL(GetUniformLocation(program->fProgramID, "uColor"));
+    program->fTwoPointParamsLocation = 
+        GR_GL(GetUniformLocation(program->fProgramID, "uParams"));
+    
+    GLint samplerLocation = 
+                GR_GL(GetUniformLocation(program->fProgramID, "sTexture"));
+
+#if !ATTRIBUTE_MATRIX   
+    if (-1 == program->fMatrixLocation)    {
+        GrAssert(!"Cannot find matrix uniform in program");
+        GR_GL(DeleteProgram(program->fProgramID));
+        program->fProgramID = 0;
+        return false;
+    }
+#endif
+
+    bool hasTexture = hasTexCoords || hasTexMatrix;
+
+    if (-1 == samplerLocation && hasTexture) {
+        GrAssert(!"Expected to find texture sampler");
+        GR_GL(DeleteProgram(program->fProgramID));
+        program->fProgramID = 0;
+        return false;
+    } else if (-1 != samplerLocation && !hasTexture) {
+        GrAssert(!"unexpectedly found texture sampler");
+    }
+#if !ATTRIBUTE_MATRIX
+    if (-1 == program->fTexMatrixLocation && hasTexMatrix) {
+        GrAssert(!"Expected to find texture matrix");
+        GR_GL(DeleteProgram(program->fProgramID));
+        program->fProgramID = 0;
+        return false;
+    } else if (-1 != program->fTexMatrixLocation && !hasTexMatrix) {
+        GrAssert(!"unexpectedly found texture matrix");
+    }
+#endif
+
+    if (-1 == program->fColorLocation && 
+        (kUniform_ColorType == colorType)) {
+        GR_GL(DeleteProgram(program->fProgramID));
+        program->fProgramID = 0;
+        return false;
+    } else if (-1 != program->fColorLocation && 
+        (kUniform_ColorType != colorType)) {
+        GrAssert(!"Unexpectedly found color uniform");
+    }
+    
+    if (twoPointRadial) {
+        if (-1 == program->fTwoPointParamsLocation) {
+            GrAssert(!"Didn't find expected uniform for 2pt radial gradient");
+            GR_GL(DeleteProgram(program->fProgramID));
+            program->fProgramID = 0;
+            return false;
+        }
+    } else {
+        GrAssert(-1 == program->fTwoPointParamsLocation);
+    }
+    
+    GR_GL(UseProgram(program->fProgramID));
+    if (-1 != samplerLocation) {
+        GR_GL(Uniform1i(samplerLocation, 0));
+    }
+    
+    return true;
+}
+
+GrGpuGLShaders::GrGpuGLShaders() {
+    
+    resetContextHelper();
+    
+    GLuint vshadIDs[GR_ARRAY_COUNT(gvshad)];
+    for (size_t s = 0; s < GR_ARRAY_COUNT(gvshad); ++s) {
+        vshadIDs[s] = loadShader(GL_VERTEX_SHADER, gvshad[s]);
+    }
+
+    GLuint fshadIDs[GR_ARRAY_COUNT(gfshad)];
+    for (size_t s = 0; s < GR_ARRAY_COUNT(gfshad); ++s) {
+        fshadIDs[s] = loadShader(GL_FRAGMENT_SHADER, gfshad[s]);
+    }
+
+    GR_STATIC_ASSERT(kProgramCount == GR_ARRAY_COUNT(gProgramLoadData));
+    for (int p = 0; p < kProgramCount; ++p) {
+        GR_DEBUGCODE(bool result = )
+        createProgram(vshadIDs[gProgramLoadData[p].fVShaderIdx], 
+                      fshadIDs[gProgramLoadData[p].fFShaderIdx],
+                      gProgramLoadData[p].fHasTexMatrix,
+                      gProgramLoadData[p].fHasTexCoords,
+                      gProgramLoadData[p].fColorType,
+                      gProgramLoadData[p].fTwoPointRadial,
+                      &fPrograms[p]);
+        GR_DEBUGASSERT(result);
+        
+        for (int m = 0; m < kMatrixModeCount; ++m) {
+            fPrograms[p].fMatrixModeCache[m].setScale(GR_ScalarMax, 
+                                                      GR_ScalarMax); // illegal
+        };
+        fPrograms[p].fColor = GrColor_ILLEGAL;
+        fPrograms[p].fTextureOrientation = (GrGLTexture::Orientation)-1; // illegal
+        
+        // these aren't strictly invalid, just really unlikely.
+        fPrograms[p].fRadial2CenterX1 = GR_ScalarMin;
+        fPrograms[p].fRadial2Radius0  = GR_ScalarMin;
+        fPrograms[p].fRadial2PosRoot  = true; // arbitrary
+    }
+}
+
+GrGpuGLShaders::~GrGpuGLShaders() {
+    // shaders get deleted once for each program that uses them, do we care? 
+    // probably not
+    for (int i = 0; i < kProgramCount; ++i) {
+        GR_GL(DeleteProgram(fPrograms[i].fProgramID));
+        GR_GL(DeleteShader(fPrograms[i].fVShaderID));
+        GR_GL(DeleteShader(fPrograms[i].fFShaderID));
+    }
+}
+
+void GrGpuGLShaders::resetContext() {
+    INHERITED::resetContext();
+    resetContextHelper();
+}
+
+void GrGpuGLShaders::resetContextHelper() {
+    fHWProgram = (Programs)-1;
+    fTextureOrientation = (GrGLTexture::Orientation)-1; // illegal
+
+    fHWGeometryState.fVertexLayout = 0;
+    fHWGeometryState.fPositionPtr  = (void*) ~0;
+    GR_GL(DisableVertexAttribArray(GR_GL_COL_ATTR_LOCATION));
+    GR_GL(DisableVertexAttribArray(GR_GL_TEX_ATTR_LOCATION));
+    GR_GL(EnableVertexAttribArray(GR_GL_POS_ATTR_LOCATION));
+}
+
+
+void GrGpuGLShaders::flushMatrix(GLint location) {
+    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(GR_GL_MAT_ATTR_LOCATION+0, mt+0);
+    glVertexAttrib4fv(GR_GL_MAT_ATTR_LOCATION+1, mt+3);
+    glVertexAttrib4fv(GR_GL_MAT_ATTR_LOCATION+2, mt+6);
+#else 
+    GR_GL(UniformMatrix3fv(location,1,false,mt));
+#endif
+}
+
+void GrGpuGLShaders::flushTexMatrix(GLint location, 
+                                    GrGLTexture::Orientation 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(GR_GL_TEXMAT_ATTR_LOCATION+0, mt+0);
+    glVertexAttrib4fv(GR_GL_TEXMAT_ATTR_LOCATION+1, mt+3);
+    glVertexAttrib4fv(GR_GL_TEXMAT_ATTR_LOCATION+2, mt+6);
+#else 
+    GR_GL(UniformMatrix3fv(location,1,false,mt));
+#endif 
+}
+
+void GrGpuGLShaders::flushTwoPointRadial(GLint paramsLocation,
+                                         const GrSamplerState& state) {
+    GrScalar centerX1 = state.getRadial2CenterX1();
+    GrScalar radius0 = state.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)),
+        state.isRadial2PosRoot() ? 1.f : -1.f
+    };
+    GR_GL(Uniform1fv(paramsLocation, 6, unis));
+}
+
+void GrGpuGLShaders::flushProgram(PrimitiveType type) {
+
+    Programs nextProgram = kNoTexture_Program;
+
+    if (!VertexHasTexCoords(fGeometrySrc.fVertexLayout)) {
+        goto HAVE_NEXT_PROGRAM;
+    }
+
+    GrAssert(fCurrDrawState.fTexture);
+
+    switch (fCurrDrawState.fSamplerState.getSampleMode()) {
+        case GrSamplerState::kRadial_SampleMode:
+            GrAssert(!fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode].hasPerspective());
+            if (fGeometrySrc.fVertexLayout & kPositionAsTexCoord_VertexLayoutBit) {
+                nextProgram = kRadialTextureVertCoords_Program;
+            } else {
+                nextProgram = kRadialTextureTexCoords_Program;
+            }
+            break;
+        case GrSamplerState::kSweep_SampleMode:
+            GrAssert(!fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode].hasPerspective());
+            if (fGeometrySrc.fVertexLayout & kPositionAsTexCoord_VertexLayoutBit) {
+                nextProgram = kSweepTextureVertCoords_Program;
+            } else {
+                nextProgram = kSweepTextureTexCoords_Program;
+            }
+            break;
+        case GrSamplerState::kRadial2_SampleMode:
+            GrAssert(!fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode].hasPerspective());
+            if (fGeometrySrc.fVertexLayout & kPositionAsTexCoord_VertexLayoutBit) {
+                nextProgram = kTwoPointRadialTextureVertCoords_Program;
+            } else {
+                nextProgram = kTwoPointRadialTextureTexCoords_Program;
+            }
+            break;
+        case GrSamplerState::kAlphaMod_SampleMode:
+            GrAssert(((GrGLTexture*)fCurrDrawState.fTexture)->orientation() == 
+                     GrGLTexture::kTopDown_Orientation);
+            (((GrGLTexture*)fCurrDrawState.fTexture)->uploadFormat() == GL_ALPHA);
+            
+            nextProgram = kText_Program;
+            break;
+        case GrSamplerState::kNormal_SampleMode: {
+            GR_DEBUGCODE(GrGLTexture* tex = (GrGLTexture*)fCurrDrawState.fTexture;)
+            GrAssert(tex);
+
+            bool persp = fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode].hasPerspective();
+
+            if (fGeometrySrc.fVertexLayout & kPositionAsTexCoord_VertexLayoutBit) {
+                nextProgram = persp ? kTextureVertCoordsProj_Program : 
+                                      kTextureVertCoords_Program;
+            } else {
+                nextProgram = persp ? kTextureTexCoordsProj_Program : 
+                                      kTextureTexCoords_Program;
+            }
+            // check for case when frag shader can skip the color modulation
+            if (!persp && !(fGeometrySrc.fVertexLayout
+                            & kColor_VertexLayoutBit) &&
+                0xffffffff == fCurrDrawState.fColor) {
+                switch (nextProgram) {
+                case kTextureVertCoords_Program:
+                    nextProgram = kTextureVertCoordsNoColor_Program;
+                    break;
+                case kTextureTexCoords_Program:
+                    nextProgram = kTextureTexCoordsNoColor_Program;
+                    break;
+                default:
+                    GrAssert("Unexpected");
+                    break;
+                }
+            }
+        } break;
+        default:
+            GrAssert(!"Unknown samplemode");
+            break;
+    }
+
+HAVE_NEXT_PROGRAM:
+    if (fHWProgram != nextProgram) {
+        GR_GL(UseProgram(fPrograms[nextProgram].fProgramID));
+        fHWProgram = nextProgram;
+#if GR_COLLECT_STATS
+        ++fStats.fProgChngCnt;
+#endif
+    }
+}
+
+bool GrGpuGLShaders::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
+        for (int p = 0; p < kProgramCount; ++p) {
+            // set to illegal matrix
+            fPrograms[p].fMatrixModeCache[kModelView_MatrixMode].setScale(GR_ScalarMax, 
+                                                                          GR_ScalarMax); 
+        }
+#endif
+        fRenderTargetChanged = false;
+    }
+    
+    flushProgram(type);
+
+    if (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit) {
+        // invalidate the immediate mode color
+        fHWDrawState.fColor = GrColor_ILLEGAL;    
+    } else {
+        // if we don't have per-vert colors either set the color attr
+        // or color uniform (depending on which program).
+        if (-1 != fPrograms[fHWProgram].fColorLocation) {
+            GrAssert(kUniform_ColorType == fPrograms[fHWProgram].fColorType);
+            if (fPrograms[fHWProgram].fColor != fCurrDrawState.fColor) {
+                float c[] = {
+                    GrColorUnpackR(fCurrDrawState.fColor) / 255.f,
+                    GrColorUnpackG(fCurrDrawState.fColor) / 255.f,
+                    GrColorUnpackB(fCurrDrawState.fColor) / 255.f,
+                    GrColorUnpackA(fCurrDrawState.fColor) / 255.f
+                };
+                GR_GL(Uniform4fv(fPrograms[fHWProgram].fColorLocation, 1, c));
+                fPrograms[fHWProgram].fColor = fCurrDrawState.fColor;
+            }
+        } else if (kAttrib_ColorType == fPrograms[fHWProgram].fColorType && 
+                   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(GR_GL_COL_ATTR_LOCATION, c));
+            fHWDrawState.fColor = fCurrDrawState.fColor;
+        }
+    }
+
+#if ATTRIBUTE_MATRIX
+    GrMatrix* currentMats = fHWDrawState.fMatrixModeCache;
+    GrGLTexture::Orientation& orientation = fTextureOrientation; 
+#else
+    GrMatrix* currentMats = fPrograms[fHWProgram].fMatrixModeCache;
+    GrGLTexture::Orientation& orientation = 
+                                    fPrograms[fHWProgram].fTextureOrientation;
+#endif
+
+    if (currentMats[kModelView_MatrixMode] !=
+          fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode]) {
+        flushMatrix(fPrograms[fHWProgram].fMatrixLocation);
+        currentMats[kModelView_MatrixMode] = 
+            fCurrDrawState.fMatrixModeCache[kModelView_MatrixMode];
+    }
+
+    GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTexture;
+    if (NULL != texture) {
+        if (-1 != fPrograms[fHWProgram].fTexMatrixLocation &&
+            (currentMats[kTexture_MatrixMode] !=
+             fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode] ||
+             orientation != texture->orientation())) {
+            flushTexMatrix(fPrograms[fHWProgram].fTexMatrixLocation,
+                           texture->orientation());
+            currentMats[kTexture_MatrixMode] = 
+                        fCurrDrawState.fMatrixModeCache[kTexture_MatrixMode];
+            orientation = texture->orientation();
+        }
+    }
+
+    const GrSamplerState& sampler = fCurrDrawState.fSamplerState;
+    if (-1 != fPrograms[fHWProgram].fTwoPointParamsLocation &&
+        (fPrograms[fHWProgram].fRadial2CenterX1 != sampler.getRadial2CenterX1() ||
+         fPrograms[fHWProgram].fRadial2Radius0  != sampler.getRadial2Radius0()  ||
+         fPrograms[fHWProgram].fRadial2PosRoot  != sampler.isRadial2PosRoot())) {
+            
+        flushTwoPointRadial(fPrograms[fHWProgram].fTwoPointParamsLocation,
+                            sampler);
+        fPrograms[fHWProgram].fRadial2CenterX1 = sampler.getRadial2CenterX1();
+        fPrograms[fHWProgram].fRadial2Radius0 = sampler.getRadial2Radius0();
+        fPrograms[fHWProgram].fRadial2PosRoot = sampler.isRadial2PosRoot();
+    }
+    
+    return true;
+}
+
+void GrGpuGLShaders::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(GR_GL_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(GR_GL_TEX_ATTR_LOCATION));
+        }
+        if (posChange || newTexCoordOffset != oldTexCoordOffset) {
+            GR_GL(VertexAttribPointer(GR_GL_TEX_ATTR_LOCATION, 2, scalarType,
+                                      texCoordNorm, newStride, texCoordPtr));
+        }
+    } else if (oldTexCoordOffset > 0) {
+        GR_GL(DisableVertexAttribArray(GR_GL_TEX_ATTR_LOCATION));
+    }
+    
+    if (newColorOffset > 0) {
+        GLvoid* colorPtr = (int8_t*)posPtr + newColorOffset;
+        if (oldColorOffset <= 0) {
+            GR_GL(EnableVertexAttribArray(GR_GL_COL_ATTR_LOCATION));
+        }
+        if (posChange || newColorOffset != oldColorOffset) {
+            GR_GL(VertexAttribPointer(GR_GL_COL_ATTR_LOCATION, 4, 
+                                      GL_UNSIGNED_BYTE,
+                                      true, newStride, colorPtr));
+        }
+    } else if (oldColorOffset > 0) {
+        GR_GL(DisableVertexAttribArray(GR_GL_COL_ATTR_LOCATION));
+    }
+    
+    fHWGeometryState.fVertexLayout = fGeometrySrc.fVertexLayout;
+}
+#endif