Some GrGLShaderBuilder cleanup

Review URL: https://codereview.appspot.com/6500043/



git-svn-id: http://skia.googlecode.com/svn/trunk@5322 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index a82e527..9613697 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -1000,6 +1000,7 @@
     const GrGLProgram::StageDesc& desc = fDesc.fStages[stageNum];
     StageUniforms& uniforms = fUniforms.fStages[stageNum];
     GrGLProgramStage* customStage = fProgramStage[stageNum];
+    GrAssert(NULL != customStage);
 
     GrAssert((desc.fInConfigFlags & StageDesc::kInConfigBitMask) == desc.fInConfigFlags);
 
@@ -1010,25 +1011,29 @@
     // decide whether we need a matrix to transform texture coords and whether the varying needs a
     // perspective coord.
     const char* matName = NULL;
+    GrSLType texCoordVaryingType;
     if (desc.fOptFlags & StageDesc::kIdentityMatrix_OptFlagBit) {
-        builder->fVaryingDims = builder->fCoordDims;
+        texCoordVaryingType = kVec2f_GrSLType;
     } else {
         uniforms.fTextureMatrixUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
                                                          kMat33f_GrSLType, "TexM", &matName);
         const GrGLShaderVar& mat = builder->getUniformVariable(uniforms.fTextureMatrixUni);
 
         if (desc.fOptFlags & StageDesc::kNoPerspective_OptFlagBit) {
-            builder->fVaryingDims = builder->fCoordDims;
+            texCoordVaryingType = kVec2f_GrSLType;
         } else {
-            builder->fVaryingDims = builder->fCoordDims + 1;
+            texCoordVaryingType = kVec3f_GrSLType;
         }
     }
-    GrAssert(builder->fVaryingDims > 0);
+    const char *varyingVSName, *varyingFSName;
+    builder->addVarying(texCoordVaryingType,
+                        "Stage",
+                        &varyingVSName,
+                        &varyingFSName);
+    builder->setupTextureAccess(varyingFSName, texCoordVaryingType);
 
-    // Must setup variables after computing segments->fVaryingDims
-    if (NULL != customStage) {
-        customStage->setupVariables(builder);
-    }
+    // Must setup variables after calling setupTextureAccess
+    customStage->setupVariables(builder);
 
     const char* samplerName;
     uniforms.fSamplerUniforms.push_back(builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
@@ -1036,45 +1041,29 @@
                                                             "Sampler",
                                                             &samplerName));
 
-    const char *varyingVSName, *varyingFSName;
-    builder->addVarying(GrSLFloatVectorType(builder->fVaryingDims),
-                        "Stage",
-                        &varyingVSName,
-                        &varyingFSName);
-
     if (!matName) {
-        GrAssert(builder->fVaryingDims == builder->fCoordDims);
+        GrAssert(kVec2f_GrSLType == texCoordVaryingType);
         builder->fVSCode.appendf("\t%s = %s;\n", varyingVSName, vsInCoord);
     } else {
         // varying = texMatrix * texCoord
         builder->fVSCode.appendf("\t%s = (%s * vec3(%s, 1))%s;\n",
                                   varyingVSName, matName, vsInCoord,
-                                  vector_all_coords(builder->fVaryingDims));
+                                  vector_all_coords(GrSLTypeToVecLength(texCoordVaryingType)));
     }
 
-    if (NULL != customStage) {
-        builder->fVSCode.appendf("\t{ // stage %d %s\n",
-                                 stageNum, customStage->name());
-        customStage->emitVS(builder, varyingVSName);
-        builder->fVSCode.appendf("\t}\n");
-    }
-
-    /// Fragment Shader Stuff
-
-    builder->fSampleCoords = varyingFSName;
-
-    builder->setupTextureAccess(stageNum);
+    builder->fVSCode.appendf("\t{ // stage %d %s\n",
+                                stageNum, customStage->name());
+    customStage->emitVS(builder, varyingVSName);
+    builder->fVSCode.appendf("\t}\n");
 
     builder->computeSwizzle(desc.fInConfigFlags);
     builder->computeModulate(fsInColor);
 
-    if (NULL != customStage) {
-        // Enclose custom code in a block to avoid namespace conflicts
-        builder->fFSCode.appendf("\t{ // stage %d %s \n",
-                                 stageNum, customStage->name());
-        customStage->emitFS(builder, fsOutColor, fsInColor,
-                            samplerName);
-        builder->fFSCode.appendf("\t}\n");
-    }
+    // Enclose custom code in a block to avoid namespace conflicts
+    builder->fFSCode.appendf("\t{ // stage %d %s \n",
+                                stageNum, customStage->name());
+    customStage->emitFS(builder, fsOutColor, fsInColor,
+                        samplerName);
+    builder->fFSCode.appendf("\t}\n");
     builder->setNonStage();
 }
diff --git a/src/gpu/gl/GrGLSL.cpp b/src/gpu/gl/GrGLSL.cpp
index ff4d498..f1f7d92 100644
--- a/src/gpu/gl/GrGLSL.cpp
+++ b/src/gpu/gl/GrGLSL.cpp
@@ -80,9 +80,16 @@
     return HOMOGS[count];
 }
 
+const char* GrGLSLVectorHomogCoord(GrSLType type) {
+    return GrGLSLVectorHomogCoord(GrSLTypeToVecLength(type));
+}
+
 const char* GrGLSLVectorNonhomogCoords(int count) {
     static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"};
     GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS));
     return NONHOMOGS[count];
 }
 
+const char* GrGLSLVectorNonhomogCoord(GrSLType type) {
+    return GrGLSLVectorNonhomogCoords(GrSLTypeToVecLength(type));
+}
diff --git a/src/gpu/gl/GrGLSL.h b/src/gpu/gl/GrGLSL.h
index d766dd9..f69385f 100644
--- a/src/gpu/gl/GrGLSL.h
+++ b/src/gpu/gl/GrGLSL.h
@@ -45,6 +45,23 @@
     kSampler2D_GrSLType
 };
 
+namespace {
+inline int GrSLTypeToVecLength(GrSLType type) {
+    static const int kVecLengths[] = {
+        0, // kVoid_GrSLType
+        1, // kFloat_GrSLType
+        2, // kVec2f_GrSLType
+        3, // kVec3f_GrSLType
+        4, // kVec4f_GrSLType
+        1, // kMat33f_GrSLType
+        1, // kMat44f_GrSLType
+        1, // kSampler2D_GrSLType
+    };
+    GrAssert((size_t) type < GR_ARRAY_COUNT(kVecLengths));
+    return kVecLengths[type];
+}
+}
+
 /**
  * Gets the most recent GLSL Generation compatible with the OpenGL context.
  */
@@ -82,11 +99,12 @@
 GrSLType GrSLFloatVectorType(int count);
 
 /** Return the GLSL swizzle operator for a homogenous component of a vector
-    with the given number of coordnates, e.g. 2 -> ".y", 3 -> ".z" */
+    with the given number of coordinates, e.g. 2 -> ".y", 3 -> ".z" */
 const char* GrGLSLVectorHomogCoord(int count);
+const char* GrGLSLVectorHomogCoord(GrSLType type);
 
 /** Return the GLSL swizzle operator for a nonhomogenous components of a vector
-    with the given number of coordnates, e.g. 2 -> ".x", 3 -> ".xy" */
+    with the given number of coordinates, e.g. 2 -> ".x", 3 -> ".xy" */
 const char* GrGLSLVectorNonhomogCoords(int count);
-
+const char* GrGLSLVectorNonhomogCoords(GrSLType type);
 #endif
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 2243a7c..5aa3a54 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -22,29 +22,25 @@
 typedef GrGLUniformManager::UniformHandle UniformHandle;
 ///////////////////////////////////////////////////////////////////////////////
 
-static SkString build_sampler_string(GrGLShaderBuilder::SamplerMode samplerMode) {
-    SkString sampler("texture2D");
-    switch (samplerMode) {
-      case GrGLShaderBuilder::kDefault_SamplerMode:
-          break;
-      case GrGLShaderBuilder::kProj_SamplerMode:
-          sampler.append("Proj");
-          break;
-      case GrGLShaderBuilder::kExplicitDivide_SamplerMode:
-          break;
-    }
+namespace {
 
-    return sampler;
+inline const char* sample_function_name(GrSLType type) {
+    if (kVec2f_GrSLType == type) {
+        return "texture2D";
+    } else {
+        GrAssert(kVec3f_GrSLType == type);
+        return "texture2DProj";
+    }
 }
 
-static bool texture_requires_alpha_to_red_swizzle(const GrGLCaps& caps,
+inline bool texture_requires_alpha_to_red_swizzle(const GrGLCaps& caps,
                                                   const GrTextureAccess& access) {
     return GrPixelConfigIsAlphaOnly(access.getTexture()->config()) && caps.textureRedSupport() &&
         access.referencesAlpha();
 }
 
-static SkString build_swizzle_string(const GrTextureAccess& textureAccess,
-                                     const GrGLCaps& caps) {
+SkString build_swizzle_string(const GrTextureAccess& textureAccess,
+                              const GrGLCaps& caps) {
     const GrTextureAccess::Swizzle& swizzle = textureAccess.getSwizzle();
     if (0 == swizzle[0]) {
         return SkString("");
@@ -63,6 +59,8 @@
     return swizzleOut;
 }
 
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 // Architectural assumption: always 2-d input coords.
@@ -79,8 +77,7 @@
     , fFSInputs(kVarsPerBlock)
     , fFSOutputs(kMaxFSOutputs)
     , fUsesGS(false)
-    , fVaryingDims(0)
-    , fComplexCoord(false)
+    , fTexCoordVaryingType(kVoid_GrSLType)
     , fContext(ctx)
     , fUniformManager(uniformManager)
     , fCurrentStage(kNonStageIdx) {
@@ -107,65 +104,59 @@
     }
 }
 
-void GrGLShaderBuilder::setupTextureAccess(int stageNum) {
-    SkString retval;
-
-    SamplerMode mode = kDefault_SamplerMode;
-    // FIXME: we aren't currently using Proj.
-    if (fVaryingDims != fCoordDims) {
-        mode = kExplicitDivide_SamplerMode;
+void GrGLShaderBuilder::setupTextureAccess(const char* varyingFSName, GrSLType varyingType) {
+    // FIXME: We don't know how the custom stage will manipulate the coords. So we give up on using
+    // projective texturing and always give the stage 2D coords. This will be fixed when custom
+    // stages are repsonsible for setting up their own tex coords / tex matrices.
+    switch (varyingType) {
+        case kVec2f_GrSLType:
+            fDefaultTexCoordsName = varyingFSName;
+            fTexCoordVaryingType = kVec2f_GrSLType;
+            break;
+        case kVec3f_GrSLType: {
+            fDefaultTexCoordsName = "inCoord";
+            GrAssert(kNonStageIdx != fCurrentStage);
+            fDefaultTexCoordsName.appendS32(fCurrentStage);
+            fTexCoordVaryingType = kVec3f_GrSLType;
+            fFSCode.appendf("\t%s %s = %s.xy / %s.z;\n",
+                            GrGLShaderVar::TypeString(kVec2f_GrSLType),
+                            fDefaultTexCoordsName.c_str(),
+                            varyingFSName,
+                            varyingFSName);
+            break;
+        }
+        default:
+            GrCrash("Tex coords must either be Vec2f or Vec3f");
     }
-
-    switch (mode) {
-        case kDefault_SamplerMode:
-            GrAssert(fVaryingDims == fCoordDims);
-            // Do nothing
-            break;
-        case kProj_SamplerMode:
-            // Do nothing
-            break;
-        case kExplicitDivide_SamplerMode:
-            retval = "inCoord";
-            retval.appendS32(stageNum);
-            fFSCode.appendf("\t%s %s = %s%s / %s%s;\n",
-                GrGLShaderVar::TypeString
-                    (GrSLFloatVectorType(fCoordDims)),
-                retval.c_str(),
-                fSampleCoords.c_str(),
-                GrGLSLVectorNonhomogCoords(fVaryingDims),
-                fSampleCoords.c_str(),
-                GrGLSLVectorHomogCoord(fVaryingDims));
-            fSampleCoords = retval;
-            break;
-    }
-    fTexFunc = build_sampler_string(mode);
-    fComplexCoord = false;
 }
 
 void GrGLShaderBuilder::emitTextureLookup(const char* samplerName,
-                                          const char* coordName) {
+                                          const char* coordName,
+                                          GrSLType varyingType) {
     if (NULL == coordName) {
-        coordName = fSampleCoords.c_str();
+        coordName = fDefaultTexCoordsName.c_str();
+        varyingType = kVec2f_GrSLType;
     }
-    fFSCode.appendf("%s(%s, %s)", fTexFunc.c_str(), samplerName, coordName);
+    fFSCode.appendf("%s(%s, %s)", sample_function_name(varyingType), samplerName, coordName);
 }
 
-void GrGLShaderBuilder::emitDefaultFetch(const char* outColor,
-                                         const char* samplerName) {
+void GrGLShaderBuilder::emitTextureLookupAndModulate(const char* outColor,
+                                                     const char* samplerName,
+                                                     const char* coordName,
+                                                     GrSLType varyingType) {
     fFSCode.appendf("\t%s = ", outColor);
-    this->emitTextureLookup(samplerName);
+    this->emitTextureLookup(samplerName, coordName, varyingType);
     fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
 }
 
-void GrGLShaderBuilder::emitCustomTextureLookup(SamplerMode samplerMode,
-                                                const GrTextureAccess& textureAccess,
+void GrGLShaderBuilder::emitCustomTextureLookup(const GrTextureAccess& textureAccess,
                                                 const char* samplerName,
-                                                const char* coordName) {
+                                                const char* coordName,
+                                                GrSLType varyingType) {
     GrAssert(samplerName && coordName);
-    SkString sampler = build_sampler_string(samplerMode);
     SkString swizzle = build_swizzle_string(textureAccess, fContext.caps());
 
-    fFSCode.appendf("%s( %s, %s)%s;\n", sampler.c_str(), samplerName,
+    fFSCode.appendf("%s( %s, %s)%s;\n", sample_function_name(varyingType), samplerName,
                     coordName, swizzle.c_str());
 }
 
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 31d603a..66de5ab 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -23,7 +23,6 @@
 class GrGLShaderBuilder {
 
 public:
-
     enum ShaderType {
         kVertex_ShaderType   = 0x1,
         kGeometry_ShaderType = 0x2,
@@ -35,36 +34,45 @@
     void computeSwizzle(uint32_t configFlags);
     void computeModulate(const char* fsInColor);
 
-    // TODO: needs a better name
-    enum SamplerMode {
-        kDefault_SamplerMode,
-        kProj_SamplerMode,
-        kExplicitDivide_SamplerMode  // must do an explicit divide
-    };
-
     /** Determines whether we should use texture2D() or texture2Dproj(), and if an explicit divide
         is required for the sample coordinates, creates the new variable and emits the code to
-        initialize it. */
-    void setupTextureAccess(int stageNum);
+        initialize it. This should only be called by GrGLProgram.*/
+    void setupTextureAccess(const char* varyingFSName, GrSLType varyingType);
 
     /** texture2D(samplerName, coordName), with projection if necessary; if coordName is not
-        specified, uses fSampleCoords. */
+        specified, uses fSampleCoords. coordType must either be Vec2f or Vec3f. The latter is
+        interpreted as projective texture coords. */
     void emitTextureLookup(const char* samplerName,
-                           const char* coordName = NULL);
+                           const char* coordName = NULL,
+                           GrSLType coordType = kVec2f_GrSLType);
 
-    /** sets outColor to results of texture lookup, with swizzle, and/or modulate as necessary */
-    void emitDefaultFetch(const char* outColor,
-                          const char* samplerName);
+    /** sets outColor to results of texture lookup, with swizzle, and/or modulate as necessary. If
+    coordName is NULL then it as if defaultTexCoordsName() was passed. coordType must be either
+    kVec2f or kVec3f. */
+    void emitTextureLookupAndModulate(const char* outColor,
+                                      const char* samplerName,
+                                      const char* coordName = NULL,
+                                      GrSLType coordType = kVec2f_GrSLType);
+
+    /** Gets the name of the default texture coords which are always kVec2f */
+    const char* defaultTexCoordsName() const { return fDefaultTexCoordsName.c_str(); }
+
+    /* Returns true if the texture matrix from which the default texture coords are computed has
+       perspective. */
+    bool defaultTextureMatrixIsPerspective() const {
+        return fTexCoordVaryingType == kVec3f_GrSLType;
+    }
 
     /** Emits a texture lookup to the shader code with the form:
           texture2D{Proj}(samplerName, coordName).swizzle
         The routine selects the type of texturing based on samplerMode.
         The generated swizzle state is built based on the format of the texture and the requested
-        swizzle access pattern. */
-    void emitCustomTextureLookup(SamplerMode samplerMode,
-                                 const GrTextureAccess& textureAccess,
+        swizzle access pattern.  coordType must either be Vec2f or Vec3f. The latter is interpreted
+        as projective texture coords.*/
+    void emitCustomTextureLookup(const GrTextureAccess& textureAccess,
                                  const char* samplerName,
-                                 const char* coordName);
+                                 const char* coordName,
+                                 GrSLType coordType = kVec2f_GrSLType);
 
     /** Emits a helper function outside of main(). Currently ShaderType must be
         kFragment_ShaderType. */
@@ -162,19 +170,9 @@
     /// Per-stage settings - only valid while we're inside GrGLProgram::genStageCode().
     //@{
 
-    int              fVaryingDims;
-    static const int fCoordDims = 2;
-
-    /// True if fSampleCoords is an expression; false if it's a bare
-    /// variable name
-    bool             fComplexCoord;
-    SkString         fSampleCoords;
-
     SkString         fSwizzle;
     SkString         fModulate;
 
-    SkString         fTexFunc;
-
     //@}
 
 private:
@@ -186,6 +184,14 @@
     GrGLUniformManager&     fUniformManager;
     int                     fCurrentStage;
     SkString                fFSFunctions;
+
+    /// Per-stage settings - only valid while we're inside GrGLProgram::genStageCode().
+    //@{
+    GrSLType         fTexCoordVaryingType;  // the type, either Vec2f or Vec3f, of the coords passed
+                                            // as a varying from the VS to the FS.
+    SkString         fDefaultTexCoordsName; // the name of the default 2D coords value.
+    //@}
+
 };
 
 #endif