Add 4x4 downsample filter with 4 bilinear texture reads, use for ssaa.

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

git-svn-id: http://skia.googlecode.com/svn/trunk@1250 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index 0365470..ce4f000 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -42,6 +42,8 @@
 
 }  // namespace
 
+#define PRINT_SHADERS 0
+
 #if GR_GL_ATTRIBUTE_MATRICES
     #define VIEW_MATRIX_NAME "aViewM"
 #else
@@ -93,6 +95,11 @@
     s->appendInt(stage);
 }
 
+static void normalized_texel_size_name(int stage, GrStringBuilder* s) {
+    *s = "uTexelSize";
+    s->appendInt(stage);
+}
+
 static void sampler_name(int stage, GrStringBuilder* s) {
     *s = "uSampler";
     s->appendInt(stage);
@@ -172,8 +179,7 @@
     }
 }
 
-void GrGLProgram::genProgram(GrGLProgram::CachedData* programData, 
-                             const GrDrawTarget* target) const {
+void GrGLProgram::genProgram(GrGLProgram::CachedData* programData) const {
 
     ShaderCodeSegments segments;
     const uint32_t& layout = fProgramDesc.fVertexLayout;
@@ -219,7 +225,7 @@
     // add texture coordinates that are used to the list of vertex attr decls
     GrTokenString texCoordAttrs[GrDrawTarget::kMaxTexCoords];
     for (int t = 0; t < GrDrawTarget::kMaxTexCoords; ++t) {
-        if (target->VertexUsesTexCoordIdx(t, layout)) {
+        if (GrDrawTarget::VertexUsesTexCoordIdx(t, layout)) {
             tex_attr_name(t, texCoordAttrs + t);
 
             segments.fVSAttrs += "attribute vec2 ";
@@ -315,11 +321,11 @@
     ++stringCnt;
 
 #if PRINT_SHADERS
-    GrPrintf("%s%s%s%s\n",
-             segments.fVSUnis.cstr(),
-             segments.fVSAttrs.cstr(),
-             segments.fVaryings.cstr(),
-             segments.fVSCode.cstr());
+    GrPrintf(segments.fVSUnis.cstr());
+    GrPrintf(segments.fVSAttrs.cstr());
+    GrPrintf(segments.fVaryings.cstr());
+    GrPrintf(segments.fVSCode.cstr());
+    GrPrintf("\n");
 #endif
     programData->fVShaderID = CompileShader(GR_GL_VERTEX_SHADER,
                                         stringCnt,
@@ -350,11 +356,11 @@
     ++stringCnt;
 
 #if PRINT_SHADERS
-    GrPrintf("%s%s%s%s\n",
-             GR_SHADER_PRECISION,
-             segments.fFSUnis.cstr(),
-             segments.fVaryings.cstr(),
-             segments.fFSCode.cstr());
+    GrPrintf(GrShaderPrecision());
+    GrPrintf(segments.fFSUnis.cstr());
+    GrPrintf(segments.fVaryings.cstr());
+    GrPrintf(segments.fFSCode.cstr());
+    GrPrintf("\n");
 #endif
     programData->fFShaderID = CompileShader(GR_GL_FRAGMENT_SHADER,
                                             stringCnt,
@@ -464,6 +470,16 @@
                 locations.fSamplerUni = -1;
             }
 
+            if (locations.fNormalizedTexelSizeUni) {
+                GrTokenString texelSizeName;
+                normalized_texel_size_name(s, &texelSizeName);
+                locations.fNormalizedTexelSizeUni = 
+                   GR_GL(GetUniformLocation(progID, texelSizeName.cstr()));
+                GrAssert(-1 != locations.fNormalizedTexelSizeUni);
+            } else {
+                locations.fNormalizedTexelSizeUni = -1;
+            }
+
             if (locations.fRadial2Uni) {
                 GrTokenString radial2ParamName;
                 radial2_param_name(s, &radial2ParamName);
@@ -478,6 +494,7 @@
             locations.fSamplerUni = -1;
             locations.fRadial2Uni = -1;
             locations.fTextureMatrixUni = -1;
+            locations.fNormalizedTexelSizeUni = -1;
         }
     }
     GR_GL(UseProgram(progID));
@@ -490,8 +507,11 @@
         programData->fTextureMatrices[s] = GrMatrix::InvalidMatrix();
         programData->fRadial2CenterX1[s] = GR_ScalarMax;
         programData->fRadial2Radius0[s] = -GR_ScalarMax;
+        programData->fTextureWidth[s] = -1;
+        programData->fTextureHeight[s] = -1;
     }
     programData->fViewMatrix = GrMatrix::InvalidMatrix();
+    programData->fColor = GrColor_ILLEGAL;
 }
 
 GrGLuint GrGLProgram::CompileShader(GrGLenum type,
@@ -535,12 +555,12 @@
 //============================================================================
 
 void GrGLProgram::genStageCode(int stageNum,
-                                  const GrGLProgram::ProgramDesc::StageDesc& desc,
-                                  const char* fsInColor, // NULL means no incoming color
-                                  const char* fsOutColor,
-                                  const char* vsInCoord,
-                                  ShaderCodeSegments* segments,
-                                  StageUniLocations* locations) const {
+                               const GrGLProgram::ProgramDesc::StageDesc& desc,
+                               const char* fsInColor, // NULL means no incoming color
+                               const char* fsOutColor,
+                               const char* vsInCoord,
+                               ShaderCodeSegments* segments,
+                               StageUniLocations* locations) const {
 
     GrAssert(stageNum >= 0 && stageNum <= 9);
 
@@ -585,6 +605,14 @@
     segments->fFSUnis += ";\n";
     locations->fSamplerUni = 1;
 
+    GrTokenString texelSizeName;
+    if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
+        normalized_texel_size_name(stageNum, &texelSizeName);
+        segments->fFSUnis += "uniform vec2 ";
+        segments->fFSUnis += texelSizeName;
+        segments->fFSUnis += ";\n";
+    }
+
     segments->fVaryings += "varying ";
     segments->fVaryings += float_vector_type(varyingDims);
     segments->fVaryings += " ";
@@ -661,14 +689,15 @@
         GrAssert(varyingDims == coordDims);
         fsCoordName = varyingName;
     } else {
-        // if we have to do some non-matrix op on the varyings to get
+        // if we have to do some special op on the varyings to get
         // our final tex coords then when in perspective we have to
         // do an explicit divide
-        if  (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping) {
+        if  (ProgramDesc::StageDesc::kIdentity_CoordMapping == desc.fCoordMapping &&
+             ProgramDesc::StageDesc::kSingle_FetchMode == desc.fFetchMode) {
             texFunc += "Proj";
             fsCoordName = varyingName;
         } else {
-            fsCoordName = "tCoord";
+            fsCoordName = "inCoord";
             fsCoordName.appendInt(stageNum);
 
             segments->fFSCode += "\t";
@@ -686,6 +715,7 @@
     }
 
     GrSStringBuilder<96> sampleCoords;
+    bool complexCoord = false;
     switch (desc.fCoordMapping) {
     case ProgramDesc::StageDesc::kIdentity_CoordMapping:
         sampleCoords = fsCoordName;
@@ -696,11 +726,13 @@
         sampleCoords += ".y, -";
         sampleCoords += fsCoordName;
         sampleCoords += ".x)*0.1591549430918 + 0.5, 0.5)";
+        complexCoord = true;
         break;
     case ProgramDesc::StageDesc::kRadialGradient_CoordMapping:
         sampleCoords = "vec2(length(";
         sampleCoords += fsCoordName;
         sampleCoords += ".xy), 0.5)";
+        complexCoord = true;
         break;
     case ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping: {
         GrTokenString cName    = "c";
@@ -769,26 +801,85 @@
         sampleCoords += ") * ";
         sampleCoords += radial2ParamsName;
         sampleCoords += "[1], 0.5)\n";
+        complexCoord = true;
         break;}
     };
 
-    segments->fFSCode += "\t";
-    segments->fFSCode += fsOutColor;
-    segments->fFSCode += " = ";
-    if (NULL != fsInColor) {
-        segments->fFSCode += fsInColor;
-        segments->fFSCode += " * ";
+    if (ProgramDesc::StageDesc::k2x2_FetchMode == desc.fFetchMode) {
+        locations->fNormalizedTexelSizeUni = 1;
+        if (complexCoord) {
+            GrTokenString coordVar("tCoord");
+            coordVar.appendInt(stageNum);
+            segments->fFSCode += "\t";
+            segments->fFSCode += float_vector_type(coordDims);
+            segments->fFSCode += " ";
+            segments->fFSCode += coordVar;
+            segments->fFSCode += " = ";
+            segments->fFSCode += sampleCoords;
+            segments->fFSCode += ";\n";
+            sampleCoords = coordVar;
+        }
+        static const char sign[] = {'-','+'};
+        GrTokenString stageAccumVar("stage2x2Accum");
+        stageAccumVar.appendInt(stageNum);
+        segments->fFSCode += "\tvec4 ";
+        segments->fFSCode += stageAccumVar;
+        segments->fFSCode += " = ";
+        GrAssert(2 == coordDims);
+        for (int y = 0; y < 2; ++y) {
+            for (int x = 0; x < 2; ++x) {
+                segments->fFSCode += texFunc;
+                segments->fFSCode += "(";
+                segments->fFSCode += samplerName;
+                segments->fFSCode += ", ";
+                segments->fFSCode += sampleCoords;
+                segments->fFSCode += " + vec2(";
+                segments->fFSCode += sign[x];
+                segments->fFSCode += texelSizeName;
+                segments->fFSCode += ".x, ";
+                segments->fFSCode += sign[y];
+                segments->fFSCode += texelSizeName;
+                segments->fFSCode += ".y))";
+                if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
+                    segments->fFSCode += ".aaaa";
+                }
+                segments->fFSCode += ";\n";
+                if (1 != x || 1 !=y ) {
+                    segments->fFSCode += "\t";
+                    segments->fFSCode += stageAccumVar;
+                    segments->fFSCode += " += ";
+                }
+            }
+        }
+        segments->fFSCode += "\t";
+        segments->fFSCode += fsOutColor;
+        segments->fFSCode += " = ";
+        if (NULL != fsInColor) {
+            segments->fFSCode += fsInColor;
+            segments->fFSCode += " * ";
+        }
+        segments->fFSCode += stageAccumVar;
+        segments->fFSCode += " / 4;\n";
+    } else {
+        segments->fFSCode += "\t";
+        segments->fFSCode += fsOutColor;
+        segments->fFSCode += " = ";
+        if (NULL != fsInColor) {
+            segments->fFSCode += fsInColor;
+            segments->fFSCode += " * ";
+        }
+
+        segments->fFSCode += texFunc;
+        segments->fFSCode += "(";
+        segments->fFSCode += samplerName;
+        segments->fFSCode += ", ";
+        segments->fFSCode += sampleCoords;
+        segments->fFSCode += ")";
+        if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
+            segments->fFSCode += ".aaaa";
+        }
+        segments->fFSCode += ";\n";
     }
-    segments->fFSCode += texFunc;
-    segments->fFSCode += "(";
-    segments->fFSCode += samplerName;
-    segments->fFSCode += ", ";
-    segments->fFSCode += sampleCoords;
-    segments->fFSCode += ")";
-    if (desc.fModulation == ProgramDesc::StageDesc::kAlpha_Modulation) {
-        segments->fFSCode += ".aaaa";
-    }
-    segments->fFSCode += ";\n";
 
     if(fStageEffects[stageNum]) {
         fStageEffects[stageNum]->genShaderCode(segments);