ccpr: Replace curve corner MSAA with analytic attenuation

Begins using the new triangle corner algorithm on curves as well.
Updates the vertex backend to render curves in a single pass.
Simplifies the cubic and quadratic shaders. Removes all code related to
sample locations.

Bug: skia:
Change-Id: I96c6c401be765e96a8fe087deb7f84760e68dcf0
Reviewed-on: https://skia-review.googlesource.com/115746
Reviewed-by: Greg Daniel <egdaniel@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/ccpr/GrCCQuadraticShader.cpp b/src/gpu/ccpr/GrCCQuadraticShader.cpp
index 5bee85e..287e63e 100644
--- a/src/gpu/ccpr/GrCCQuadraticShader.cpp
+++ b/src/gpu/ccpr/GrCCQuadraticShader.cpp
@@ -14,8 +14,7 @@
 using Shader = GrCCCoverageProcessor::Shader;
 
 void GrCCQuadraticShader::emitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
-                                        const char* repetitionID, const char* wind,
-                                        GeometryVars* vars) const {
+                                        const char* wind, const char** tighterHull) const {
     s->declareGlobal(fQCoordMatrix);
     s->codeAppendf("%s = float2x2(1, 1, .5, 0) * inverse(float2x2(%s[2] - %s[0], %s[1] - %s[0]));",
                    fQCoordMatrix.c_str(), pts, pts, pts, pts);
@@ -28,113 +27,60 @@
     s->codeAppendf("float2 edgept1 = %s[%s > 0 ? 0 : 2];", pts, wind);
     Shader::EmitEdgeDistanceEquation(s, "edgept0", "edgept1", fEdgeDistanceEquation.c_str());
 
-    this->onEmitSetupCode(s, pts, repetitionID, vars);
+    if (tighterHull) {
+        // Find the T value whose tangent is halfway between the tangents at the endpionts.
+        s->codeAppendf("float2 tan0 = %s[1] - %s[0];", pts, pts);
+        s->codeAppendf("float2 tan1 = %s[2] - %s[1];", pts, pts);
+        s->codeAppend ("float2 midnorm = normalize(tan0) - normalize(tan1);");
+        s->codeAppend ("float2 T = midnorm * float2x2(tan0 - tan1, tan0);");
+        s->codeAppend ("float t = clamp(T.t / T.s, 0, 1);"); // T.s!=0; we cull flat curves on CPU.
+
+        // Clip the bezier triangle by the tangent at our new t value. This is a simple application
+        // for De Casteljau's algorithm.
+        s->codeAppendf("float4x2 quadratic_hull = float4x2(%s[0], "
+                                                          "%s[0] + tan0 * t, "
+                                                          "%s[1] + tan1 * t, "
+                                                          "%s[2]);", pts, pts, pts, pts);
+        *tighterHull = "quadratic_hull";
+    }
 }
 
 void GrCCQuadraticShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
                                          GrGLSLVarying::Scope scope, SkString* code,
                                          const char* position, const char* coverage,
-                                         const char* attenuatedCoverage, const char* wind) {
-    SkASSERT(!coverage);
-    SkASSERT(!attenuatedCoverage);
+                                         const char* attenuatedCoverage) {
+    fCoord.reset(kFloat4_GrSLType, scope);
+    varyingHandler->addVarying("coord", &fCoord);
+    code->appendf("%s.xy = %s * (%s - %s);", // Quadratic coords.
+                  OutName(fCoord), fQCoordMatrix.c_str(), position, fQCoord0.c_str());
+    code->appendf("%s.zw = 2*bloat * float2(2 * %s.x, -1) * %s;", // Gradient.
+                  OutName(fCoord), OutName(fCoord), fQCoordMatrix.c_str());
 
-    fXYDW.reset(kFloat4_GrSLType, scope);
-    varyingHandler->addVarying("xydw", &fXYDW);
-    code->appendf("%s.xy = %s * (%s - %s);",
-                  OutName(fXYDW), fQCoordMatrix.c_str(), position, fQCoord0.c_str());
-    code->appendf("%s.z = dot(%s.xy, %s) + %s.z;",
-                  OutName(fXYDW), fEdgeDistanceEquation.c_str(), position,
-                  fEdgeDistanceEquation.c_str());
-    code->appendf("%s.w = %s;", OutName(fXYDW), wind);
-
-    this->onEmitVaryings(varyingHandler, scope, code);
+    // Coverages need full precision since distance to the opposite edge can be large.
+    fCoverages.reset(attenuatedCoverage ? kFloat4_GrSLType : kFloat2_GrSLType, scope);
+    varyingHandler->addVarying("coverages", &fCoverages);
+    code->appendf("%s.x = dot(%s, float3(%s, 1));", // Distance to flat edge opposite the curve.
+                  OutName(fCoverages), fEdgeDistanceEquation.c_str(), position);
+    code->appendf("%s.y = %s;", OutName(fCoverages), coverage); // Wind.
+    if (attenuatedCoverage) {
+        code->appendf("%s.zw = %s;", // Attenuated corner coverage.
+                      OutName(fCoverages), attenuatedCoverage);
+    }
 }
 
 void GrCCQuadraticShader::onEmitFragmentCode(GrGLSLFPFragmentBuilder* f,
                                              const char* outputCoverage) const {
-    this->emitCoverage(f, outputCoverage);
-    f->codeAppendf("%s *= %s.w;", outputCoverage, fXYDW.fsIn()); // Sign by wind.
-}
-
-void GrCCQuadraticHullShader::onEmitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
-                                              const char* /*repetitionID*/,
-                                              GeometryVars* vars) const {
-    // Find the T value whose tangent is halfway between the tangents at the endpionts.
-    s->codeAppendf("float2 tan0 = %s[1] - %s[0];", pts, pts);
-    s->codeAppendf("float2 tan1 = %s[2] - %s[1];", pts, pts);
-    s->codeAppend ("float2 midnorm = normalize(tan0) - normalize(tan1);");
-    s->codeAppend ("float2 T = midnorm * float2x2(tan0 - tan1, tan0);");
-    s->codeAppend ("float t = clamp(T.t / T.s, 0, 1);"); // T.s != 0; we cull flat curves on CPU.
-
-    // Clip the bezier triangle by the tangent at our new t value. This is a simple application for
-    // De Casteljau's algorithm.
-    s->codeAppendf("float4x2 quadratic_hull = float4x2(%s[0], "
-                                                      "%s[0] + tan0 * t, "
-                                                      "%s[1] + tan1 * t, "
-                                                      "%s[2]);", pts, pts, pts, pts);
-    vars->fHullVars.fAlternatePoints = "quadratic_hull";
-}
-
-void GrCCQuadraticHullShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
-                                             GrGLSLVarying::Scope scope, SkString* code) {
-    fGrad.reset(kFloat2_GrSLType, scope);
-    varyingHandler->addVarying("grad", &fGrad);
-    code->appendf("%s = 2*bloat * float2(2 * %s.x, -1) * %s;",
-                  OutName(fGrad), OutName(fXYDW), fQCoordMatrix.c_str());
-}
-
-void GrCCQuadraticHullShader::emitCoverage(GrGLSLFPFragmentBuilder* f,
-                                           const char* outputCoverage) const {
-    f->codeAppendf("float d = (%s.x * %s.x - %s.y) * inversesqrt(dot(%s, %s));",
-                   fXYDW.fsIn(), fXYDW.fsIn(), fXYDW.fsIn(), fGrad.fsIn(), fGrad.fsIn());
-    f->codeAppendf("%s = clamp(0.5 - d, 0, 1);", outputCoverage);
-    f->codeAppendf("%s += min(%s.z, 0);", outputCoverage, fXYDW.fsIn()); // Flat closing edge.
-}
-
-void GrCCQuadraticCornerShader::onEmitSetupCode(GrGLSLVertexGeoBuilder* s, const char* pts,
-                                                const char* repetitionID,
-                                                GeometryVars* vars) const {
-    s->codeAppendf("float2 corner = %s[%s * 2];", pts, repetitionID);
-    vars->fCornerVars.fPoint = "corner";
-}
-
-void GrCCQuadraticCornerShader::onEmitVaryings(GrGLSLVaryingHandler* varyingHandler,
-                                               GrGLSLVarying::Scope scope, SkString* code) {
-    using Interpolation = GrGLSLVaryingHandler::Interpolation;
-
-    fdXYDdx.reset(kFloat3_GrSLType, scope);
-    varyingHandler->addVarying("dXYDdx", &fdXYDdx, Interpolation::kCanBeFlat);
-    code->appendf("%s = 2*bloat * float3(%s[0].x, %s[0].y, %s.x);",
-                  OutName(fdXYDdx), fQCoordMatrix.c_str(), fQCoordMatrix.c_str(),
-                  fEdgeDistanceEquation.c_str());
-
-    fdXYDdy.reset(kFloat3_GrSLType, scope);
-    varyingHandler->addVarying("dXYDdy", &fdXYDdy, Interpolation::kCanBeFlat);
-    code->appendf("%s = 2*bloat * float3(%s[1].x, %s[1].y, %s.y);",
-                  OutName(fdXYDdy), fQCoordMatrix.c_str(), fQCoordMatrix.c_str(),
-                  fEdgeDistanceEquation.c_str());
-}
-
-void GrCCQuadraticCornerShader::emitCoverage(GrGLSLFPFragmentBuilder* f,
-                                             const char* outputCoverage) const {
-    f->codeAppendf("float x = %s.x, y = %s.y, d = %s.z;",
-                   fXYDW.fsIn(), fXYDW.fsIn(), fXYDW.fsIn());
-    f->codeAppendf("float2x3 grad_xyd = float2x3(%s, %s);", fdXYDdx.fsIn(), fdXYDdy.fsIn());
-
-    // Erase what the previous hull shader wrote. We don't worry about the two corners falling on
-    // the same pixel because those cases should have been weeded out by this point.
+    f->codeAppendf("float x = %s.x, y = %s.y;", fCoord.fsIn(), fCoord.fsIn());
     f->codeAppend ("float f = x*x - y;");
-    f->codeAppend ("float2 grad_f = float2(2*x, -1) * float2x2(grad_xyd);");
-    f->codeAppendf("%s = -(0.5 - f * inversesqrt(dot(grad_f, grad_f)));", outputCoverage);
-    f->codeAppendf("%s -= d;", outputCoverage);
+    f->codeAppendf("float2 grad = %s.zw;", fCoord.fsIn());
+    f->codeAppendf("%s = clamp(0.5 - f * inversesqrt(dot(grad, grad)), 0, 1);", outputCoverage);
 
-    // Use software msaa to approximate coverage at the corner pixels.
-    int sampleCount = Shader::DefineSoftSampleLocations(f, "samples");
-    f->codeAppendf("float3 xyd_center = float3(%s.xy, %s.z + 0.5);", fXYDW.fsIn(), fXYDW.fsIn());
-    f->codeAppendf("for (int i = 0; i < %i; ++i) {", sampleCount);
-    f->codeAppend (    "float3 xyd = grad_xyd * samples[i] + xyd_center;");
-    f->codeAppend (    "half f = xyd.y - xyd.x * xyd.x;"); // f > 0 -> inside curve.
-    f->codeAppendf(    "%s += all(greaterThan(float2(f,xyd.z), float2(0))) ? %f : 0;",
-                       outputCoverage, 1.0 / sampleCount);
-    f->codeAppendf("}");
+    f->codeAppendf("half d = min(%s.x, 0);", fCoverages.fsIn()); // Flat edge opposite the curve.
+    f->codeAppendf("half wind = %s.y;", fCoverages.fsIn());
+    f->codeAppendf("%s = (%s + d) * wind;", outputCoverage, outputCoverage);
+
+    if (kFloat4_GrSLType == fCoverages.type()) {
+        f->codeAppendf("%s = %s.z * %s.w + %s;", // Attenuated corner coverage.
+                       outputCoverage, fCoverages.fsIn(), fCoverages.fsIn(), outputCoverage);
+    }
 }