Implement edge AA for concave polys in the tesselated path renderer.

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



git-svn-id: http://skia.googlecode.com/svn/trunk@1600 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/src/GrGLProgram.cpp b/gpu/src/GrGLProgram.cpp
index ecb4753..b0d41aa 100644
--- a/gpu/src/GrGLProgram.cpp
+++ b/gpu/src/GrGLProgram.cpp
@@ -510,21 +510,39 @@
                 segments.fFSCode.appendS32(i);
                 segments.fFSCode.append("], pos), 0.0, 1.0);\n");
             }
-            segments.fFSCode.append("\tfloat edgeAlpha = ");
-            for (int i = 0; i < count - 1; i++) {
-                segments.fFSCode.append("min(a");
-                segments.fFSCode.appendS32(i);
-                segments.fFSCode.append(" * a");
-                segments.fFSCode.appendS32(i + 1);
-                segments.fFSCode.append(", ");
+            if (fProgramDesc.fEdgeAAConcave && (count & 0x01) == 0) {
+                // For concave polys, we consider the edges in pairs.
+                segments.fFSFunctions.append("float cross2(vec2 a, vec2 b) {\n");
+                segments.fFSFunctions.append("\treturn dot(a, vec2(b.y, -b.x));\n");
+                segments.fFSFunctions.append("}\n");
+                for (int i = 0; i < count; i += 2) {
+                    segments.fFSCode.appendf("\tfloat eb%d;\n", i / 2);
+                    segments.fFSCode.appendf("\tif (cross2(" EDGES_UNI_NAME "[%d].xy, " EDGES_UNI_NAME "[%d].xy) < 0.0) {\n", i, i + 1);
+                    segments.fFSCode.appendf("\t\teb%d = a%d * a%d;\n", i / 2, i, i + 1);
+                    segments.fFSCode.append("\t} else {\n");
+                    segments.fFSCode.appendf("\t\teb%d = a%d + a%d - a%d * a%d;\n", i / 2, i, i + 1, i, i + 1);
+                    segments.fFSCode.append("\t}\n");
+                }
+                segments.fFSCode.append("\tfloat edgeAlpha = ");
+                for (int i = 0; i < count / 2 - 1; i++) {
+                    segments.fFSCode.appendf("min(eb%d, ", i);
+                }
+                segments.fFSCode.appendf("eb%d", count / 2 - 1);
+                for (int i = 0; i < count / 2 - 1; i++) {
+                    segments.fFSCode.append(")");
+                }
+                segments.fFSCode.append(";\n");
+            } else {
+                segments.fFSCode.append("\tfloat edgeAlpha = ");
+                for (int i = 0; i < count - 1; i++) {
+                    segments.fFSCode.appendf("min(a%d * a%d, ", i, i + 1);
+                }
+                segments.fFSCode.appendf("a%d * a0", count - 1);
+                for (int i = 0; i < count - 1; i++) {
+                    segments.fFSCode.append(")");
+                }
+                segments.fFSCode.append(";\n");
             }
-            segments.fFSCode.append("a");
-            segments.fFSCode.appendS32(count - 1);
-            segments.fFSCode.append(" * a0");
-            for (int i = 0; i < count - 1; i++) {
-                segments.fFSCode.append(")");
-            }
-            segments.fFSCode.append(";\n");
             inCoverage = "edgeAlpha";
         }
 
@@ -702,6 +720,11 @@
         lengths[stringCnt] = segments.fFSOutputs.size();
         ++stringCnt;
     }
+    if (segments.fFSFunctions.size()) {
+        strings[stringCnt] = segments.fFSFunctions.c_str();
+        lengths[stringCnt] = segments.fFSFunctions.size();
+        ++stringCnt;
+    }
 
     GrAssert(segments.fFSCode.size());
     strings[stringCnt] = segments.fFSCode.c_str();
@@ -714,6 +737,7 @@
     GrPrintf(segments.fFSUnis.c_str());
     GrPrintf(segments.fVaryings.c_str());
     GrPrintf(segments.fFSOutputs.c_str());
+    GrPrintf(segments.fFSFunctions.c_str());
     GrPrintf(segments.fFSCode.c_str());
     GrPrintf("\n");
 #endif