Registry-based unit test for custom effects

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



git-svn-id: http://skia.googlecode.com/svn/trunk@4946 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index ebbd267..b04d924 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -301,7 +301,7 @@
     add_helper(outputVar, colorStr.c_str(), constStr.c_str(), fsCode);
 }
 
-void GrGLProgram::genEdgeCoverage(SkString* coverageVar,
+bool GrGLProgram::genEdgeCoverage(SkString* coverageVar,
                                   GrGLShaderBuilder* segments) const {
     if (fDesc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit) {
         const char *vsName, *fsName;
@@ -358,8 +358,10 @@
             break;
         }
         *coverageVar = "edgeAlpha";
+        return true;
     } else {
         coverageVar->reset();
+        return false;
     }
 }
 
@@ -770,7 +772,7 @@
     if (!wroteFragColorZero || Desc::kNone_DualSrcOutput != fDesc.fDualSrcOutput) {
 
         if (!coverageIsZero) {
-            this->genEdgeCoverage(&inCoverage, &builder);
+            bool inCoverageIsScalar  = this->genEdgeCoverage(&inCoverage, &builder);
 
             switch (fDesc.fCoverageInput) {
                 case Desc::kSolidWhite_ColorInput:
@@ -778,9 +780,11 @@
                     break;
                 case Desc::kAttribute_ColorInput:
                     gen_attribute_coverage(&builder, &inCoverage);
+                    inCoverageIsScalar = false;
                     break;
                 case Desc::kUniform_ColorInput:
                     this->genUniformCoverage(&builder, &inCoverage);
+                    inCoverageIsScalar = false;
                     break;
                 default:
                     GrCrash("Unexpected input coverage.");
@@ -793,8 +797,7 @@
                     // create var to hold stage output
                     outCoverage = "coverage";
                     outCoverage.appendS32(s);
-                    builder.fFSCode.appendf("\tvec4 %s;\n",
-                                            outCoverage.c_str());
+                    builder.fFSCode.appendf("\tvec4 %s;\n", outCoverage.c_str());
 
                     const char* inCoords;
                     // figure out what our input coords are
@@ -813,6 +816,13 @@
                         const GrProgramStageFactory& factory = customStages[s]->getFactory();
                         fProgramStage[s] = factory.createGLInstance(*customStages[s]);
                     }
+                    // stages don't know how to deal with a scalar input. (Maybe they should. We 
+                    // could pass a GrGLShaderVar)
+                    if (inCoverageIsScalar) {
+                        builder.fFSCode.appendf("\tvec4 %s4 = vec4(%s);\n", 
+                                                inCoverage.c_str(), inCoverage.c_str());
+                        inCoverage.append("4");
+                    }
                     this->genStageCode(s,
                                        inCoverage.size() ? inCoverage.c_str() : NULL,
                                        outCoverage.c_str(),
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 62c70e5..989b7c6 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -259,8 +259,10 @@
 
     void genUniformCoverage(GrGLShaderBuilder* segments, SkString* inOutCoverage);
 
-    // generates code to compute coverage based on edge AA.
-    void genEdgeCoverage(SkString* coverageVar, GrGLShaderBuilder* builder) const;
+    // generates code to compute coverage based on edge AA. Returns true if edge coverage was
+    // inserted in which case coverageVar will be updated to refer to a scalar. Otherwise,
+    // coverageVar is set to an empty string.
+    bool genEdgeCoverage(SkString* coverageVar, GrGLShaderBuilder* builder) const;
 
     // Creates a GL program ID, binds shader attributes to GL vertex attrs, and links the program
     bool bindOutputsAttribsAndLinkProgram(SkString texCoordAttrNames[GrDrawState::kMaxTexCoords],
diff --git a/src/gpu/gl/GrGLProgramStage.h b/src/gpu/gl/GrGLProgramStage.h
index 8e3a4b1..69095b6 100644
--- a/src/gpu/gl/GrGLProgramStage.h
+++ b/src/gpu/gl/GrGLProgramStage.h
@@ -57,7 +57,12 @@
         on the state.
         The code will be inside an otherwise-empty block.
         Fragment shader inputs are a vec2 of coordinates, one texture,
-        and a color; output is a color. */
+        and a color; output is a color. The input color may be NULL which
+        indicates that the input color is solid white. TODO: Better system
+        for communicating optimization info (e.g. input color is solid white,
+        trans black, known to be opaque, etc.) that allows the custom stage
+        to communicate back similar known info about its output.
+        */
     /* TODO: don't give them the samplerName, just a handle; then give
        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
diff --git a/src/gpu/gl/GrGLShaderBuilder.cpp b/src/gpu/gl/GrGLShaderBuilder.cpp
index fb70556..3ca4086 100644
--- a/src/gpu/gl/GrGLShaderBuilder.cpp
+++ b/src/gpu/gl/GrGLShaderBuilder.cpp
@@ -184,11 +184,7 @@
 GrCustomStage::StageKey GrGLShaderBuilder::KeyForTextureAccess(const GrTextureAccess& access,
                                                                const GrGLCaps& caps) {
     GrCustomStage::StageKey key = 0;
-    
-    if (!access.getTexture()) {
-        return key;
-    }    
-    
+
     // Assume that swizzle support implies that we never have to modify a shader to adjust
     // for texture format/swizzle settings.
     if (caps.textureSwizzleSupport()) {
@@ -277,7 +273,11 @@
         fGSOutputs.push_back();
         fGSOutputs.back().setType(type);
         fGSOutputs.back().setTypeModifier(GrGLShaderVar::kOut_TypeModifier);
-        fGSOutputs.back().accessName()->printf("g%s", name);
+        if (kNonStageIdx == fCurrentStage) {
+            fGSOutputs.back().accessName()->printf("g%s", name);
+        } else {
+            fGSOutputs.back().accessName()->printf("g%s%d", name, fCurrentStage);
+        }
         fsName = fGSOutputs.back().accessName();
     } else {
         fsName = fVSOutputs.back().accessName();