Interpolate coverage in screen space for perspective quads

Bug: chromium:947055
Change-Id: I1e0c4c5a6ab839ecca73759f66e2271038de835f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/204961
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/ops/GrQuadPerEdgeAA.cpp b/src/gpu/ops/GrQuadPerEdgeAA.cpp
index 2a53dd9..c624b25 100644
--- a/src/gpu/ops/GrQuadPerEdgeAA.cpp
+++ b/src/gpu/ops/GrQuadPerEdgeAA.cpp
@@ -617,7 +617,8 @@
 
 static CoverageMode get_mode_for_spec(const GrQuadPerEdgeAA::VertexSpec& spec) {
     if (spec.usesCoverageAA()) {
-        if (spec.compatibleWithCoverageAsAlpha() && spec.hasVertexColors()) {
+        if (spec.compatibleWithCoverageAsAlpha() && spec.hasVertexColors() &&
+            spec.deviceQuadType() != GrQuadType::kPerspective) {
             return CoverageMode::kWithColor;
         } else {
             return CoverageMode::kWithPosition;
@@ -897,6 +898,7 @@
 
                 // Solid color before any texturing gets modulated in
                 if (gp.fColor.isInitialized()) {
+                    SkASSERT(gp.fCoverageMode != CoverageMode::kWithColor || !gp.fNeedsPerspective);
                     // The color cannot be flat if the varying coverage has been modulated into it
                     args.fVaryingHandler->addPassThroughAttribute(gp.fColor, args.fOutputColor,
                             gp.fCoverageMode == CoverageMode::kWithColor ?
@@ -946,15 +948,20 @@
                     GrGLSLVarying coverage(kFloat_GrSLType);
                     args.fVaryingHandler->addVarying("coverage", &coverage);
                     if (gp.fNeedsPerspective) {
-                        args.fVertBuilder->codeAppendf("%s = %s.w;",
-                                                       coverage.vsOut(), gp.fPosition.name());
+                        // Multiply by "W" in the vertex shader, then by 1/w (sk_FragCoord.w) in
+                        // the fragment shader to get screen-space linear coverage.
+                        args.fVertBuilder->codeAppendf("%s = %s.w * %s.z;",
+                                                       coverage.vsOut(), gp.fPosition.name(),
+                                                       gp.fPosition.name());
+                        args.fFragBuilder->codeAppendf("%s = half4(half(%s * sk_FragCoord.w));",
+                                                       args.fOutputCoverage, coverage.fsIn());
                     } else {
                         args.fVertBuilder->codeAppendf("%s = %s.z;",
                                                        coverage.vsOut(), gp.fPosition.name());
+                        args.fFragBuilder->codeAppendf("%s = half4(half(%s));",
+                                                       args.fOutputCoverage, coverage.fsIn());
                     }
 
-                    args.fFragBuilder->codeAppendf("%s = half4(half(%s));",
-                                                   args.fOutputCoverage, coverage.fsIn());
                 } else {
                     // Set coverage to 1, since it's either non-AA or the coverage was already
                     // folded into the output color