Hooks up the GrCustomStage/GrGLProgramStageFactory/GrGLProgramStage
classes from r3726 so they can be used. Does not implement any actual
effect stages.

Has one large known bug: if custom stages are provided, GrSamplerState
comparisons will break; this should preserve correct drawing, but decrease
performance - among other things, we'll break draw batching. To fix this
we'll need a RTTI system for GrCustomState objects, and we'll need to change
the GrSamplerState comparison from a memcmp to something that also does a
deep type-sensitive compare of any GrCustomState objects present.

http://codereview.appspot.com/6074043/



git-svn-id: http://skia.googlecode.com/svn/trunk@3742 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 16a60ce..fb98b4d 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -10,6 +10,8 @@
 #include "GrGLProgram.h"
 
 #include "../GrAllocator.h"
+#include "GrCustomStage.h"
+#include "GrGLProgramStage.h"
 #include "GrGLShaderVar.h"
 #include "SkTrace.h"
 #include "SkXfermode.h"
@@ -620,8 +622,17 @@
     }
 }
 
+// If this destructor is in the header file, we must include GrGLProgramStage
+// instead of just forward-declaring it.
+GrGLProgram::CachedData::~CachedData() {
+    for (int i = 0; i < GrDrawState::kNumStages; ++i) {
+        delete fCustomStage[i];
+    }
+}
+
 
 bool GrGLProgram::genProgram(const GrGLContextInfo& gl,
+                             GrCustomStage** customStages,
                              GrGLProgram::CachedData* programData) const {
 
     ShaderCodeSegments segments;
@@ -733,6 +744,21 @@
     }
 
     ///////////////////////////////////////////////////////////////////////////
+    // Convert generic effect representation to GL-specific backend so they
+    // can be accesseed in genStageCode() and in subsequent uses of
+    // programData.
+    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
+        GrCustomStage* customStage = customStages[s];
+        if (NULL != customStage) {
+            GrGLProgramStageFactory* factory = customStage->getGLFactory();
+            programData->fCustomStage[s] =
+                factory->createGLInstance(customStage);
+        } else {
+            programData->fCustomStage[s] = NULL;
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
     // compute the final color
 
     // if we have color stages string them together, feeding the output color
@@ -766,7 +792,8 @@
                                    outColor.c_str(),
                                    inCoords,
                                    &segments,
-                                   &programData->fUniLocations.fStages[s]);
+                                   &programData->fUniLocations.fStages[s],
+                                   programData->fCustomStage[s]);
                 inColor = outColor;
             }
         }
@@ -878,13 +905,14 @@
                         inCoords = texCoordAttrs[tcIdx].c_str();
                     }
 
-                    genStageCode(gl, s,
-                                 fProgramDesc.fStages[s],
-                                 inCoverage.size() ? inCoverage.c_str() : NULL,
-                                 outCoverage.c_str(),
-                                 inCoords,
-                                 &segments,
-                                 &programData->fUniLocations.fStages[s]);
+                    this->genStageCode(gl, s,
+                        fProgramDesc.fStages[s],
+                        inCoverage.size() ? inCoverage.c_str() : NULL,
+                        outCoverage.c_str(),
+                        inCoords,
+                        &segments,
+                        &programData->fUniLocations.fStages[s],
+                        programData->fCustomStage[s]);
                     inCoverage = outCoverage;
                 }
             }
@@ -1348,6 +1376,11 @@
                                                imageIncrementName.c_str()));
                 GrAssert(kUnusedUniform != locations.fImageIncrementUni);
             }
+
+            if (NULL != programData->fCustomStage[s]) {
+                programData->fCustomStage[s]->
+                    initUniforms(gl.interface(), progID);
+            }
         }
     }
     GL_CALL(UseProgram(progID));
@@ -1363,6 +1396,7 @@
         programData->fTextureWidth[s] = -1;
         programData->fTextureHeight[s] = -1;
         programData->fTextureDomain[s].setEmpty();
+        // Must not reset fStageOverride[] here.
     }
     programData->fViewMatrix = GrMatrix::InvalidMatrix();
     programData->fColor = GrColor_ILLEGAL;
@@ -1712,7 +1746,8 @@
                                const char* fsOutColor,
                                const char* vsInCoord,
                                ShaderCodeSegments* segments,
-                               StageUniLocations* locations) const {
+                               StageUniLocations* locations,
+                               GrGLProgramStage* customStage) const {
 
     GrAssert(stageNum >= 0 && stageNum <= GrDrawState::kNumStages);
     GrAssert((desc.fInConfigFlags & StageDesc::kInConfigBitMask) ==
@@ -1723,8 +1758,13 @@
     // gradients.
     static const int coordDims = 2;
     int varyingDims;
+
     /// Vertex Shader Stuff
 
+    if (NULL != customStage) {
+        customStage->setupVSUnis(segments->fVSUnis, stageNum);
+    }
+
     // decide whether we need a matrix to transform texture coords
     // and whether the varying needs a perspective coord.
     const char* matName = NULL;
@@ -1808,7 +1848,20 @@
                         &imageIncrementName, varyingVSName);
     }
 
+    if (NULL != customStage) {
+        GrStringBuilder vertexShader;
+        customStage->emitVS(&vertexShader, varyingVSName);
+        segments->fVSCode.appendf("{\n");
+        segments->fVSCode.append(vertexShader);
+        segments->fVSCode.appendf("}\n");
+    }
+
     /// Fragment Shader Stuff
+
+    if (NULL != customStage) {
+        customStage->setupFSUnis(segments->fFSUnis, stageNum);
+    }
+
     GrStringBuilder fsCoordName;
     // function used to access the shader, may be made projective
     GrStringBuilder texFunc("texture2D");
@@ -1959,6 +2012,31 @@
                                       swizzle, modulate.c_str());
         }
     }
+
+    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);
+        }
+
+        GrStringBuilder fragmentShader;
+        fsCoordName = customStage->emitTextureSetup(
+                          &fragmentShader, varyingFSName,
+                          stageNum, coordDims, varyingDims);
+        customStage->emitFS(&fragmentShader, fsOutColor, fsInColor,
+                            samplerName, fsCoordName.c_str());
+      
+        // Enclose custom code in a block to avoid namespace conflicts
+        segments->fFSCode.appendf("{\n");
+        segments->fFSCode.append(fragmentShader);
+        segments->fFSCode.appendf("}\n");
+    }
 }