Move swizzle & modulation computation, non-virtual functions onto
GrGLShaderBuilder. This lets us access all the default computations
when there's no GrCustomStage specified, and means that GrGLProgramStage
is effectively an interface class, all of whose functions can/should
be overriden.

http://codereview.appspot.com/6242051/



git-svn-id: http://skia.googlecode.com/svn/trunk@4045 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/effects/GrConvolutionEffect.cpp b/src/gpu/effects/GrConvolutionEffect.cpp
index 8ccf585..15f2aeb 100644
--- a/src/gpu/effects/GrConvolutionEffect.cpp
+++ b/src/gpu/effects/GrConvolutionEffect.cpp
@@ -124,7 +124,7 @@
                   fKernelWidth);
 
     code->appendf("\t\t\tsum += ");
-    this->emitTextureLookup(code, samplerName, "coord");
+    state->emitTextureLookup(samplerName, "coord");
     code->appendf(" * %s;\n", kernelIndex.c_str());
 
     code->appendf("\t\t\tcoord += %s;\n",
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 8fc3ac2..2fdcd77 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -1405,10 +1405,8 @@
               GrGLProgram::StageUniLocations* locations,
               const char* samplerName,
               const char* texelSizeName,
-              const char* swizzle,
               const char* fsOutColor,
-              GrStringBuilder& texFunc,
-              GrStringBuilder& modulate) {
+              GrStringBuilder& texFunc) {
     locations->fNormalizedTexelSizeUni = kUseUniform;
     if (segments->fComplexCoord) {
         // assign the coord to a var rather than compute 4x.
@@ -1422,11 +1420,11 @@
     GrAssert(2 == segments->fCoordDims);
     GrStringBuilder accumVar("accum");
     accumVar.appendS32(stageNum);
-    segments->fFSCode.appendf("\tvec4 %s  = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, swizzle);
-    segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, swizzle);
-    segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, swizzle);
-    segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, swizzle);
-    segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), modulate.c_str());
+    segments->fFSCode.appendf("\tvec4 %s  = %s(%s, %s + vec2(-%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str());
+    segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,-%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str());
+    segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(-%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str());
+    segments->fFSCode.appendf("\t%s += %s(%s, %s + vec2(+%s.x,+%s.y))%s;\n", accumVar.c_str(), texFunc.c_str(), samplerName, segments->fSampleCoords.c_str(), texelSizeName, texelSizeName, segments->fSwizzle.c_str());
+    segments->fFSCode.appendf("\t%s = .25 * %s%s;\n", fsOutColor, accumVar.c_str(), segments->fModulate.c_str());
 
 }
 
@@ -1456,11 +1454,9 @@
                      const StageDesc& desc,
                      GrGLShaderBuilder* segments,
                      const char* samplerName,
-                     const char* swizzle,
                      const char* imageIncrementName,
                      const char* fsOutColor,
-                     GrStringBuilder& texFunc,
-                     GrStringBuilder& modulate) {
+                     GrStringBuilder& texFunc) {
     GrStringBuilder valueVar("value");
     valueVar.appendS32(stageNum);
     GrStringBuilder coordVar("coord");
@@ -1482,13 +1478,14 @@
     segments->fFSCode.appendf("\t\t%s = %s(%s, %s(%s, %s)%s);\n",
                               valueVar.c_str(), isDilate ? "max" : "min",
                               valueVar.c_str(), texFunc.c_str(),
-                              samplerName, coordVar.c_str(), swizzle);
+                              samplerName, coordVar.c_str(),
+                              segments->fSwizzle.c_str());
     segments->fFSCode.appendf("\t\t%s += %s;\n",
                               coordVar.c_str(),
                               imageIncrementName);
     segments->fFSCode.appendf("\t}\n");
     segments->fFSCode.appendf("\t%s = %s%s;\n", fsOutColor,
-                              valueVar.c_str(), modulate.c_str());
+                              valueVar.c_str(), segments->fModulate.c_str());
 }
 
 }
@@ -1660,25 +1657,8 @@
         (StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
          StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
 
-    const char* swizzle = "";
-    if (desc.fInConfigFlags & StageDesc::kSwapRAndB_InConfigFlag) {
-        GrAssert(!(desc.fInConfigFlags & StageDesc::kSmearAlpha_InConfigFlag));
-        GrAssert(!(desc.fInConfigFlags & StageDesc::kSmearRed_InConfigFlag));
-        swizzle = ".bgra";
-    } else if (desc.fInConfigFlags & StageDesc::kSmearAlpha_InConfigFlag) {
-        GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
-        GrAssert(!(desc.fInConfigFlags & StageDesc::kSmearRed_InConfigFlag));
-        swizzle = ".aaaa";
-    } else if (desc.fInConfigFlags & StageDesc::kSmearRed_InConfigFlag) {
-        GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
-        GrAssert(!(desc.fInConfigFlags & StageDesc::kSmearAlpha_InConfigFlag));
-        swizzle = ".rrrr";
-    }
-
-    GrStringBuilder modulate;
-    if (NULL != fsInColor) {
-        modulate.printf(" * %s", fsInColor);
-    }
+    segments->computeSwizzle(desc.fInConfigFlags);
+    segments->computeModulate(fsInColor);
 
     if (desc.fOptFlags &
         StageDesc::kCustomTextureDomain_OptFlagBit) {
@@ -1697,14 +1677,24 @@
         locations->fTexDomUni = kUseUniform;
     }
 
+    if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
+                          StageDesc::kNoPerspective_OptFlagBit)) {
+        segments->setSamplerMode(GrGLShaderBuilder::kDefault_SamplerMode);
+    } else if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
+               StageDesc::kSingle_FetchMode == desc.fFetchMode) {
+        segments->setSamplerMode(GrGLShaderBuilder::kProj_SamplerMode);
+    } else {
+        segments->setSamplerMode(
+            GrGLShaderBuilder::kExplicitDivide_SamplerMode);
+    }
+
     // NOTE: GrGLProgramStages are now responsible for fetching
     if (NULL == customStage) {
         switch (desc.fFetchMode) {
         case StageDesc::k2x2_FetchMode:
             GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
             gen2x2FS(stageNum, segments, locations,
-                samplerName, texelSizeName, swizzle, fsOutColor,
-                texFunc, modulate);
+                samplerName, texelSizeName, fsOutColor, texFunc);
             break;
         case StageDesc::kConvolution_FetchMode:
             GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
@@ -1713,8 +1703,7 @@
         case StageDesc::kErode_FetchMode:
             GrAssert(!(desc.fInConfigFlags & kMulByAlphaMask));
             genMorphologyFS(stageNum, desc, segments,
-                samplerName, swizzle, imageIncrementName, fsOutColor,
-                texFunc, modulate);
+                samplerName, imageIncrementName, fsOutColor, texFunc);
             break;
         default:
             if (desc.fInConfigFlags & kMulByAlphaMask) {
@@ -1728,43 +1717,28 @@
                                           fsOutColor, texFunc.c_str(), 
                                           samplerName,
                                           segments->fSampleCoords.c_str(),
-                                          swizzle);
+                                          segments->fSwizzle.c_str());
                 if (desc.fInConfigFlags &
                     StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag) {
                     segments->fFSCode.appendf("\t%s = vec4(ceil(%s.rgb*%s.a*255.0)/255.0,%s.a)%s;\n",
                                               fsOutColor, fsOutColor, fsOutColor,
-                                              fsOutColor, modulate.c_str());
+                                              fsOutColor, segments->fModulate.c_str());
                 } else {
                     segments->fFSCode.appendf("\t%s = vec4(floor(%s.rgb*%s.a*255.0)/255.0,%s.a)%s;\n",
                                               fsOutColor, fsOutColor, fsOutColor,
-                                              fsOutColor, modulate.c_str());
+                                              fsOutColor, segments->fModulate.c_str());
                 }
             } else {
-                segments->fFSCode.appendf("\t%s = %s(%s, %s)%s%s;\n",
-                                          fsOutColor, texFunc.c_str(), 
-                                          samplerName, 
-                                          segments->fSampleCoords.c_str(),
-                                          swizzle, modulate.c_str());
+                segments->emitDefaultFetch(fsOutColor, samplerName);
             }
         }
     }
 
     if (NULL != customStage) {
-        if (desc.fOptFlags & (StageDesc::kIdentityMatrix_OptFlagBit |
-                              StageDesc::kNoPerspective_OptFlagBit)) {
-            customStage->setSamplerMode(GrGLProgramStage::kDefault_SamplerMode);
-        } else if (StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
-                   StageDesc::kSingle_FetchMode == desc.fFetchMode) {
-            customStage->setSamplerMode(GrGLProgramStage::kProj_SamplerMode);
-        } else {
-            customStage->setSamplerMode(
-                GrGLProgramStage::kExplicitDivide_SamplerMode);
-        }
-
         // Enclose custom code in a block to avoid namespace conflicts
         segments->fFSCode.appendf("\t{ // stage %d %s \n",
                                   stageNum, customStage->name());
-        customStage->emitTextureSetup(segments);
+        segments->emitTextureSetup();
         customStage->emitFS(segments, fsOutColor, fsInColor, samplerName);
         segments->fFSCode.appendf("\t}\n");
     }
diff --git a/src/gpu/gl/GrGLProgramStage.cpp b/src/gpu/gl/GrGLProgramStage.cpp
index b5e2228..96c6e55 100644
--- a/src/gpu/gl/GrGLProgramStage.cpp
+++ b/src/gpu/gl/GrGLProgramStage.cpp
@@ -41,55 +41,3 @@
 
 }
 
-void GrGLProgramStage::emitTextureSetup(GrGLShaderBuilder* segments) {
-    GrStringBuilder retval;
-
-    switch (fSamplerMode) {
-        case kDefault_SamplerMode:
-            // Fall through
-        case kProj_SamplerMode:
-            // Do nothing
-            break;
-        case kExplicitDivide_SamplerMode:
-            retval = "inCoord";
-            segments->fFSCode.appendf("\t %s %s = %s%s / %s%s\n",
-                GrGLShaderVar::TypeString
-                    (GrSLFloatVectorType(segments->fCoordDims)),
-                retval.c_str(),
-                segments->fSampleCoords.c_str(),
-                GrGLSLVectorNonhomogCoords(segments->fVaryingDims),
-                segments->fSampleCoords.c_str(),
-                GrGLSLVectorHomogCoord(segments->fVaryingDims));
-            segments->fSampleCoords = retval;
-            break;
-    }
-}
-
-void GrGLProgramStage::emitTextureLookup(GrStringBuilder* code,
-                                         const char* samplerName,
-                                         const char* coordName) {
-    switch (fSamplerMode) {
-        case kDefault_SamplerMode:
-            // Fall through
-        case kExplicitDivide_SamplerMode:
-            code->appendf("texture2D(%s, %s)", samplerName, coordName);
-            break;
-        case kProj_SamplerMode:
-            code->appendf("texture2DProj(%s, %s)", samplerName, coordName);
-            break;
-    }
-
-}
-
-void GrGLProgramStage::emitDefaultFetch(GrGLShaderBuilder* state,
-                                        const char* fsOutColor,
-                                        const char* samplerName,
-                                        const char* swizzle,
-                                        const char* modulate) {
-    state->fFSCode.appendf("\t%s = ", fsOutColor);
-    this->emitTextureLookup(&state->fFSCode, samplerName,
-                            state->fSampleCoords.c_str());
-    state->fFSCode.appendf("%s%s;\n", swizzle, modulate);
-}
-
-
diff --git a/src/gpu/gl/GrGLProgramStage.h b/src/gpu/gl/GrGLProgramStage.h
index 60ab60d..0d2d660 100644
--- a/src/gpu/gl/GrGLProgramStage.h
+++ b/src/gpu/gl/GrGLProgramStage.h
@@ -96,43 +96,10 @@
                          GrCustomStage* stage,
                          int stageNum);
 
-    // TODO: needs a better name
-    enum SamplerMode {
-        kDefault_SamplerMode,
-        kProj_SamplerMode,
-        kExplicitDivide_SamplerMode  // must do an explicit divide
-    };
-
-    void setSamplerMode(SamplerMode samplerMode) { fSamplerMode = samplerMode; }
-
-    /** Does perspective divide or other necessary transform, then
-        updates the name of the sample coordinates. */
-    void emitTextureSetup(GrGLShaderBuilder* segments);
-
-     /** Human-meaningful string to identify this effect; may be embedded
-         in generated shader code. Because the implementation is delegated to
-         the factory, the name will be the same as that of the generating
-         GrCustomStage. */
     const char* name() const { return fFactory.name(); }
 
 protected:
 
-    /** Convenience function for subclasses to write texture2D() or
-        texture2DProj(), depending on fSamplerMode. */
-    void emitTextureLookup(GrStringBuilder* code,
-                           const char* samplerName,
-                           const char* coordName);
-
-    /** Standard texture fetch, complete with swizzle & modulate if
-        appropriate. */
-    void emitDefaultFetch(GrGLShaderBuilder* state,
-                          const char* fsOutColor,
-                          const char* samplerName,
-                          const char* swizzle,
-                          const char* modulate);
-
-    SamplerMode fSamplerMode;
-
     const GrProgramStageFactory& fFactory;
 };
 
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index 321e507..289e7be 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "gl/GrGLShaderBuilder.h"
+#include "gl/GrGLProgram.h"
 
 namespace {
 
@@ -33,6 +34,7 @@
     , fFSOutputs(sMaxFSOutputs)
     , fUsesGS(false)
     , fVaryingDims(0)
+    , fSamplerMode(kDefault_SamplerMode)
     , fComplexCoord(false) {
 
 }
@@ -85,3 +87,87 @@
     nameWithStage.appendS32(stageNum);
     this->appendVarying(type, nameWithStage.c_str(), vsOutName, fsInName);
 }
+
+void GrGLShaderBuilder::computeSwizzle(uint32_t configFlags) {
+   static const uint32_t kMulByAlphaMask =
+        (GrGLProgram::StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag |
+         GrGLProgram::StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag);
+
+    fSwizzle = "";
+    if (configFlags & GrGLProgram::StageDesc::kSwapRAndB_InConfigFlag) {
+        GrAssert(!(configFlags &
+                   GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
+        GrAssert(!(configFlags &
+                   GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
+        fSwizzle = ".bgra";
+    } else if (configFlags & GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag) {
+        GrAssert(!(configFlags & kMulByAlphaMask));
+        GrAssert(!(configFlags &
+                   GrGLProgram::StageDesc::kSmearRed_InConfigFlag));
+        fSwizzle = ".aaaa";
+    } else if (configFlags & GrGLProgram::StageDesc::kSmearRed_InConfigFlag) {
+        GrAssert(!(configFlags & kMulByAlphaMask));
+        GrAssert(!(configFlags &
+                   GrGLProgram::StageDesc::kSmearAlpha_InConfigFlag));
+        fSwizzle = ".rrrr";
+    }
+}
+
+void GrGLShaderBuilder::computeModulate(const char* fsInColor) {
+    if (NULL != fsInColor) {
+        fModulate.printf(" * %s", fsInColor);
+    }
+}
+
+void GrGLShaderBuilder::emitTextureSetup() {
+    GrStringBuilder retval;
+
+    switch (fSamplerMode) {
+        case kDefault_SamplerMode:
+            // Fall through
+        case kProj_SamplerMode:
+            // Do nothing
+            break;
+        case kExplicitDivide_SamplerMode:
+            retval = "inCoord";
+            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;
+    }
+}
+
+void GrGLShaderBuilder::emitTextureLookup(const char* samplerName,
+                                          const char* coordName) {
+    if (NULL == coordName) {
+        coordName = fSampleCoords.c_str();
+    }
+    switch (fSamplerMode) {
+        default:
+            SkDEBUGFAIL("Unknown sampler mode");
+            // Fall through
+        case kDefault_SamplerMode:
+            // Fall through
+        case kExplicitDivide_SamplerMode:
+            fFSCode.appendf("texture2D(%s, %s)", samplerName, coordName);
+            break;
+        case kProj_SamplerMode:
+            fFSCode.appendf("texture2DProj(%s, %s)", samplerName, coordName);
+            break;
+    }
+
+}
+
+void GrGLShaderBuilder::emitDefaultFetch(const char* outColor,
+                                         const char* samplerName) {
+    fFSCode.appendf("\t%s = ", outColor);
+    this->emitTextureLookup(samplerName);
+    fFSCode.appendf("%s%s;\n", fSwizzle.c_str(), fModulate.c_str());
+}
+
diff --git a/src/gpu/gl/GrGLShaderBuilder.h b/src/gpu/gl/GrGLShaderBuilder.h
index 6a7e279..889219d 100644
--- a/src/gpu/gl/GrGLShaderBuilder.h
+++ b/src/gpu/gl/GrGLShaderBuilder.h
@@ -37,6 +37,38 @@
                        const char** vsOutName = NULL,
                        const char** fsInName = NULL);
 
+    void computeSwizzle(uint32_t configFlags);
+    void computeModulate(const char* fsInColor);
+
+    void emitTextureSetup();
+
+    /** texture2D(samplerName, coordName), with projection
+        if necessary; if coordName is not specified,
+        uses fSampleCoords. */
+    void emitTextureLookup(const char* samplerName,
+                           const char* coordName = NULL);
+
+    /** sets outColor to results of texture lookup, with
+        swizzle, and/or modulate as necessary */
+    void emitDefaultFetch(const char* outColor,
+                          const char* samplerName);
+
+    // TODO: needs a better name
+    enum SamplerMode {
+        kDefault_SamplerMode,
+        kProj_SamplerMode,
+        kExplicitDivide_SamplerMode  // must do an explicit divide
+    };
+
+    // TODO: computing this requires information about fetch mode
+    // && coord mapping, as well as StageDesc::fOptFlags - proably
+    // need to set up default value and have some custom stages
+    // override as necessary?
+    void setSamplerMode(SamplerMode samplerMode) {
+        fSamplerMode = samplerMode;
+    }
+
+
     GrStringBuilder fHeader; // VS+FS, GLSL version, etc
     VarArray        fVSUnis;
     VarArray        fVSAttrs;
@@ -53,16 +85,26 @@
     GrStringBuilder fFSCode;
     bool            fUsesGS;
 
-    /// Per-stage settings
+    /// Per-stage settings - only valid while we're inside
+    /// GrGLProgram::genStageCode().
     //@{
 
-    int             fVaryingDims;
+    int              fVaryingDims;
     static const int fCoordDims = 2;
 
+protected:
+
+    SamplerMode      fSamplerMode;
+
+public:
+
     /// True if fSampleCoords is an expression; false if it's a bare
     /// variable name
-    bool            fComplexCoord;
-    GrStringBuilder fSampleCoords;
+    bool             fComplexCoord;
+    GrStringBuilder  fSampleCoords;
+
+    GrStringBuilder  fSwizzle;
+    GrStringBuilder  fModulate;
 
     //@}