Add GL uniform manager
Review URL: http://codereview.appspot.com/6423066/



git-svn-id: http://skia.googlecode.com/svn/trunk@4758 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/gpu.gyp b/gyp/gpu.gyp
index cff89d3..6792db5 100644
--- a/gyp/gpu.gyp
+++ b/gyp/gpu.gyp
@@ -332,6 +332,9 @@
         '../src/gpu/gl/GrGLTexture.h',
         '../src/gpu/gl/GrGLUtil.cpp',
         '../src/gpu/gl/GrGLUtil.h',
+        '../src/gpu/gl/GrGLUniformManager.cpp',
+        '../src/gpu/gl/GrGLUniformManager.h',
+        '../src/gpu/gl/GrGLUniformHandle.h',
         '../src/gpu/gl/GrGLVertexBuffer.cpp',
         '../src/gpu/gl/GrGLVertexBuffer.h',
         '../src/gpu/gl/GrGpuGL.cpp',
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 99a51d4..21a553d 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -12,16 +12,15 @@
 #include "GrProgramStageFactory.h"
 #include "effects/GrSingleTextureEffect.h"
 #include "gl/GrGLProgramStage.h"
-#include "gl/GrGLSL.h"
 #include "gl/GrGLTexture.h"
 #include "GrCustomStage.h"
 
 class GrGLDiffuseLightingEffect;
 class GrGLSpecularLightingEffect;
 
-// For brevity, and these definitions are likely to move to a different class soon.
-typedef GrGLShaderBuilder::UniformHandle UniformHandle;
-static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
+// For brevity
+typedef GrGLUniformManager::UniformHandle UniformHandle;
+static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
 
 namespace {
 
@@ -30,19 +29,21 @@
 const SkScalar gOneHalf = SkFloatToScalar(0.5f);
 const SkScalar gOneQuarter = SkFloatToScalar(0.25f);
 
-void setUniformPoint3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
-    float x = SkScalarToFloat(point.fX);
-    float y = SkScalarToFloat(point.fY);
-    float z = SkScalarToFloat(point.fZ);
-    GR_GL_CALL(gl, Uniform3f(location, x, y, z));
+void setUniformPoint3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
+    GR_STATIC_ASSERT(offsetof(SkPoint3, fX) + sizeof(float) == offsetof(SkPoint3, fY));
+    GR_STATIC_ASSERT(offsetof(SkPoint3, fY) + sizeof(float) == offsetof(SkPoint3, fZ));
+    uman.set3fv(uni, 0, 1, &point.fX);
 }
 
-void setUniformNormal3(const GrGLInterface* gl, GrGLint location, const SkPoint3& point) {
-    setUniformPoint3(gl, location, SkPoint3(point.fX, -point.fY, point.fZ));
+void setUniformNormal3(const GrGLUniformManager& uman, UniformHandle uni, const SkPoint3& point) {
+    setUniformPoint3(uman, uni, SkPoint3(point.fX, -point.fY, point.fZ));
 }
 
-void setUniformPoint3FlipY(const GrGLInterface* gl, GrGLint location, const SkPoint3& point, int height) {
-    setUniformPoint3(gl, location, SkPoint3(point.fX, height-point.fY, point.fZ));
+void setUniformPoint3FlipY(const GrGLUniformManager& uman,
+                           UniformHandle uni,
+                           const SkPoint3& point,
+                           int height) {
+    setUniformPoint3(uman, uni, SkPoint3(point.fX, height-point.fY, point.fZ));
 }
 
 // Shift matrix components to the left, as we advance pixels to the right.
@@ -370,15 +371,13 @@
     virtual void emitLightColor(const GrGLShaderBuilder*,
                                 SkString* out,
                                 const char *surfaceToLight) const;
-    virtual void initUniforms(const GrGLShaderBuilder*, const GrGLInterface* gl, int programID);
-    virtual void setData(const GrGLInterface*, const GrRenderTarget* rt, const SkLight* light) const;
+    virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const;
 
 private:
     typedef SkRefCnt INHERITED;
 
 protected:
     UniformHandle fColorUni;
-    int fColorLocation;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -387,18 +386,13 @@
 public:
     virtual ~GrGLDistantLight() {}
     virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
-    virtual void initUniforms(const GrGLShaderBuilder*,
-                              const GrGLInterface* gl,
-                              int programID) SK_OVERRIDE;
-    virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
     virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
                                     SkString* out,
                                     const char* z) const SK_OVERRIDE;
-
 private:
     typedef GrGLLight INHERITED;
     UniformHandle fDirectionUni;
-    int fDirectionLocation;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -407,20 +401,15 @@
 public:
     virtual ~GrGLPointLight() {}
     virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
-    virtual void initUniforms(const GrGLShaderBuilder*,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE;
-    virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
     virtual void emitVS(SkString* out) const SK_OVERRIDE;
     virtual void emitSurfaceToLight(const GrGLShaderBuilder*,
                                     SkString* out,
                                     const char* z) const SK_OVERRIDE;
-
 private:
     typedef GrGLLight INHERITED;
     SkPoint3 fLocation;
     UniformHandle fLocationUni;
-    int fLocationLocation;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -429,10 +418,7 @@
 public:
     virtual ~GrGLSpotLight() {}
     virtual void setupVariables(GrGLShaderBuilder* builder, int stage) SK_OVERRIDE;
-    virtual void initUniforms(const GrGLShaderBuilder* builder,
-                              const GrGLInterface* gl,
-                              int programID) SK_OVERRIDE;
-    virtual void setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
+    virtual void setData(const GrGLUniformManager&, const GrRenderTarget* rt, const SkLight* light) const SK_OVERRIDE;
     virtual void emitVS(SkString* out) const SK_OVERRIDE;
     virtual void emitFuncs(const GrGLShaderBuilder* builder, SkString* out) const;
     virtual void emitSurfaceToLight(const GrGLShaderBuilder* builder,
@@ -446,17 +432,11 @@
     typedef GrGLLight INHERITED;
 
     UniformHandle   fLocationUni;
-    int             fLocationLocation;
     UniformHandle   fExponentUni;
-    int             fExponentLocation;
     UniformHandle   fCosOuterConeAngleUni;
-    int             fCosOuterConeAngleLocation;
     UniformHandle   fCosInnerConeAngleUni;
-    int             fCosInnerConeAngleLocation;
     UniformHandle   fConeScaleUni;
-    int             fConeScaleLocation;
     UniformHandle   fSUni;
-    int             fSLocation;
 };
 
 };
@@ -903,10 +883,7 @@
 
     static inline StageKey GenKey(const GrCustomStage& s);
 
-    virtual void initUniforms(const GrGLShaderBuilder* builder,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE;
-    virtual void setData(const GrGLInterface*, 
+    virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
                          int stageNum) SK_OVERRIDE;
@@ -915,9 +892,7 @@
     typedef GrGLProgramStage INHERITED;
 
     UniformHandle   fImageIncrementUni;
-    GrGLint         fImageIncrementLocation;
     UniformHandle   fSurfaceScaleUni;
-    GrGLint         fSurfaceScaleLocation;
     GrGLLight*      fLight;
 };
 
@@ -930,10 +905,7 @@
     virtual void setupVariables(GrGLShaderBuilder* builder,
                                 int stage) SK_OVERRIDE;
     virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
-    virtual void initUniforms(const GrGLShaderBuilder*,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE;
-    virtual void setData(const GrGLInterface*, 
+    virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
                          int stageNum) SK_OVERRIDE;
@@ -942,7 +914,6 @@
     typedef GrGLLightingEffect INHERITED;
 
     UniformHandle   fKDUni;
-    GrGLint         fKDLocation;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -954,10 +925,7 @@
     virtual void setupVariables(GrGLShaderBuilder* builder,
                                 int stage) SK_OVERRIDE;
     virtual void emitLightFunc(const GrGLShaderBuilder*, SkString* funcs) SK_OVERRIDE;
-    virtual void initUniforms(const GrGLShaderBuilder*,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE;
-    virtual void setData(const GrGLInterface*, 
+    virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
                          int stageNum) SK_OVERRIDE;
@@ -966,9 +934,7 @@
     typedef GrGLLightingEffect INHERITED;
 
     UniformHandle   fKSUni;
-    GrGLint         fKSLocation;
     UniformHandle   fShininessUni;
-    GrGLint         fShininessLocation;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1015,9 +981,7 @@
                                        const GrCustomStage& stage)
     : GrGLProgramStage(factory)
     , fImageIncrementUni(kInvalidUniformHandle)
-    , fImageIncrementLocation(0)
-    , fSurfaceScaleUni(kInvalidUniformHandle)
-    , fSurfaceScaleLocation(0) {
+    , fSurfaceScaleUni(kInvalidUniformHandle) {
     const GrLightingEffect& m = static_cast<const GrLightingEffect&>(stage);
     fLight = m.light()->createGLLight();
 }
@@ -1041,17 +1005,6 @@
     fLight->emitVS(&builder->fVSCode);
 }
 
-void GrGLLightingEffect::initUniforms(const GrGLShaderBuilder* builder,
-                                      const GrGLInterface* gl,
-                                      int programID) {
-    const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
-    const char* surfScale = builder->getUniformCStr(fSurfaceScaleUni);
-
-    GR_GL_CALL_RET(gl, fSurfaceScaleLocation, GetUniformLocation(programID, surfScale));
-    GR_GL_CALL_RET(gl, fImageIncrementLocation, GetUniformLocation(programID, imgInc));
-    fLight->initUniforms(builder, gl, programID);
-}
-
 void GrGLLightingEffect::emitFS(GrGLShaderBuilder* builder,
                                 const char* outputColor,
                                 const char* inputColor,
@@ -1103,7 +1056,7 @@
     return static_cast<const GrLightingEffect&>(s).light()->type();
 }
 
-void GrGLLightingEffect::setData(const GrGLInterface* gl,
+void GrGLLightingEffect::setData(const GrGLUniformManager& uman,
                                  const GrCustomStage& data,
                                  const GrRenderTarget* rt,
                                  int stageNum) {
@@ -1111,9 +1064,9 @@
         static_cast<const GrLightingEffect&>(data);
     GrGLTexture* texture = static_cast<GrGLTexture*>(data.texture(0));
     float ySign = texture->orientation() == GrGLTexture::kTopDown_Orientation ? -1.0f : 1.0f;
-    GR_GL_CALL(gl, Uniform2f(fImageIncrementLocation, 1.0f / texture->width(), ySign / texture->height()));
-    GR_GL_CALL(gl, Uniform1f(fSurfaceScaleLocation, effect.surfaceScale()));
-    fLight->setData(gl, rt, effect.light());
+    uman.set2f(fImageIncrementUni, 1.0f / texture->width(), ySign / texture->height());
+    uman.set1f(fSurfaceScaleUni, effect.surfaceScale());
+    fLight->setData(uman, rt, effect.light());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1123,8 +1076,7 @@
 GrGLDiffuseLightingEffect::GrGLDiffuseLightingEffect(const GrProgramStageFactory& factory,
                                             const GrCustomStage& stage)
     : INHERITED(factory, stage)
-    , fKDUni(kInvalidUniformHandle)
-    , fKDLocation(0) {
+    , fKDUni(kInvalidUniformHandle) {
 }
 
 void GrGLDiffuseLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
@@ -1133,14 +1085,6 @@
                                  stage);
 }
 
-void GrGLDiffuseLightingEffect::initUniforms(const GrGLShaderBuilder* builder,
-                                             const GrGLInterface* gl,
-                                             int programID) {
-    INHERITED::initUniforms(builder, gl, programID);
-    const char* kd = builder->getUniformCStr(fKDUni);
-    GR_GL_CALL_RET(gl, fKDLocation, GetUniformLocation(programID, kd));
-}
-
 void GrGLDiffuseLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
     const char* kd = builder->getUniformCStr(fKDUni);
     funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
@@ -1149,14 +1093,14 @@
     funcs->appendf("}\n");
 }
 
-void GrGLDiffuseLightingEffect::setData(const GrGLInterface* gl,
+void GrGLDiffuseLightingEffect::setData(const GrGLUniformManager& uman,
                                         const GrCustomStage& data,
                                         const GrRenderTarget* rt,
                                         int stageNum) {
-    INHERITED::setData(gl, data, rt, stageNum);
+    INHERITED::setData(uman, data, rt, stageNum);
     const GrDiffuseLightingEffect& effect =
         static_cast<const GrDiffuseLightingEffect&>(data);
-    GR_GL_CALL(gl, Uniform1f(fKDLocation, effect.kd()));
+    uman.set1f(fKDUni, effect.kd());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1185,9 +1129,7 @@
                                             const GrCustomStage& stage)
     : GrGLLightingEffect(factory, stage)
     , fKSUni(kInvalidUniformHandle)
-    , fKSLocation(0)
-    , fShininessUni(kInvalidUniformHandle)
-    , fShininessLocation(0) {
+    , fShininessUni(kInvalidUniformHandle) {
 }
 
 void GrGLSpecularLightingEffect::setupVariables(GrGLShaderBuilder* builder, int stage) {
@@ -1198,16 +1140,6 @@
                                         kFloat_GrSLType, "uShininess", stage);
 }
 
-void GrGLSpecularLightingEffect::initUniforms(const GrGLShaderBuilder* builder,
-                                              const GrGLInterface* gl,
-                                              int programID) {
-    INHERITED::initUniforms(builder, gl, programID);
-    const char* ks = builder->getUniformCStr(fKSUni);
-    const char* shininess = builder->getUniformCStr(fShininessUni);
-    GR_GL_CALL_RET(gl, fKSLocation, GetUniformLocation(programID, ks));
-    GR_GL_CALL_RET(gl, fShininessLocation, GetUniformLocation(programID, shininess));
-}
-
 void GrGLSpecularLightingEffect::emitLightFunc(const GrGLShaderBuilder* builder, SkString* funcs) {
     funcs->appendf("vec4 light(vec3 normal, vec3 surfaceToLight, vec3 lightColor) {\n");
     funcs->appendf("\tvec3 halfDir = vec3(normalize(surfaceToLight + vec3(0, 0, 1)));\n");
@@ -1219,15 +1151,14 @@
     funcs->appendf("}\n");
 }
 
-void GrGLSpecularLightingEffect::setData(const GrGLInterface* gl,
+void GrGLSpecularLightingEffect::setData(const GrGLUniformManager& uman,
                                          const GrCustomStage& data,
                                          const GrRenderTarget* rt,
                                          int stageNum) {
-    INHERITED::setData(gl, data, rt, stageNum);
-    const GrSpecularLightingEffect& effect =
-        static_cast<const GrSpecularLightingEffect&>(data);
-    GR_GL_CALL(gl, Uniform1f(fKSLocation, effect.ks()));
-    GR_GL_CALL(gl, Uniform1f(fShininessLocation, effect.shininess()));
+    INHERITED::setData(uman, data, rt, stageNum);
+    const GrSpecularLightingEffect& effect = static_cast<const GrSpecularLightingEffect&>(data);
+    uman.set1f(fKSUni, effect.ks());
+    uman.set1f(fShininessUni, effect.shininess());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1244,15 +1175,10 @@
                                     kVec3f_GrSLType, "uLightColor", stage);
 }
 
-void GrGLLight::initUniforms(const GrGLShaderBuilder* builder,
-                             const GrGLInterface* gl,
-                             int programID) {
-    const char* color = builder->getUniformCStr(fColorUni);
-    GR_GL_CALL_RET(gl, fColorLocation, GetUniformLocation(programID, color));
-}
-
-void GrGLLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
-    setUniformPoint3(gl, fColorLocation, light->color() * SkScalarInvert(SkIntToScalar(255)));
+void GrGLLight::setData(const GrGLUniformManager& uman,
+                        const GrRenderTarget* rt,
+                        const SkLight* light) const {
+    setUniformPoint3(uman, fColorUni, light->color() * SkScalarInvert(SkIntToScalar(255)));
 }
 
 GrGLLight* SkDistantLight::createGLLight() const {
@@ -1267,19 +1193,13 @@
                                         "uLightDirection", stage);
 }
 
-void GrGLDistantLight::initUniforms(const GrGLShaderBuilder* builder,
-                                    const GrGLInterface* gl,
-                                    int programID) {
-    INHERITED::initUniforms(builder, gl, programID);
-    const char* dir = builder->getUniformCStr(fDirectionUni);
-    GR_GL_CALL_RET(gl, fDirectionLocation, GetUniformLocation(programID, dir));
-}
-
-void GrGLDistantLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
-    INHERITED::setData(gl, rt, light);
+void GrGLDistantLight::setData(const GrGLUniformManager& uman,
+                               const GrRenderTarget* rt,
+                               const SkLight* light) const {
+    INHERITED::setData(uman, rt, light);
     SkASSERT(light->type() == SkLight::kDistant_LightType);
     const SkDistantLight* distantLight = static_cast<const SkDistantLight*>(light);
-    setUniformNormal3(gl, fDirectionLocation, distantLight->direction());
+    setUniformNormal3(uman, fDirectionUni, distantLight->direction());
 }
 
 void GrGLDistantLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
@@ -1297,28 +1217,23 @@
                                        "uLightLocation", stage);
 }
 
-void GrGLPointLight::initUniforms(const GrGLShaderBuilder* builder,
-                                  const GrGLInterface* gl,
-                                  int programID) {
-    INHERITED::initUniforms(builder, gl, programID);
-    const char* loc = builder->getUniformCStr(fLocationUni);
-    GR_GL_CALL_RET(gl, fLocationLocation, GetUniformLocation(programID, loc));
-}
-
-void GrGLPointLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
-    INHERITED::setData(gl, rt, light);
+void GrGLPointLight::setData(const GrGLUniformManager& uman,
+                             const GrRenderTarget* rt,
+                             const SkLight* light) const {
+    INHERITED::setData(uman, rt, light);
     SkASSERT(light->type() == SkLight::kPoint_LightType);
     const SkPointLight* pointLight = static_cast<const SkPointLight*>(light);
-    setUniformPoint3FlipY(gl, fLocationLocation, pointLight->location(), rt->height());
+    setUniformPoint3FlipY(uman, fLocationUni, pointLight->location(), rt->height());
 }
 
 void GrGLPointLight::emitVS(SkString* out) const {
 }
 
-void GrGLPointLight::emitSurfaceToLight(const GrGLShaderBuilder* builder, SkString* out, const char* z) const {
+void GrGLPointLight::emitSurfaceToLight(const GrGLShaderBuilder* builder,
+                                        SkString* out,
+                                        const char* z) const {
     const char* loc = builder->getUniformCStr(fLocationUni);
-    out->appendf(
-        "normalize(%s - vec3(gl_FragCoord.xy, %s))", loc, z);
+    out->appendf("normalize(%s - vec3(gl_FragCoord.xy, %s))", loc, z);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1339,32 +1254,18 @@
                               kVec3f_GrSLType, "uS", stage);
 }
 
-void GrGLSpotLight::initUniforms(const GrGLShaderBuilder* builder, const GrGLInterface* gl, int programID) {
-    INHERITED::initUniforms(builder, gl, programID);
-    const char* location = builder->getUniformCStr(fLocationUni);
-    const char* exponent = builder->getUniformCStr(fExponentUni);
-    const char* cosInner = builder->getUniformCStr(fCosInnerConeAngleUni);
-    const char* cosOuter = builder->getUniformCStr(fCosOuterConeAngleUni);
-    const char* coneScale = builder->getUniformCStr(fConeScaleUni);
-    const char* s = builder->getUniformCStr(fSUni);
-    GR_GL_CALL_RET(gl, fLocationLocation, GetUniformLocation(programID, location));
-    GR_GL_CALL_RET(gl, fExponentLocation, GetUniformLocation(programID, exponent));
-    GR_GL_CALL_RET(gl, fCosInnerConeAngleLocation, GetUniformLocation(programID, cosInner));
-    GR_GL_CALL_RET(gl, fCosOuterConeAngleLocation, GetUniformLocation(programID, cosOuter));
-    GR_GL_CALL_RET(gl, fConeScaleLocation, GetUniformLocation(programID, coneScale));
-    GR_GL_CALL_RET(gl, fSLocation, GetUniformLocation(programID, s));
-}
-
-void GrGLSpotLight::setData(const GrGLInterface* gl, const GrRenderTarget* rt, const SkLight* light) const {
-    INHERITED::setData(gl, rt, light);
+void GrGLSpotLight::setData(const GrGLUniformManager& uman,
+                            const GrRenderTarget* rt,
+                            const SkLight* light) const {
+    INHERITED::setData(uman, rt, light);
     SkASSERT(light->type() == SkLight::kSpot_LightType);
     const SkSpotLight* spotLight = static_cast<const SkSpotLight *>(light);
-    setUniformPoint3FlipY(gl, fLocationLocation, spotLight->location(), rt->height());
-    GR_GL_CALL(gl, Uniform1f(fExponentLocation, spotLight->specularExponent()));
-    GR_GL_CALL(gl, Uniform1f(fCosInnerConeAngleLocation, spotLight->cosInnerConeAngle()));
-    GR_GL_CALL(gl, Uniform1f(fCosOuterConeAngleLocation, spotLight->cosOuterConeAngle()));
-    GR_GL_CALL(gl, Uniform1f(fConeScaleLocation, spotLight->coneScale()));
-    setUniformNormal3(gl, fSLocation, spotLight->s());
+    setUniformPoint3FlipY(uman, fLocationUni, spotLight->location(), rt->height());
+    uman.set1f(fExponentUni, spotLight->specularExponent());
+    uman.set1f(fCosInnerConeAngleUni, spotLight->cosInnerConeAngle());
+    uman.set1f(fCosOuterConeAngleUni, spotLight->cosOuterConeAngle());
+    uman.set1f(fConeScaleUni, spotLight->coneScale());
+    setUniformNormal3(uman, fSUni, spotLight->s());
 }
 
 void GrGLSpotLight::emitVS(SkString* out) const {
diff --git a/src/gpu/effects/GrColorTableEffect.cpp b/src/gpu/effects/GrColorTableEffect.cpp
index 8ea0dbf..f047a3e 100644
--- a/src/gpu/effects/GrColorTableEffect.cpp
+++ b/src/gpu/effects/GrColorTableEffect.cpp
@@ -26,11 +26,7 @@
                         const char* inputColor,
                         const char* samplerName) SK_OVERRIDE;
 
-    virtual void initUniforms(const GrGLShaderBuilder*,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE {}
-
-    virtual void setData(const GrGLInterface*,
+    virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
                          int stageNum) SK_OVERRIDE {}
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index a16313e..f01caa3 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -11,9 +11,9 @@
 #include "gl/GrGLTexture.h"
 #include "GrProgramStageFactory.h"
 
-// For brevity, and these definitions are likely to move to a different class soon.
-typedef GrGLShaderBuilder::UniformHandle UniformHandle;
-static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
+// For brevity
+typedef GrGLUniformManager::UniformHandle UniformHandle;
+static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
 
 class GrGLConvolutionEffect : public GrGLProgramStage {
 public:
@@ -29,11 +29,7 @@
                         const char* inputColor,
                         const char* samplerName) SK_OVERRIDE;
 
-    virtual void initUniforms(const GrGLShaderBuilder*,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE;
-
-    virtual void setData(const GrGLInterface*,
+    virtual void setData(const GrGLUniformManager& uman,
                          const GrCustomStage&,
                          const GrRenderTarget*,
                          int stageNum) SK_OVERRIDE;
@@ -45,9 +41,7 @@
 
     int             fRadius;
     UniformHandle   fKernelUni;
-    GrGLint         fKernelLocation;
     UniformHandle   fImageIncrementUni;
-    GrGLint         fImageIncrementLocation;
 
     typedef GrGLProgramStage INHERITED;
 };
@@ -56,9 +50,7 @@
                                              const GrCustomStage& stage)
     : GrGLProgramStage(factory)
     , fKernelUni(kInvalidUniformHandle)
-    , fKernelLocation(0)
-    , fImageIncrementUni(kInvalidUniformHandle)
-    , fImageIncrementLocation(0) {
+    , fImageIncrementUni(kInvalidUniformHandle) {
     const GrConvolutionEffect& c =
         static_cast<const GrConvolutionEffect&>(stage);
     fRadius = c.radius();
@@ -71,9 +63,6 @@
                                              kVec2f_GrSLType, "uImageIncrement", stage);
     fKernelUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                      kFloat_GrSLType, "uKernel", stage, this->width());
-
-    fImageIncrementLocation = kUseUniform;
-    fKernelLocation = kUseUniform;
 }
 
 void GrGLConvolutionEffect::emitVS(GrGLShaderBuilder* builder,
@@ -114,16 +103,7 @@
     }
 }
 
-void GrGLConvolutionEffect::initUniforms(const GrGLShaderBuilder* builder,
-                                         const GrGLInterface* gl,
-                                         int programID) {
-    const char* kernel = builder->getUniformCStr(fKernelUni);
-    const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
-    GR_GL_CALL_RET(gl, fImageIncrementLocation, GetUniformLocation(programID, imgInc));
-    GR_GL_CALL_RET(gl, fKernelLocation, GetUniformLocation(programID, kernel));
-}
-
-void GrGLConvolutionEffect::setData(const GrGLInterface* gl,
+void GrGLConvolutionEffect::setData(const GrGLUniformManager& uman,
                                     const GrCustomStage& data,
                                     const GrRenderTarget*,
                                     int stageNum) {
@@ -143,9 +123,8 @@
         default:
             GrCrash("Unknown filter direction.");
     }
-    GR_GL_CALL(gl, Uniform2fv(fImageIncrementLocation, 1, imageIncrement));
-
-    GR_GL_CALL(gl, Uniform1fv(fKernelLocation, this->width(), conv.kernel()));
+    uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
+    uman.set1fv(fKernelUni, 0, this->width(), conv.kernel());
 }
 
 GrGLProgramStage::StageKey GrGLConvolutionEffect::GenKey(
diff --git a/src/gpu/effects/GrGradientEffects.cpp b/src/gpu/effects/GrGradientEffects.cpp
index 34bff09..3769e21 100644
--- a/src/gpu/effects/GrGradientEffects.cpp
+++ b/src/gpu/effects/GrGradientEffects.cpp
@@ -202,9 +202,9 @@
 
 /////////////////////////////////////////////////////////////////////
 
-// For brevity, and these definitions are likely to move to a different class soon.
-typedef GrGLShaderBuilder::UniformHandle UniformHandle;
-static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
+// For brevity
+typedef GrGLUniformManager::UniformHandle UniformHandle;
+static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
 
 class GrGLRadial2Gradient : public GrGLGradientStage {
 
@@ -222,10 +222,7 @@
                         const char* outputColor,
                         const char* inputColor,
                         const char* samplerName) SK_OVERRIDE;
-    virtual void initUniforms(const GrGLShaderBuilder* builder,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE;
-    virtual void setData(const GrGLInterface*,
+    virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
                          int stageNum) SK_OVERRIDE;
@@ -237,9 +234,7 @@
 protected:
 
     UniformHandle   fVSParamUni;
-    GrGLint         fVSParamLocation;
     UniformHandle   fFSParamUni;
-    GrGLint         fFSParamLocation;
 
     const char* fVSVaryingName;
     const char* fFSVaryingName;
@@ -287,9 +282,6 @@
     fFSParamUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                        kFloat_GrSLType, "uRadial2FSParams", stage, 6);
 
-    fVSParamLocation = GrGLProgramStage::kUseUniform;
-    fFSParamLocation = GrGLProgramStage::kUseUniform;
-
     // For radial gradients without perspective we can pass the linear
     // part of the quadratic as a varying.
     if (builder->fVaryingDims == builder->fCoordDims) {
@@ -385,16 +377,7 @@
     this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
 }
 
-void GrGLRadial2Gradient::initUniforms(const GrGLShaderBuilder* builder,
-                                       const GrGLInterface* gl,
-                                       int programID) {
-    const char* vsParam = builder->getUniformCStr(fVSParamUni);
-    const char* fsParam = builder->getUniformCStr(fFSParamUni);
-    GR_GL_CALL_RET(gl, fVSParamLocation, GetUniformLocation(programID, vsParam));
-    GR_GL_CALL_RET(gl, fFSParamLocation, GetUniformLocation(programID, fsParam));
-}
-
-void GrGLRadial2Gradient::setData(const GrGLInterface* gl,
+void GrGLRadial2Gradient::setData(const GrGLUniformManager& uman,
                                   const GrCustomStage& baseData,
                                   const GrRenderTarget*,
                                   int stageNum) {
@@ -423,8 +406,8 @@
             data.isPosRoot() ? 1.f : -1.f
         };
 
-        GR_GL_CALL(gl, Uniform1fv(fVSParamLocation, 6, values));
-        GR_GL_CALL(gl, Uniform1fv(fFSParamLocation, 6, values));
+        uman.set1fv(fVSParamUni, 0, 6, values);
+        uman.set1fv(fFSParamUni, 0, 6, values);
         fCachedCenter = centerX1;
         fCachedRadius = radius0;
         fCachedPosRoot = data.isPosRoot();
@@ -492,10 +475,7 @@
                         const char* outputColor,
                         const char* inputColor,
                         const char* samplerName) SK_OVERRIDE;
-    virtual void initUniforms(const GrGLShaderBuilder* builder,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE;
-    virtual void setData(const GrGLInterface*,
+    virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
                          int stageNum) SK_OVERRIDE;
@@ -713,16 +693,7 @@
     }
 }
 
-void GrGLConical2Gradient::initUniforms(const GrGLShaderBuilder* builder,
-                                        const GrGLInterface* gl,
-                                        int programID) {
-    const char* vsParam = builder->getUniformCStr(fVSParamUni);
-    const char* fsParam = builder->getUniformCStr(fFSParamUni);
-    GR_GL_CALL_RET(gl, fVSParamLocation, GetUniformLocation(programID, vsParam));
-    GR_GL_CALL_RET(gl, fFSParamLocation, GetUniformLocation(programID, fsParam));
-}
-
-void GrGLConical2Gradient::setData(const GrGLInterface* gl,
+void GrGLConical2Gradient::setData(const GrGLUniformManager& uman,
                                    const GrCustomStage& baseData,
                                    const GrRenderTarget*,
                                    int stageNum) {
@@ -753,8 +724,8 @@
             GrScalarToFloat(diffRadius)
         };
 
-        GR_GL_CALL(gl, Uniform1fv(fVSParamLocation, 6, values));
-        GR_GL_CALL(gl, Uniform1fv(fFSParamLocation, 6, values));
+        uman.set1fv(fVSParamUni, 0, 6, values);
+        uman.set1fv(fFSParamUni, 0, 6, values);
         fCachedCenter = centerX1;
         fCachedRadius = radius0;
         fCachedDiffRadius = diffRadius;
diff --git a/src/gpu/effects/GrMorphologyEffect.cpp b/src/gpu/effects/GrMorphologyEffect.cpp
index 6699989..22c986a 100644
--- a/src/gpu/effects/GrMorphologyEffect.cpp
+++ b/src/gpu/effects/GrMorphologyEffect.cpp
@@ -29,10 +29,7 @@
 
     static inline StageKey GenKey(const GrCustomStage& s);
 
-    virtual void initUniforms(const GrGLShaderBuilder*,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE;
-    virtual void setData(const GrGLInterface*,
+    virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
                          int stageNum) SK_OVERRIDE;
@@ -40,10 +37,9 @@
 private:
     int width() const { return GrMorphologyEffect::WidthFromRadius(fRadius); }
 
-    int                                fRadius;
-    GrMorphologyEffect::MorphologyType fType;
-    GrGLShaderBuilder::UniformHandle   fImageIncrementUni;
-    GrGLint                            fImageIncrementLocation;
+    int                                 fRadius;
+    GrMorphologyEffect::MorphologyType  fType;
+    GrGLUniformManager::UniformHandle   fImageIncrementUni;
 
     typedef GrGLProgramStage INHERITED;
 };
@@ -51,8 +47,7 @@
 GrGLMorphologyEffect ::GrGLMorphologyEffect(const GrProgramStageFactory& factory,
                                             const GrCustomStage& stage)
     : GrGLProgramStage(factory)
-    , fImageIncrementUni(GrGLShaderBuilder::kInvalidUniformHandle)
-    , fImageIncrementLocation(0) {
+    , fImageIncrementUni(GrGLUniformManager::kInvalidUniformHandle) {
     const GrMorphologyEffect& m = static_cast<const GrMorphologyEffect&>(stage);
     fRadius = m.radius();
     fType = m.type();
@@ -71,13 +66,6 @@
     code->appendf("\t\t%s -= vec2(%d, %d) * %s;\n", vertexCoords, fRadius, fRadius, imgInc);
 }
 
-void GrGLMorphologyEffect::initUniforms(const GrGLShaderBuilder* builder,
-                                        const GrGLInterface* gl,
-                                        int programID) {
-    const char* imgInc = builder->getUniformCStr(fImageIncrementUni);
-    GR_GL_CALL_RET(gl, fImageIncrementLocation, GetUniformLocation(programID, imgInc));
-}
-
 void GrGLMorphologyEffect ::emitFS(GrGLShaderBuilder* builder,
                                    const char* outputColor,
                                    const char* inputColor,
@@ -119,7 +107,7 @@
     return key;
 }
 
-void GrGLMorphologyEffect ::setData(const GrGLInterface* gl,
+void GrGLMorphologyEffect ::setData(const GrGLUniformManager& uman,
                                     const GrCustomStage& data,
                                     const GrRenderTarget*,
                                     int stageNum) {
@@ -140,7 +128,7 @@
         default:
             GrCrash("Unknown filter direction.");
     }
-    GR_GL_CALL(gl, Uniform2fv(fImageIncrementLocation, 1, imageIncrement));
+    uman.set2fv(fImageIncrementUni, 0, 1, imageIncrement);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/effects/GrSingleTextureEffect.cpp b/src/gpu/effects/GrSingleTextureEffect.cpp
index d8b90a1..350d9e6 100644
--- a/src/gpu/effects/GrSingleTextureEffect.cpp
+++ b/src/gpu/effects/GrSingleTextureEffect.cpp
@@ -12,10 +12,6 @@
 #include "GrProgramStageFactory.h"
 #include "GrTexture.h"
 
-// For brevity, and these definitions are likely to move to a different class soon.
-typedef GrGLShaderBuilder::UniformHandle UniformHandle;
-static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
-
 class GrGLSingleTextureEffect : public GrGLProgramStage {
 public:
     GrGLSingleTextureEffect(const GrProgramStageFactory& factory,
diff --git a/src/gpu/effects/GrTextureDomainEffect.cpp b/src/gpu/effects/GrTextureDomainEffect.cpp
index e949c4c..ca8561c 100644
--- a/src/gpu/effects/GrTextureDomainEffect.cpp
+++ b/src/gpu/effects/GrTextureDomainEffect.cpp
@@ -9,10 +9,6 @@
 #include "gl/GrGLProgramStage.h"
 #include "GrProgramStageFactory.h"
 
-// For brevity, and these definitions are likely to move to a different class soon.
-typedef GrGLShaderBuilder::UniformHandle UniformHandle;
-static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
-
 class GrGLTextureDomainEffect : public GrGLProgramStage {
 public:
     GrGLTextureDomainEffect(const GrProgramStageFactory& factory,
@@ -27,11 +23,7 @@
                         const char* inputColor,
                         const char* samplerName) SK_OVERRIDE;
 
-    virtual void initUniforms(const GrGLShaderBuilder* builder,
-                              const GrGLInterface*,
-                              int programID) SK_OVERRIDE;
-
-    virtual void setData(const GrGLInterface*,
+    virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage&,
                          const GrRenderTarget*,
                          int stageNum) SK_OVERRIDE;
@@ -39,8 +31,7 @@
     static inline StageKey GenKey(const GrCustomStage&) { return 0; }
 
 private:
-    UniformHandle fNameUni;
-    int           fNameLocation;
+    GrGLUniformManager::UniformHandle fNameUni;
 
     typedef GrGLProgramStage INHERITED;
 };
@@ -48,15 +39,13 @@
 GrGLTextureDomainEffect::GrGLTextureDomainEffect(const GrProgramStageFactory& factory,
                                                  const GrCustomStage& stage)
     : GrGLProgramStage(factory)
-    , fNameUni(kInvalidUniformHandle)
-    , fNameLocation(0) {
+    , fNameUni(GrGLUniformManager::kInvalidUniformHandle) {
 }
 
 void GrGLTextureDomainEffect::setupVariables(GrGLShaderBuilder* builder,
                                              int stage) {
     fNameUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
                                    kVec4f_GrSLType, "uTexDom", stage);
-    fNameLocation = kUseUniform;
 };
 
 void GrGLTextureDomainEffect::emitFS(GrGLShaderBuilder* builder,
@@ -75,17 +64,10 @@
     builder->emitDefaultFetch(outputColor, samplerName);
 }
 
-void GrGLTextureDomainEffect::initUniforms(const GrGLShaderBuilder* builder,
-                                           const GrGLInterface* gl, int programID) {
-    GR_GL_CALL_RET(gl, fNameLocation,
-                   GetUniformLocation(programID, builder->getUniformCStr(fNameUni)));
-    GrAssert(kUnusedUniform != fNameLocation);
-}
-
-void GrGLTextureDomainEffect::setData(const GrGLInterface* gl,
-                         const GrCustomStage& data,
-                         const GrRenderTarget*,
-                         int stageNum) {
+void GrGLTextureDomainEffect::setData(const GrGLUniformManager& uman,
+                                      const GrCustomStage& data,
+                                      const GrRenderTarget*,
+                                      int stageNum) {
     const GrTextureDomainEffect& effect = static_cast<const GrTextureDomainEffect&>(data);
     const GrRect& domain = effect.domain();
 
@@ -104,8 +86,7 @@
         // of elements so that values = (l, t, r, b).
         SkTSwap(values[1], values[3]);
     }
-
-    GR_GL_CALL(gl, Uniform4fv(fNameLocation, 1, values));
+    uman.set4fv(fNameUni, 0, 1, values);
 }
 
 
@@ -114,7 +95,6 @@
 GrTextureDomainEffect::GrTextureDomainEffect(GrTexture* texture, GrRect domain)
     : GrSingleTextureEffect(texture)
     , fTextureDomain(domain) {
-
 }
 
 GrTextureDomainEffect::~GrTextureDomainEffect() {
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 8c1f4f7..3a39d0c 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -21,16 +21,6 @@
 #define GL_CALL(X) GR_GL_CALL(fContextInfo.interface(), X)
 #define GL_CALL_RET(R, X) GR_GL_CALL_RET(fContextInfo.interface(), R, X)
 
-namespace {
-
-enum {
-    /// Used to mark a StageUniLocation field that should be bound
-    /// to a uniform during getUniformLocationsAndInitCache().
-    kUseUniform = 2000
-};
-
-}  // namespace
-
 #define PRINT_SHADERS 0
 
 typedef GrGLProgram::Desc::StageDesc StageDesc;
@@ -104,15 +94,27 @@
 
 GrGLProgram::GrGLProgram(const GrGLContextInfo& gl,
                          const Desc& desc,
-                         GrCustomStage** customStages) : fContextInfo(gl) {
+                         GrCustomStage** customStages)
+: fContextInfo(gl)
+, fUniformManager(gl) {
     fDesc = desc;
     fVShaderID = 0;
     fGShaderID = 0;
     fFShaderID = 0;
     fProgramID = 0;
+
+    fViewMatrix = GrMatrix::InvalidMatrix();
+    fViewportSize.set(-1, -1);
+    fColor = GrColor_ILLEGAL;
+    fColorFilterColor = GrColor_ILLEGAL;
+
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
         fProgramStage[s] = NULL;
+        fTextureMatrices[s] = GrMatrix::InvalidMatrix();
+        // this is arbitrary, just initialize to something
+        fTextureOrientation[s] = GrGLTexture::kBottomUp_Orientation;
     }
+
     this->genProgram(customStages);
 }
 
@@ -399,9 +401,8 @@
             *inColor = fsName;
             } break;
         case GrGLProgram::Desc::kUniform_ColorInput:
-            builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                                 kVec4f_GrSLType, COL_UNI_NAME);
-            fUniLocations.fColorUni = kUseUniform;
+            fUniforms.fColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                                      kVec4f_GrSLType, COL_UNI_NAME);
             *inColor = COL_UNI_NAME;
             break;
         case GrGLProgram::Desc::kTransBlack_ColorInput:
@@ -416,9 +417,8 @@
 }
 
 void GrGLProgram::genUniformCoverage(GrGLShaderBuilder* builder, SkString* inOutCoverage) {
-    builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                        kVec4f_GrSLType, COV_UNI_NAME);
-    fUniLocations.fCoverageUni = kUseUniform;
+    fUniforms.fCoverageUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                                 kVec4f_GrSLType, COV_UNI_NAME);
     if (inOutCoverage->size()) {
         builder->fFSCode.appendf("\tvec4 uniCoverage = %s * %s;\n",
                                   COV_UNI_NAME, inOutCoverage->c_str());
@@ -589,15 +589,12 @@
     return true;
 }
 
-
 bool GrGLProgram::genProgram(GrCustomStage** customStages) {
     GrAssert(0 == fProgramID);
 
-    GrGLShaderBuilder builder(fContextInfo);
+    GrGLShaderBuilder builder(fContextInfo, fUniformManager);
     const uint32_t& layout = fDesc.fVertexLayout;
 
-    fUniLocations.reset();
-
 #if GR_GL_EXPERIMENTAL_GS
     builder.fUsesGS = fDesc.fExperimentalGS;
 #endif
@@ -658,9 +655,8 @@
         builder.fFSOutputs.push_back(colorOutput);
     }
 
-    builder.addUniform(GrGLShaderBuilder::kVertex_ShaderType,
-                       kMat33f_GrSLType, VIEW_MATRIX_NAME);
-    fUniLocations.fViewMatrixUni = kUseUniform;
+    fUniforms.fViewMatrixUni = builder.addUniform(GrGLShaderBuilder::kVertex_ShaderType,
+                                                  kMat33f_GrSLType, VIEW_MATRIX_NAME);
 
     builder.fVSAttrs.push_back().set(kVec2f_GrSLType,
                                      GrGLShaderVar::kAttribute_TypeModifier,
@@ -748,9 +744,8 @@
         }
     }
     if (needColorFilterUniform) {
-        builder.addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                           kVec4f_GrSLType, COL_FILTER_UNI_NAME);
-        fUniLocations.fColorFilterUni = kUseUniform;
+        fUniforms.fColorFilterUni = builder.addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                                       kVec4f_GrSLType, COL_FILTER_UNI_NAME);
     }
     bool wroteFragColorZero = false;
     if (SkXfermode::kZero_Coeff == uniformCoeff &&
@@ -768,12 +763,10 @@
         inColor = "filteredColor";
     }
     if (applyColorMatrix) {
-        builder.addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                           kMat44f_GrSLType, COL_MATRIX_UNI_NAME);
-        builder.addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                           kVec4f_GrSLType, COL_MATRIX_VEC_UNI_NAME);
-        fUniLocations.fColorMatrixUni = kUseUniform;
-        fUniLocations.fColorMatrixVecUni = kUseUniform;
+        fUniforms.fColorMatrixUni = builder.addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                                       kMat44f_GrSLType, COL_MATRIX_UNI_NAME);
+        fUniforms.fColorMatrixVecUni = builder.addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                                          kVec4f_GrSLType, COL_MATRIX_VEC_UNI_NAME);
         builder.fFSCode.append("\tvec4 matrixedColor;\n");
         const char* color = adjustInColor(inColor);
         addColorMatrix(&builder.fFSCode, "matrixedColor", color);
@@ -927,7 +920,8 @@
         return false;
     }
 
-    this->getUniformLocationsAndInitCache(builder);
+    builder.finished(fProgramID);
+    this->initSamplerUniforms();
 
     return true;
 }
@@ -993,78 +987,14 @@
     return true;
 }
 
-void GrGLProgram::getUniformLocationsAndInitCache(const GrGLShaderBuilder& builder) {
-
-    if (kUseUniform == fUniLocations.fViewMatrixUni) {
-        GL_CALL_RET(fUniLocations.fViewMatrixUni, GetUniformLocation(fProgramID, VIEW_MATRIX_NAME));
-        GrAssert(kUnusedUniform != fUniLocations.fViewMatrixUni);
-    }
-    if (kUseUniform == fUniLocations.fColorUni) {
-        GL_CALL_RET(fUniLocations.fColorUni, GetUniformLocation(fProgramID, COL_UNI_NAME));
-        GrAssert(kUnusedUniform != fUniLocations.fColorUni);
-    }
-    if (kUseUniform == fUniLocations.fColorFilterUni) {
-        GL_CALL_RET(fUniLocations.fColorFilterUni,
-                    GetUniformLocation(fProgramID, COL_FILTER_UNI_NAME));
-        GrAssert(kUnusedUniform != fUniLocations.fColorFilterUni);
-    }
-
-    if (kUseUniform == fUniLocations.fColorMatrixUni) {
-        GL_CALL_RET(fUniLocations.fColorMatrixUni,
-                    GetUniformLocation(fProgramID, COL_MATRIX_UNI_NAME));
-    }
-
-    if (kUseUniform == fUniLocations.fColorMatrixVecUni) {
-        GL_CALL_RET(fUniLocations.fColorMatrixVecUni,
-                    GetUniformLocation(fProgramID, COL_MATRIX_VEC_UNI_NAME));
-    }
-
-    if (kUseUniform == fUniLocations.fCoverageUni) {
-        GL_CALL_RET(fUniLocations.fCoverageUni,GetUniformLocation(fProgramID, COV_UNI_NAME));
-        GrAssert(kUnusedUniform != fUniLocations.fCoverageUni);
-    }
-
-    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-        StageUniLocations& locations = fUniLocations.fStages[s];
-        if (fDesc.fStages[s].isEnabled()) {
-            if (kUseUniform == locations.fTextureMatrixUni) {
-                SkString texMName;
-                tex_matrix_name(s, &texMName);
-                GL_CALL_RET(locations.fTextureMatrixUni,
-                            GetUniformLocation(fProgramID, texMName.c_str()));
-                //color filter table effect does not consumer coords gen'ed by matrix.
-                //GrAssert(kUnusedUniform != locations.fTextureMatrixUni);
-            }
-
-            if (kUseUniform == locations.fSamplerUni) {
-                SkString samplerName;
-                sampler_name(s, &samplerName);
-                GL_CALL_RET(locations.fSamplerUni,
-                            GetUniformLocation(fProgramID,samplerName.c_str()));
-                GrAssert(kUnusedUniform != locations.fSamplerUni);
-            }
-
-            if (NULL != fProgramStage[s]) {
-                fProgramStage[s]->initUniforms(&builder, fContextInfo.interface(), fProgramID);
-            }
-        }
-    }
+void GrGLProgram::initSamplerUniforms() {
     GL_CALL(UseProgram(fProgramID));
-
     // init sampler unis and set bogus values for state tracking
     for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-        if (kUnusedUniform != fUniLocations.fStages[s].fSamplerUni) {
-            GL_CALL(Uniform1i(fUniLocations.fStages[s].fSamplerUni, s));
+        if (GrGLUniformManager::kInvalidUniformHandle != fUniforms.fStages[s].fSamplerUni) {
+            fUniformManager.setSampler(fUniforms.fStages[s].fSamplerUni, s);
         }
-        fTextureMatrices[s] = GrMatrix::InvalidMatrix();
-        // this is arbitrary, just initialize to something
-        fTextureOrientation[s] = GrGLTexture::kBottomUp_Orientation;
-        // Must not reset fStageOverride[] here.
     }
-    fViewMatrix = GrMatrix::InvalidMatrix();
-    fViewportSize.set(-1, -1);
-    fColor = GrColor_ILLEGAL;
-    fColorFilterColor = GrColor_ILLEGAL;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1078,7 +1008,7 @@
     GrAssert(stageNum >= 0 && stageNum <= GrDrawState::kNumStages);
 
     const GrGLProgram::StageDesc& desc = fDesc.fStages[stageNum];
-    StageUniLocations& locations = fUniLocations.fStages[stageNum];
+    StageUniforms& uniforms = fUniforms.fStages[stageNum];
     GrGLProgramStage* customStage = fProgramStage[stageNum];
 
     GrAssert((desc.fInConfigFlags & StageDesc::kInConfigBitMask) == desc.fInConfigFlags);
@@ -1093,13 +1023,11 @@
     } else {
         SkString texMatName;
         tex_matrix_name(stageNum, &texMatName);
-        GrGLShaderBuilder::UniformHandle m =
-            segments->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
-                                 kMat33f_GrSLType, texMatName.c_str());
-        const GrGLShaderVar& mat = segments->getUniformVariable(m);
+        uniforms.fTextureMatrixUni = segments->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
+                                                          kMat33f_GrSLType, texMatName.c_str());
+        const GrGLShaderVar& mat = segments->getUniformVariable(uniforms.fTextureMatrixUni);
         // Can't use texMatName.c_str() because it's on the stack!
         matName = mat.getName().c_str();
-        locations.fTextureMatrixUni = kUseUniform;
 
         if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
             segments->fVaryingDims = segments->fCoordDims;
@@ -1116,9 +1044,8 @@
 
     SkString samplerName;
     sampler_name(stageNum, &samplerName);
-    segments->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
-                         kSampler2D_GrSLType, samplerName.c_str());
-    locations.fSamplerUni = kUseUniform;
+    uniforms.fSamplerUni = segments->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
+                                                kSampler2D_GrSLType, samplerName.c_str());
 
     const char *varyingVSName, *varyingFSName;
     segments->addVarying(GrSLFloatVectorType(segments->fVaryingDims),
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 6b6454d..02cb6ef 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -13,7 +13,7 @@
 #include "GrGLContextInfo.h"
 #include "GrGLSL.h"
 #include "GrGLTexture.h"
-//#include "GrGpu.h"
+#include "GrGLUniformManager.h"
 
 #include "SkString.h"
 #include "SkXfermode.h"
@@ -75,10 +75,6 @@
         return 7 + GrDrawState::kMaxTexCoords + 3 * stage;
     }
 
-    enum {
-        kUnusedUniform = -1,
-    };
-
     // Parameters that affect code generation
     // These structs should be kept compact; they are the input to an
     // expensive hash key generator.
@@ -259,6 +255,8 @@
 
     void genGeometryShader(GrGLShaderBuilder* segments) const;
 
+    typedef GrGLUniformManager::UniformHandle UniformHandle;
+
     void genUniformCoverage(GrGLShaderBuilder* segments, SkString* inOutCoverage);
 
     // generates code to compute coverage based on edge AA.
@@ -269,42 +267,37 @@
                                           bool bindColorOut,
                                           bool bindDualSrcOut);
 
-    // Binds uniforms; initializes cache to invalid values.
-    void getUniformLocationsAndInitCache(const GrGLShaderBuilder& builder);
+    // Sets the texture units for samplers
+    void initSamplerUniforms();
 
     bool compileShaders(const GrGLShaderBuilder& builder);
 
     const char* adjustInColor(const SkString& inColor) const;
 
-    struct StageUniLocations {
-        GrGLint fTextureMatrixUni;
-        GrGLint fSamplerUni;
-        GrGLint fTexDomUni;
-        void reset() {
-            fTextureMatrixUni = kUnusedUniform;
-            fSamplerUni = kUnusedUniform;
-            fTexDomUni = kUnusedUniform;
+    struct StageUniforms {
+        UniformHandle fTextureMatrixUni;
+        UniformHandle fSamplerUni;
+        StageUniforms() {
+            fTextureMatrixUni = GrGLUniformManager::kInvalidUniformHandle;
+            fSamplerUni = GrGLUniformManager::kInvalidUniformHandle;
         }
     };
 
-    struct UniLocations {
-        GrGLint fViewMatrixUni;
-        GrGLint fColorUni;
-        GrGLint fCoverageUni;
-        GrGLint fColorFilterUni;
-        GrGLint fColorMatrixUni;
-        GrGLint fColorMatrixVecUni;
-        StageUniLocations fStages[GrDrawState::kNumStages];
-        void reset() {
-            fViewMatrixUni = kUnusedUniform;
-            fColorUni = kUnusedUniform;
-            fCoverageUni = kUnusedUniform;
-            fColorFilterUni = kUnusedUniform;
-            fColorMatrixUni = kUnusedUniform;
-            fColorMatrixVecUni = kUnusedUniform;
-            for (int s = 0; s < GrDrawState::kNumStages; ++s) {
-                fStages[s].reset();
-            }
+    struct Uniforms {
+        UniformHandle fViewMatrixUni;
+        UniformHandle fColorUni;
+        UniformHandle fCoverageUni;
+        UniformHandle fColorFilterUni;
+        UniformHandle fColorMatrixUni;
+        UniformHandle fColorMatrixVecUni;
+        StageUniforms fStages[GrDrawState::kNumStages];
+        Uniforms() {
+            fViewMatrixUni = GrGLUniformManager::kInvalidUniformHandle;
+            fColorUni = GrGLUniformManager::kInvalidUniformHandle;
+            fCoverageUni = GrGLUniformManager::kInvalidUniformHandle;
+            fColorFilterUni = GrGLUniformManager::kInvalidUniformHandle;
+            fColorMatrixUni = GrGLUniformManager::kInvalidUniformHandle;
+            fColorMatrixVecUni = GrGLUniformManager::kInvalidUniformHandle;
         }
     };
 
@@ -313,8 +306,6 @@
     GrGLuint    fGShaderID;
     GrGLuint    fFShaderID;
     GrGLuint    fProgramID;
-    // shader uniform locations (-1 if shader doesn't use them)
-    UniLocations fUniLocations;
 
     // The matrix sent to GL is determined by both the client's matrix and
     // the size of the viewport.
@@ -336,6 +327,9 @@
     Desc fDesc;
     const GrGLContextInfo&      fContextInfo;
 
+    GrGLUniformManager          fUniformManager;
+    Uniforms                    fUniforms;
+
     friend class GrGpuGL; // TODO: remove this by adding getters and moving functionality.
 
     typedef GrRefCnt INHERITED;
diff --git a/src/gpu/gl/GrGLProgramStage.cpp b/src/gpu/gl/GrGLProgramStage.cpp
index fe103ad..caf123b 100644
--- a/src/gpu/gl/GrGLProgramStage.cpp
+++ b/src/gpu/gl/GrGLProgramStage.cpp
@@ -21,13 +21,7 @@
 
 }
 
-void GrGLProgramStage::initUniforms(const GrGLShaderBuilder*,
-                                    const GrGLInterface*,
-                                    int progID) {
-
-}
-
-void GrGLProgramStage::setData(const GrGLInterface*,
+void GrGLProgramStage::setData(const GrGLUniformManager&,
                                const GrCustomStage&,
                                const GrRenderTarget*,
                                int stageNum) {
diff --git a/src/gpu/gl/GrGLProgramStage.h b/src/gpu/gl/GrGLProgramStage.h
index 6350ae3..5b2ff50 100644
--- a/src/gpu/gl/GrGLProgramStage.h
+++ b/src/gpu/gl/GrGLProgramStage.h
@@ -73,17 +73,11 @@
                         const char* inputColor,
                         const char* samplerName) = 0;
 
-    /** Binds uniforms; we must have already bound the program and
-        determined its GL program ID. */
-    virtual void initUniforms(const GrGLShaderBuilder* builder,
-                              const GrGLInterface* gl,
-                              int programID);
-
     /** A GrGLCustomStage instance can be reused with any GrCustomStage
         that produces the same stage key; this function reads data from
         a stage and uploads any uniform variables required by the shaders
         created in emit*(). */
-    virtual void setData(const GrGLInterface* gl,
+    virtual void setData(const GrGLUniformManager&,
                          const GrCustomStage& stage,
                          const GrRenderTarget* renderTarget,
                          int stageNum);
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 7fa804a..f56f102 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -7,6 +7,7 @@
 
 #include "gl/GrGLShaderBuilder.h"
 #include "gl/GrGLProgram.h"
+#include "gl/GrGLUniformHandle.h"
 
 // number of each input/output type in a single allocation block
 static const int kVarsPerBlock = 8;
@@ -17,12 +18,15 @@
 // ES2 FS only guarantees mediump and lowp support
 static const GrGLShaderVar::Precision kDefaultFragmentPrecision = GrGLShaderVar::kMedium_Precision;
 
+typedef GrGLUniformManager::UniformHandle UniformHandle;
+///////////////////////////////////////////////////////////////////////////////
+
 // Architectural assumption: always 2-d input coords.
 // Likely to become non-constant and non-static, perhaps even
 // varying by stage, if we use 1D textures for gradients!
 //const int GrGLShaderBuilder::fCoordDims = 2;
 
-GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx)
+GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx, GrGLUniformManager& uniformManager)
     : fUniforms(kVarsPerBlock)
     , fVSAttrs(kVarsPerBlock)
     , fVSOutputs(kVarsPerBlock)
@@ -33,8 +37,8 @@
     , fUsesGS(false)
     , fVaryingDims(0)
     , fComplexCoord(false)
-    , fContext(ctx) {
-
+    , fContext(ctx)
+    , fUniformManager(uniformManager) {
 }
 
 void GrGLShaderBuilder::computeSwizzle(uint32_t configFlags) {
@@ -115,23 +119,23 @@
     fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
 }
 
-namespace {
-inline int handle_to_index(GrGLShaderBuilder::UniformHandle h) { return ~h; }
-inline GrGLShaderBuilder::UniformHandle index_to_handle(int i) { return ~i; }
-}
-
-GrGLShaderBuilder::UniformHandle GrGLShaderBuilder::addUniform(uint32_t visibility,
-                                                               GrSLType type,
-                                                               const char* name,
-                                                               int stageNum,
-                                                               int count) {
+GrGLUniformManager::UniformHandle GrGLShaderBuilder::addUniform(uint32_t visibility,
+                                                                GrSLType type,
+                                                                const char* name,
+                                                                int stageNum,
+                                                                int count) {
     GrAssert(name && strlen(name));
     static const uint32_t kVisibilityMask = kVertex_ShaderType | kFragment_ShaderType;
     GrAssert(0 == (~kVisibilityMask & visibility));
     GrAssert(0 != visibility);
 
-    Uniform& uni = fUniforms.push_back();
+    BuilderUniform& uni = fUniforms.push_back();
     UniformHandle h = index_to_handle(fUniforms.count() - 1);
+    GR_DEBUGCODE(UniformHandle h2 =)
+    fUniformManager.appendUniform(type, count);
+    // We expect the uniform manager to initially have no uniforms and that all uniforms are added
+    // by this function. Therefore, the handles should match.
+    GrAssert(h2 == h);
     uni.fVariable.setType(type);
     uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
     uni.fVariable.setName(name);
@@ -280,3 +284,6 @@
     }
  }
 
+void GrGLShaderBuilder::finished(GrGLuint programID) {
+    fUniformManager.getUniformLocations(programID, fUniforms);
+}
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 892fcbe..347bcda 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -11,28 +11,25 @@
 #include "GrAllocator.h"
 #include "gl/GrGLShaderVar.h"
 #include "gl/GrGLSL.h"
+#include "gl/GrGLUniformManager.h"
 
 class GrGLContextInfo;
+
 /**
   Contains all the incremental state of a shader as it is being built,as well as helpers to
   manipulate that state.
-  TODO: migrate CompileShaders() here?
 */
-
 class GrGLShaderBuilder {
 
 public:
 
-    typedef int UniformHandle;
-    static const UniformHandle kInvalidUniformHandle = 0;
-
     enum ShaderType {
         kVertex_ShaderType   = 0x1,
         kGeometry_ShaderType = 0x2,
         kFragment_ShaderType = 0x4,
     };
 
-    GrGLShaderBuilder(const GrGLContextInfo&);
+    GrGLShaderBuilder(const GrGLContextInfo&, GrGLUniformManager&);
 
     void computeSwizzle(uint32_t configFlags);
     void computeModulate(const char* fsInColor);
@@ -64,18 +61,18 @@
         from which shaders the uniform should be accessible. At least one bit must be set. Geometry
         shader uniforms are not supported at this time.
     */
-    UniformHandle addUniform(uint32_t visibility,
-                             GrSLType type,
-                             const char* name,
-                             int stageNum = -1,
-                             int count = GrGLShaderVar::kNonArray);
+    GrGLUniformManager::UniformHandle addUniform(uint32_t visibility,
+                                                 GrSLType type,
+                                                 const char* name,
+                                                 int stageNum = -1,
+                                                 int count = GrGLShaderVar::kNonArray);
 
-    const GrGLShaderVar& getUniformVariable(UniformHandle) const;
+    const GrGLShaderVar& getUniformVariable(GrGLUniformManager::UniformHandle) const;
 
     /**
      * Shorcut for getUniformVariable(u).c_str()
      */
-    const char* getUniformCStr(UniformHandle u) const {
+    const char* getUniformCStr(GrGLUniformManager::UniformHandle u) const {
         return this->getUniformVariable(u).c_str();
     }
 
@@ -99,19 +96,20 @@
     /** Called after building is complete to get the final shader string. */
     void getShader(ShaderType, SkString*) const;
 
+    /**
+     * TODO: Make this do all the compiling, linking, etc. Hide this from the custom stages
+     */
+    void finished(GrGLuint programID);
+
 private:
+
     typedef GrTAllocator<GrGLShaderVar> VarArray;
 
-    struct Uniform {
-        GrGLShaderVar fVariable;
-        uint32_t      fVisibility;
-    };
-
-    typedef GrTAllocator<Uniform> UniformArray;
     void appendDecls(const VarArray&, SkString*) const;
     void appendUniformDecls(ShaderType, SkString*) const;
 
-    UniformArray fUniforms;
+    typedef GrGLUniformManager::BuilderUniform BuilderUniform;
+    GrGLUniformManager::BuilderUniformArray fUniforms;
 
     // TODO: Everything below here private.
 public:
@@ -149,7 +147,8 @@
     //@}
 
 private:
-    const GrGLContextInfo& fContext;
+    const GrGLContextInfo&  fContext;
+    GrGLUniformManager&     fUniformManager;
 };
 
 #endif
diff --git a/src/gpu/gl/GrGLUniformHandle.h b/src/gpu/gl/GrGLUniformHandle.h
new file mode 100644
index 0000000..231dd31
--- /dev/null
+++ b/src/gpu/gl/GrGLUniformHandle.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrUniformHandle_DEFINED
+#define GrUniformHandle_DEFINED
+
+namespace {
+inline int handle_to_index(GrGLUniformManager::UniformHandle h) { return ~h; }
+inline GrGLUniformManager::UniformHandle index_to_handle(int i) { return ~i; }
+}
+
+#endif
diff --git a/src/gpu/gl/GrGLUniformManager.cpp b/src/gpu/gl/GrGLUniformManager.cpp
new file mode 100644
index 0000000..1625ebb
--- /dev/null
+++ b/src/gpu/gl/GrGLUniformManager.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gl/GrGLShaderBuilder.h"
+#include "gl/GrGLProgram.h"
+#include "gl/GrGLUniformHandle.h"
+
+#define ASSERT_ARRAY_UPLOAD_IN_BOUNDS(UNI, OFFSET, COUNT) \
+         GrAssert(offset + arrayCount <= uni.fArrayCount || \
+                  (0 == offset && 1 == arrayCount && GrGLShaderVar::kNonArray == uni.fArrayCount))
+
+GrGLUniformManager::UniformHandle GrGLUniformManager::appendUniform(GrSLType type, int arrayCount) {
+    int idx = fUniforms.count();
+    Uniform& uni = fUniforms.push_back();
+    GrAssert(GrGLShaderVar::kNonArray == arrayCount || arrayCount > 0);
+    uni.fArrayCount = arrayCount;
+    uni.fType = type;
+    uni.fVSLocation = kUnusedUniform;
+    uni.fFSLocation = kUnusedUniform;
+    return index_to_handle(idx);
+}
+
+void GrGLUniformManager::setSampler(UniformHandle u, GrGLint texUnit) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kSampler2D_GrSLType);
+    GrAssert(GrGLShaderVar::kNonArray == uni.fArrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform1i(uni.fFSLocation, texUnit));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform1i(uni.fVSLocation, texUnit));
+    }
+}
+
+void GrGLUniformManager::set1f(UniformHandle u, GrGLfloat v0) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kFloat_GrSLType);
+    GrAssert(GrGLShaderVar::kNonArray == uni.fArrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform1f(uni.fFSLocation, v0));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform1f(uni.fVSLocation, v0));
+    }
+}
+
+void GrGLUniformManager::set1fv(UniformHandle u,
+                                int offset,
+                                int arrayCount,
+                                const GrGLfloat v[]) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kFloat_GrSLType);
+    GrAssert(arrayCount > 0);
+    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, offset, arrayCount);
+    // This assert fires in some instances of the two-pt gradient for its VSParams.
+    // Once the uniform manager is responsible for inserting the duplicate uniform
+    // arrays in VS and FS driver bug workaround, this can be enabled.
+    //GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform1fv(uni.fFSLocation + offset, arrayCount, v));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform1fv(uni.fVSLocation + offset, arrayCount, v));
+    }
+}
+
+void GrGLUniformManager::set2f(UniformHandle u, GrGLfloat v0, GrGLfloat v1) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kVec2f_GrSLType);
+    GrAssert(GrGLShaderVar::kNonArray == uni.fArrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform2f(uni.fFSLocation, v0, v1));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform2f(uni.fVSLocation, v0, v1));
+    }
+}
+
+void GrGLUniformManager::set2fv(UniformHandle u,
+                                int offset,
+                                int arrayCount,
+                                const GrGLfloat v[]) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kVec2f_GrSLType);
+    GrAssert(arrayCount > 0);
+    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, offset, arrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform2fv(uni.fFSLocation + offset, arrayCount, v));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform2fv(uni.fVSLocation + offset, arrayCount, v));
+    }
+}
+
+void GrGLUniformManager::set3f(UniformHandle u, GrGLfloat v0, GrGLfloat v1, GrGLfloat v2) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kVec3f_GrSLType);
+    GrAssert(GrGLShaderVar::kNonArray == uni.fArrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform3f(uni.fFSLocation, v0, v1, v2));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform3f(uni.fVSLocation, v0, v1, v2));
+    }
+}
+
+void GrGLUniformManager::set3fv(UniformHandle u,
+                                int offset,
+                                int arrayCount,
+                                const GrGLfloat v[]) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kVec3f_GrSLType);
+    GrAssert(arrayCount > 0);
+    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, offset, arrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform3fv(uni.fFSLocation + offset, arrayCount, v));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform3fv(uni.fVSLocation + offset, arrayCount, v));
+    }
+}
+
+void GrGLUniformManager::set4f(UniformHandle u,
+                               GrGLfloat v0,
+                               GrGLfloat v1,
+                               GrGLfloat v2,
+                               GrGLfloat v3) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kVec4f_GrSLType);
+    GrAssert(GrGLShaderVar::kNonArray == uni.fArrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform4f(uni.fFSLocation, v0, v1, v2, v3));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform4f(uni.fVSLocation, v0, v1, v2, v3));
+    }
+}
+
+void GrGLUniformManager::set4fv(UniformHandle u,
+                                int offset,
+                                int arrayCount,
+                                const GrGLfloat v[]) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kVec4f_GrSLType);
+    GrAssert(arrayCount > 0);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform4fv(uni.fFSLocation + offset, arrayCount, v));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), Uniform4fv(uni.fVSLocation + offset, arrayCount, v));
+    }
+}
+
+void GrGLUniformManager::setMatrix3f(UniformHandle u, const GrGLfloat matrix[]) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kMat33f_GrSLType);
+    GrAssert(GrGLShaderVar::kNonArray == uni.fArrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), UniformMatrix3fv(uni.fFSLocation, 1, false, matrix));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), UniformMatrix3fv(uni.fVSLocation, 1, false, matrix));
+    }
+}
+
+void GrGLUniformManager::setMatrix4f(UniformHandle u, const GrGLfloat matrix[]) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kMat44f_GrSLType);
+    GrAssert(GrGLShaderVar::kNonArray == uni.fArrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), UniformMatrix4fv(uni.fFSLocation, 1, false, matrix));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(), UniformMatrix4fv(uni.fVSLocation, 1, false, matrix));
+    }
+}
+
+void GrGLUniformManager::setMatrix3fv(UniformHandle u,
+                                      int offset,
+                                      int arrayCount,
+                                      const GrGLfloat matrices[]) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kMat33f_GrSLType);
+    GrAssert(arrayCount > 0);
+    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, offset, arrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(),
+                   UniformMatrix3fv(uni.fFSLocation + offset, arrayCount, false, matrices));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(),
+                   UniformMatrix3fv(uni.fVSLocation + offset, arrayCount, false, matrices));
+    }
+}
+
+void GrGLUniformManager::setMatrix4fv(UniformHandle u,
+                                      int offset,
+                                      int arrayCount,
+                                      const GrGLfloat matrices[]) const {
+    const Uniform& uni = fUniforms[handle_to_index(u)];
+    GrAssert(uni.fType == kMat44f_GrSLType);
+    GrAssert(arrayCount > 0);
+    ASSERT_ARRAY_UPLOAD_IN_BOUNDS(uni, offset, arrayCount);
+    GrAssert(kUnusedUniform != uni.fFSLocation || kUnusedUniform != uni.fVSLocation);
+    if (kUnusedUniform != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(),
+                   UniformMatrix4fv(uni.fFSLocation + offset, arrayCount, false, matrices));
+    }
+    if (kUnusedUniform != uni.fVSLocation && uni.fVSLocation != uni.fFSLocation) {
+        GR_GL_CALL(fContext.interface(),
+                   UniformMatrix4fv(uni.fVSLocation + offset, arrayCount, false, matrices));
+    }
+}
+
+void GrGLUniformManager::getUniformLocations(GrGLuint programID, const BuilderUniformArray& uniforms) {
+    GrAssert(uniforms.count() == fUniforms.count());
+    int count = fUniforms.count();
+    for (int i = 0; i < count; ++i) {
+        GrAssert(uniforms[i].fVariable.getType() == fUniforms[i].fType);
+        GrAssert(uniforms[i].fVariable.getArrayCount() == fUniforms[i].fArrayCount);
+        GrGLint location;
+        // TODO: Move the Xoom uniform array in both FS and VS bug workaround here.
+        GR_GL_CALL_RET(fContext.interface(), location,
+                       GetUniformLocation(programID, uniforms[i].fVariable.c_str()));
+        if (GrGLShaderBuilder::kVertex_ShaderType & uniforms[i].fVisibility) {
+            fUniforms[i].fVSLocation = location;
+        }
+        if (GrGLShaderBuilder::kFragment_ShaderType & uniforms[i].fVisibility) {
+            fUniforms[i].fFSLocation = location;
+        }
+    }
+}
diff --git a/src/gpu/gl/GrGLUniformManager.h b/src/gpu/gl/GrGLUniformManager.h
new file mode 100644
index 0000000..aea96f0
--- /dev/null
+++ b/src/gpu/gl/GrGLUniformManager.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLUniformManager_DEFINED
+#define GrGLUniformManager_DEFINED
+
+#include "gl/GrGLShaderVar.h"
+#include "gl/GrGLSL.h"
+
+#include "SkTArray.h"
+
+class GrGLContextInfo;
+
+/** Manages a program's uniforms.
+*/
+class GrGLUniformManager {
+public:
+    // Opaque handle to a uniform
+    typedef int UniformHandle;
+    static const UniformHandle kInvalidUniformHandle = 0;
+
+    GrGLUniformManager(const GrGLContextInfo& context) : fContext(context) {}
+
+    UniformHandle appendUniform(GrSLType type, int arrayCount = GrGLShaderVar::kNonArray);
+
+    /** Functions for uploading uniform values. The varities ending in v can be used to upload to an
+     *  array of uniforms. offset + arrayCount must be <= the array count of the uniform.
+     */
+    void setSampler(UniformHandle, GrGLint texUnit) const;
+    void set1f(UniformHandle, GrGLfloat v0) const;
+    void set1fv(UniformHandle, int offset, int arrayCount, const GrGLfloat v[]) const;
+    void set2f(UniformHandle, GrGLfloat, GrGLfloat) const;
+    void set2fv(UniformHandle, int offset, int arrayCount, const GrGLfloat v[]) const;
+    void set3f(UniformHandle, GrGLfloat, GrGLfloat, GrGLfloat) const;
+    void set3fv(UniformHandle, int offset, int arrayCount, const GrGLfloat v[]) const;
+    void set4f(UniformHandle, GrGLfloat, GrGLfloat, GrGLfloat, GrGLfloat) const;
+    void set4fv(UniformHandle, int offset, int arrayCount, const GrGLfloat v[]) const;
+    // matrices are column-major, the first three upload a single matrix, the latter three upload
+    // arrayCount matrices into a uniform array.
+    void setMatrix3f(UniformHandle, const GrGLfloat matrix[]) const;
+    void setMatrix4f(UniformHandle, const GrGLfloat matrix[]) const;
+    void setMatrix3fv(UniformHandle, int offset, int arrayCount, const GrGLfloat matrices[]) const;
+    void setMatrix4fv(UniformHandle, int offset, int arrayCount, const GrGLfloat matrices[]) const;
+
+    struct BuilderUniform {
+        GrGLShaderVar fVariable;
+        uint32_t      fVisibility;
+    };
+    typedef SkTArray<BuilderUniform, true> BuilderUniformArray;
+
+    /**
+     * Called by the GrGLShaderBuilder to get GL locations for all uniforms.
+     */
+    void getUniformLocations(GrGLuint programID, const BuilderUniformArray& uniforms);
+
+private:
+    enum {
+        kUnusedUniform = -1,
+    };
+
+    struct Uniform {
+        GrGLint     fVSLocation;
+        GrGLint     fFSLocation;
+        GrSLType    fType;
+        int         fArrayCount;
+    };
+
+    SkTArray<Uniform, true> fUniforms;
+    const GrGLContextInfo&  fContext;
+};
+
+#endif
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index fb78ad2..b3e8cf8 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -219,8 +219,8 @@
     void flushBoundTextureAndParams(int stage);
     void flushBoundTextureAndParams(int stage, GrGLTexture* nextTexture);
 
-    // sets the texture matrix and domain for the currently bound program
-    void flushTextureMatrixAndDomain(int stage);
+    // sets the texture matrix for the currently bound program
+    void flushTextureMatrix(int stage);
 
     // sets the color specified by GrDrawState::setColor()
     void flushColor(GrColor color);
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index 56a893d..f4044fc 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -11,6 +11,9 @@
 #include "GrGLProgramStage.h"
 #include "GrGpuVertex.h"
 
+typedef GrGLUniformManager::UniformHandle UniformHandle;
+static const UniformHandle kInvalidUniformHandle = GrGLUniformManager::kInvalidUniformHandle;
+
 #define SKIP_CACHE_CHECK    true
 #define GR_UINT32_MAX   static_cast<uint32_t>(-1)
 
@@ -147,11 +150,7 @@
             GrScalarToFloat(m[GrMatrix::kMTransY]),
             GrScalarToFloat(m[GrMatrix::kMPersp2])
         };
-
-        GrAssert(GrGLProgram::kUnusedUniform != 
-                 fCurrentProgram->fUniLocations.fViewMatrixUni);
-        GL_CALL(UniformMatrix3fv(fCurrentProgram->fUniLocations.fViewMatrixUni,
-                                 1, false, mt));
+        fCurrentProgram->fUniformManager.setMatrix3f(fCurrentProgram->fUniforms.fViewMatrixUni, mt);
         fCurrentProgram->fViewMatrix = vm;
         fCurrentProgram->fViewportSize = viewportSize;
     }
@@ -194,7 +193,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrGpuGL::flushTextureMatrixAndDomain(int s) {
+void GrGpuGL::flushTextureMatrix(int s) {
     const GrDrawState& drawState = this->getDrawState();
     const GrGLTexture* texture =
         static_cast<const GrGLTexture*>(drawState.getTexture(s));
@@ -203,13 +202,12 @@
         bool orientationChange = fCurrentProgram->fTextureOrientation[s] !=
                                  texture->orientation();
 
-        const GrGLint& matrixUni =
-            fCurrentProgram->fUniLocations.fStages[s].fTextureMatrixUni;
+        UniformHandle matrixUni = fCurrentProgram->fUniforms.fStages[s].fTextureMatrixUni;
 
         const GrMatrix& hwMatrix = fCurrentProgram->fTextureMatrices[s];
         const GrMatrix& samplerMatrix = drawState.getSampler(s).getMatrix();
 
-        if (GrGLProgram::kUnusedUniform != matrixUni &&
+        if (kInvalidUniformHandle != matrixUni &&
             (orientationChange || !hwMatrix.cheapEqualTo(samplerMatrix))) {
 
             GrMatrix m = samplerMatrix;
@@ -229,7 +227,7 @@
                 GrScalarToFloat(m[GrMatrix::kMPersp2])
             };
 
-            GL_CALL(UniformMatrix3fv(matrixUni, 1, false, mt));
+            fCurrentProgram->fUniformManager.setMatrix3f(matrixUni, mt);
             fCurrentProgram->fTextureMatrices[s] = samplerMatrix;
         }
 
@@ -239,10 +237,9 @@
 
 
 void GrGpuGL::flushColorMatrix() {
-    int matrixUni = fCurrentProgram->fUniLocations.fColorMatrixUni;
-    int vecUni = fCurrentProgram->fUniLocations.fColorMatrixVecUni;
-    if (GrGLProgram::kUnusedUniform != matrixUni
-     && GrGLProgram::kUnusedUniform != vecUni) {
+    UniformHandle matrixUni = fCurrentProgram->fUniforms.fColorMatrixUni;
+    UniformHandle vecUni = fCurrentProgram->fUniforms.fColorMatrixVecUni;
+    if (kInvalidUniformHandle != matrixUni && kInvalidUniformHandle != vecUni) {
         const float* m = this->getDrawState().getColorMatrix();
         GrGLfloat mt[]  = {
             m[0], m[5], m[10], m[15],
@@ -254,8 +251,8 @@
         GrGLfloat vec[] = {
             m[4] * scale, m[9] * scale, m[14] * scale, m[19] * scale,
         };
-        GL_CALL(UniformMatrix4fv(matrixUni, 1, false, mt));
-        GL_CALL(Uniform4fv(vecUni, 1, vec));
+        fCurrentProgram->fUniformManager.setMatrix4f(matrixUni, mt);
+        fCurrentProgram->fUniformManager.set4fv(vecUni, 0, 1, vec);
     }
 }
 
@@ -293,9 +290,9 @@
                     // OpenGL ES doesn't support unsigned byte varieties of
                     // glUniform
                     float c[] = GR_COLOR_TO_VEC4(color);
-                    GrAssert(GrGLProgram::kUnusedUniform != 
-                             fCurrentProgram->fUniLocations.fColorUni);
-                    GL_CALL(Uniform4fv(fCurrentProgram->fUniLocations.fColorUni, 1, c));
+                    GrAssert(kInvalidUniformHandle !=  fCurrentProgram->fUniforms.fColorUni);
+                    fCurrentProgram->fUniformManager.set4fv(fCurrentProgram->fUniforms.fColorUni,
+                                                            0, 1, c);
                     fCurrentProgram->fColor = color;
                 }
                 break;
@@ -306,12 +303,11 @@
                 GrCrash("Unknown color type.");
         }
     }
-    if (fCurrentProgram->fUniLocations.fColorFilterUni
-                != GrGLProgram::kUnusedUniform
-            && fCurrentProgram->fColorFilterColor
-                != drawState.getColorFilterColor()) {
+    UniformHandle filterColorUni = fCurrentProgram->fUniforms.fColorFilterUni;
+    if (kInvalidUniformHandle != filterColorUni &&
+        fCurrentProgram->fColorFilterColor != drawState.getColorFilterColor()) {
         float c[] = GR_COLOR_TO_VEC4(drawState.getColorFilterColor());
-        GL_CALL(Uniform4fv(fCurrentProgram->fUniLocations.fColorFilterUni, 1, c));
+        fCurrentProgram->fUniformManager.set4fv(filterColorUni, 0, 1, c);
         fCurrentProgram->fColorFilterColor = drawState.getColorFilterColor();
     }
 }
@@ -342,9 +338,9 @@
                     // OpenGL ES doesn't support unsigned byte varieties of
                     // glUniform
                     float c[] = GR_COLOR_TO_VEC4(coverage);
-                    GrAssert(GrGLProgram::kUnusedUniform != 
-                             fCurrentProgram->fUniLocations.fCoverageUni);
-                    GL_CALL(Uniform4fv(fCurrentProgram->fUniLocations.fCoverageUni, 1, c));
+                    GrAssert(kInvalidUniformHandle !=  fCurrentProgram->fUniforms.fCoverageUni);
+                    fCurrentProgram->fUniformManager.set4fv(fCurrentProgram->fUniforms.fCoverageUni,
+                                                            0, 1, c);
                     fCurrentProgram->fCoverage = coverage;
                 }
                 break;
@@ -418,13 +414,13 @@
 #endif
                 this->flushBoundTextureAndParams(s);
 
-                this->flushTextureMatrixAndDomain(s);
+                this->flushTextureMatrix(s);
 
                 if (NULL != fCurrentProgram->fProgramStage[s]) {
                     const GrSamplerState& sampler = this->getDrawState().getSampler(s);
                     const GrGLTexture* texture = static_cast<const GrGLTexture*>(
                                                     this->getDrawState().getTexture(s));
-                    fCurrentProgram->fProgramStage[s]->setData(this->glInterface(),
+                    fCurrentProgram->fProgramStage[s]->setData(fCurrentProgram->fUniformManager,
                                                                *sampler.getCustomStage(),
                                                                drawState.getRenderTarget(), s);
                 }