Remove uniform var pointers from custom effects

Review URL: http://codereview.appspot.com/6374067/



git-svn-id: http://skia.googlecode.com/svn/trunk@4616 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 1ad9817..d13620c 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -932,7 +932,7 @@
         return false;
     }
 
-    this->getUniformLocationsAndInitCache(gl, programData);
+    this->getUniformLocationsAndInitCache(builder, gl, programData);
 
     return true;
 }
@@ -1003,7 +1003,8 @@
     return true;
 }
 
-void GrGLProgram::getUniformLocationsAndInitCache(const GrGLContextInfo& gl,
+void GrGLProgram::getUniformLocationsAndInitCache(const GrGLShaderBuilder& builder,
+                                                  const GrGLContextInfo& gl,
                                                   CachedData* programData) const {
     const GrGLint& progID = programData->fProgramID;
 
@@ -1066,8 +1067,7 @@
             }
 
             if (NULL != programData->fCustomStage[s]) {
-                programData->fCustomStage[s]->
-                    initUniforms(gl.interface(), progID);
+                programData->fCustomStage[s]->initUniforms(&builder, gl.interface(), progID);
             }
         }
     }
@@ -1118,10 +1118,12 @@
     } else {
         SkString texMatName;
         tex_matrix_name(stageNum, &texMatName);
-        const GrGLShaderVar* mat = &segments->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
-                                                         kMat33f_GrSLType, texMatName.c_str());
+        GrGLShaderBuilder::UniformHandle m =
+            segments->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
+                                 kMat33f_GrSLType, texMatName.c_str());
+        const GrGLShaderVar& mat = segments->getUniformVariable(m);
         // Can't use texMatName.c_str() because it's on the stack!
-        matName = mat->getName().c_str();
+        matName = mat.getName().c_str();
         locations->fTextureMatrixUni = kUseUniform;
 
         if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 0be08b3..bebaa58 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -366,7 +366,8 @@
                 CachedData* programData) const;
 
     // Binds uniforms; initializes cache to invalid values.
-    void getUniformLocationsAndInitCache(const GrGLContextInfo& gl,
+    void getUniformLocationsAndInitCache(const GrGLShaderBuilder& builder,
+                                         const GrGLContextInfo& gl,
                                          CachedData* programData) const;
 
     friend class GrGpuGL;
diff --git a/src/gpu/gl/GrGLProgramStage.cpp b/src/gpu/gl/GrGLProgramStage.cpp
index c1d4942..fe103ad 100644
--- a/src/gpu/gl/GrGLProgramStage.cpp
+++ b/src/gpu/gl/GrGLProgramStage.cpp
@@ -17,11 +17,13 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void GrGLProgramStage::setupVariables(GrGLShaderBuilder* state, int stage) {
+void GrGLProgramStage::setupVariables(GrGLShaderBuilder*, int stage) {
 
 }
 
-void GrGLProgramStage::initUniforms(const GrGLInterface*, int progID) {
+void GrGLProgramStage::initUniforms(const GrGLShaderBuilder*,
+                                    const GrGLInterface*,
+                                    int progID) {
 
 }
 
diff --git a/src/gpu/gl/GrGLProgramStage.h b/src/gpu/gl/GrGLProgramStage.h
index d5c79b4..6350ae3 100644
--- a/src/gpu/gl/GrGLProgramStage.h
+++ b/src/gpu/gl/GrGLProgramStage.h
@@ -48,7 +48,7 @@
     virtual ~GrGLProgramStage();
 
     /** Create any uniforms or varyings the vertex shader requires. */
-    virtual void setupVariables(GrGLShaderBuilder* state, int stage);
+    virtual void setupVariables(GrGLShaderBuilder* builder, int stage);
 
     /** Appends vertex code to the appropriate SkString
         on the state.
@@ -56,7 +56,7 @@
         Vertex shader input is a vec2 of coordinates, which may
         be altered.
         The code will be inside an otherwise-empty block. */
-    virtual void emitVS(GrGLShaderBuilder* state,
+    virtual void emitVS(GrGLShaderBuilder* builder,
                         const char* vertexCoords) = 0;
 
     /** Appends fragment code to the appropriate SkString
@@ -68,14 +68,16 @@
        a function here for them to call into that'll apply any texture
        domain - but do we force them to be honest about texture domain
        parameters? */
-    virtual void emitFS(GrGLShaderBuilder* state,
+    virtual void emitFS(GrGLShaderBuilder* builder,
                         const char* outputColor,
                         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 GrGLInterface* gl, int programID);
+    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
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 3303bf2..7fa804a 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -23,13 +23,12 @@
 //const int GrGLShaderBuilder::fCoordDims = 2;
 
 GrGLShaderBuilder::GrGLShaderBuilder(const GrGLContextInfo& ctx)
-    : fVSUnis(kVarsPerBlock)
+    : fUniforms(kVarsPerBlock)
     , fVSAttrs(kVarsPerBlock)
     , fVSOutputs(kVarsPerBlock)
     , fGSInputs(kVarsPerBlock)
     , fGSOutputs(kVarsPerBlock)
     , fFSInputs(kVarsPerBlock)
-    , fFSUnis(kVarsPerBlock)
     , fFSOutputs(kMaxFSOutputs)
     , fUsesGS(false)
     , fVaryingDims(0)
@@ -116,38 +115,45 @@
     fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
 }
 
-const GrGLShaderVar& GrGLShaderBuilder::addUniform(uint32_t visibility,
-                                                   GrSLType type,
-                                                   const char* name,
-                                                   int stageNum,
-                                                   int count) {
+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) {
     GrAssert(name && strlen(name));
     static const uint32_t kVisibilityMask = kVertex_ShaderType | kFragment_ShaderType;
     GrAssert(0 == (~kVisibilityMask & visibility));
     GrAssert(0 != visibility);
 
-    GrGLShaderVar* var = NULL;
-    if (kVertex_ShaderType & visibility) {
-        var = &fVSUnis.push_back();
-    } else {
-        GrAssert(kFragment_ShaderType & visibility);
-        var = &fFSUnis.push_back();
-    }
-    var->setType(type);
-    var->setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
-    var->setName(name);
+    Uniform& uni = fUniforms.push_back();
+    UniformHandle h = index_to_handle(fUniforms.count() - 1);
+    uni.fVariable.setType(type);
+    uni.fVariable.setTypeModifier(GrGLShaderVar::kUniform_TypeModifier);
+    uni.fVariable.setName(name);
     if (stageNum >= 0) {
-        var->accessName()->appendS32(stageNum);
+        uni.fVariable.accessName()->appendS32(stageNum);
     }
-    var->setArrayCount(count);
+    uni.fVariable.setArrayCount(count);
+    uni.fVisibility = visibility;
 
+    // If it is visible in both the VS and FS, the precision must match.
+    // We declare a default FS precision, but not a default VS. So set the var
+    // to use the default FS precision.
     if ((kVertex_ShaderType | kFragment_ShaderType) == visibility) {
         // the fragment and vertex precisions must match
-        var->setPrecision(kDefaultFragmentPrecision);
-        fFSUnis.push_back(*var);
+        uni.fVariable.setPrecision(kDefaultFragmentPrecision);
     }
 
-    return *var;
+    return h;
+}
+
+const GrGLShaderVar& GrGLShaderBuilder::getUniformVariable(UniformHandle u) const {
+    return fUniforms[handle_to_index(u)].fVariable;
 }
 
 void GrGLShaderBuilder::addVarying(GrSLType type,
@@ -222,31 +228,37 @@
         }
     }
 }
+}
 
-void append_decls(const GrGLShaderBuilder::VarArray& vars,
-                  const GrGLContextInfo& ctx,
-                  SkString* string) {
+void GrGLShaderBuilder::appendDecls(const VarArray& vars, SkString* out) const {
     for (int i = 0; i < vars.count(); ++i) {
-        vars[i].appendDecl(ctx, string);
+        vars[i].appendDecl(fContext, out);
     }
 }
+
+void GrGLShaderBuilder::appendUniformDecls(ShaderType stype, SkString* out) const {
+    for (int i = 0; i < fUniforms.count(); ++i) {
+        if (fUniforms[i].fVisibility & stype) {
+            fUniforms[i].fVariable.appendDecl(fContext, out);
+        }
+    }
 }
 
 void GrGLShaderBuilder::getShader(ShaderType type, SkString* shaderStr) const {
     switch (type) {
         case kVertex_ShaderType:
             *shaderStr = fHeader;
-            append_decls(fVSUnis, fContext, shaderStr);
-            append_decls(fVSAttrs, fContext, shaderStr);
-            append_decls(fVSOutputs, fContext, shaderStr);
+            this->appendUniformDecls(kVertex_ShaderType, shaderStr);
+            this->appendDecls(fVSAttrs, shaderStr);
+            this->appendDecls(fVSOutputs, shaderStr);
             shaderStr->append(fVSCode);
             break;
         case kGeometry_ShaderType:
             if (fUsesGS) {
                 *shaderStr = fHeader;
                 shaderStr->append(fGSHeader);
-                append_decls(fGSInputs, fContext, shaderStr);
-                append_decls(fGSOutputs, fContext, shaderStr);
+                this->appendDecls(fGSInputs, shaderStr);
+                this->appendDecls(fGSOutputs, shaderStr);
                 shaderStr->append(fGSCode);
             } else {
                 shaderStr->reset();
@@ -257,11 +269,11 @@
             append_default_precision_qualifier(kDefaultFragmentPrecision,
                                                fContext.binding(),
                                                shaderStr);
-            append_decls(fFSUnis, fContext, shaderStr);
-            append_decls(fFSInputs, fContext, shaderStr);
+            this->appendUniformDecls(kFragment_ShaderType, shaderStr);
+            this->appendDecls(fFSInputs, shaderStr);
             // We shouldn't have declared outputs on 1.10
             GrAssert(k110_GrGLSLGeneration != fContext.glslGeneration() || fFSOutputs.empty());
-            append_decls(fFSOutputs, fContext, shaderStr);
+            this->appendDecls(fFSOutputs, shaderStr);
             shaderStr->append(fFSFunctions);
             shaderStr->append(fFSCode);
             break;
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 5884a90..892fcbe 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -22,7 +22,9 @@
 class GrGLShaderBuilder {
 
 public:
-    typedef GrTAllocator<GrGLShaderVar> VarArray;
+
+    typedef int UniformHandle;
+    static const UniformHandle kInvalidUniformHandle = 0;
 
     enum ShaderType {
         kVertex_ShaderType   = 0x1,
@@ -62,11 +64,20 @@
         from which shaders the uniform should be accessible. At least one bit must be set. Geometry
         shader uniforms are not supported at this time.
     */
-    const GrGLShaderVar& addUniform(uint32_t visibility,
-                                    GrSLType type,
-                                    const char* name,
-                                    int stageNum = -1,
-                                    int count = GrGLShaderVar::kNonArray);
+    UniformHandle addUniform(uint32_t visibility,
+                             GrSLType type,
+                             const char* name,
+                             int stageNum = -1,
+                             int count = GrGLShaderVar::kNonArray);
+
+    const GrGLShaderVar& getUniformVariable(UniformHandle) const;
+
+    /**
+     * Shorcut for getUniformVariable(u).c_str()
+     */
+    const char* getUniformCStr(UniformHandle u) const {
+        return this->getUniformVariable(u).c_str();
+    }
 
     /** Add a varying variable to the current program to pass values between vertex and fragment
         shaders. If the last two parameters are non-NULL, they are filled in with the name
@@ -88,17 +99,30 @@
     /** Called after building is complete to get the final shader string. */
     void getShader(ShaderType, SkString*) const;
 
+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;
+
     // TODO: Everything below here private.
+public:
 
     SkString    fHeader; // VS+FS, GLSL version, etc
-    VarArray    fVSUnis;
     VarArray    fVSAttrs;
     VarArray    fVSOutputs;
     VarArray    fGSInputs;
     VarArray    fGSOutputs;
     VarArray    fFSInputs;
     SkString    fGSHeader; // layout qualifiers specific to GS
-    VarArray    fFSUnis;
     VarArray    fFSOutputs;
     SkString    fFSFunctions;
     SkString    fVSCode;
diff --git a/src/gpu/gl/GrGLShaderVar.h b/src/gpu/gl/GrGLShaderVar.h
index 2eccd3b..0231d21 100644
--- a/src/gpu/gl/GrGLShaderVar.h
+++ b/src/gpu/gl/GrGLShaderVar.h
@@ -171,12 +171,18 @@
      */
     void setName(const SkString& n) { fName = n; }
     void setName(const char* n) { fName = n; }
+
     /**
      * Get the var name.
      */
     const SkString& getName() const { return fName; }
 
     /**
+     * Shortcut for this->getName().c_str();
+     */
+    const char* c_str() const { return this->getName().c_str(); }
+
+    /**
      * Get the type of the var
      */
     GrSLType getType() const { return fType; }