ccpr: Add an MSAA atlas mode

Adds the option to use a multisampled (or mixed sampled) atlas, and
uses the sample mask and stencil buffer instead of coverage counts.

Bug: skia:
Change-Id: I9fb76d17895ae25208124f6c27e37977ac31b5eb
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/227428
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
index 55d8a18..06c2481 100644
--- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
+++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
@@ -18,30 +18,51 @@
 
 using PathInstance = GrCCPathProcessor::Instance;
 
-bool GrCoverageCountingPathRenderer::IsSupported(const GrCaps& caps) {
+bool GrCoverageCountingPathRenderer::IsSupported(const GrCaps& caps, CoverageType* coverageType) {
     const GrShaderCaps& shaderCaps = *caps.shaderCaps();
-    if (caps.driverBlacklistCCPR() || !caps.allowCoverageCounting() ||
-        !shaderCaps.integerSupport() || !caps.instanceAttribSupport() ||
-        !shaderCaps.floatIs32Bits() || GrCaps::kNone_MapFlags == caps.mapBufferFlags() ||
-        !caps.isConfigTexturable(kAlpha_half_GrPixelConfig) ||
-        !caps.isConfigRenderable(kAlpha_half_GrPixelConfig) ||
+    if (caps.driverBlacklistCCPR() || !shaderCaps.integerSupport() ||
+        !caps.instanceAttribSupport() || !shaderCaps.floatIs32Bits() ||
+        GrCaps::kNone_MapFlags == caps.mapBufferFlags() ||
         !caps.isConfigTexturable(kAlpha_8_GrPixelConfig) ||
         !caps.isConfigRenderable(kAlpha_8_GrPixelConfig) ||
         !caps.halfFloatVertexAttributeSupport()) {
         return false;
     }
-    return true;
+
+    if (caps.allowCoverageCounting() &&
+        caps.isConfigTexturable(kAlpha_half_GrPixelConfig) &&
+        caps.isConfigRenderable(kAlpha_half_GrPixelConfig)) {
+        if (coverageType) {
+            *coverageType = CoverageType::kFP16_CoverageCount;
+        }
+        return true;
+    }
+
+    if (caps.internalMultisampleCount(kAlpha_8_GrPixelConfig) > 1 &&
+        caps.sampleLocationsSupport() &&
+        shaderCaps.sampleVariablesStencilSupport()) {
+        if (coverageType) {
+            *coverageType = CoverageType::kA8_Multisample;
+        }
+        return true;
+    }
+
+    return false;
 }
 
 sk_sp<GrCoverageCountingPathRenderer> GrCoverageCountingPathRenderer::CreateIfSupported(
         const GrCaps& caps, AllowCaching allowCaching, uint32_t contextUniqueID) {
-    return sk_sp<GrCoverageCountingPathRenderer>((IsSupported(caps))
-            ? new GrCoverageCountingPathRenderer(allowCaching, contextUniqueID)
-            : nullptr);
+    CoverageType coverageType;
+    if (IsSupported(caps, &coverageType)) {
+        return sk_sp<GrCoverageCountingPathRenderer>(new GrCoverageCountingPathRenderer(
+                coverageType, allowCaching, contextUniqueID));
+    }
+    return nullptr;
 }
 
-GrCoverageCountingPathRenderer::GrCoverageCountingPathRenderer(AllowCaching allowCaching,
-                                                               uint32_t contextUniqueID) {
+GrCoverageCountingPathRenderer::GrCoverageCountingPathRenderer(
+        CoverageType coverageType, AllowCaching allowCaching, uint32_t contextUniqueID)
+        : fCoverageType(coverageType) {
     if (AllowCaching::kYes == allowCaching) {
         fPathCache = skstd::make_unique<GrCCPathCache>(contextUniqueID);
     }
@@ -59,6 +80,9 @@
 GrPathRenderer::CanDrawPath GrCoverageCountingPathRenderer::onCanDrawPath(
         const CanDrawPathArgs& args) const {
     const GrShape& shape = *args.fShape;
+    // We use "kCoverage", or analytic AA, no mater what the coverage type of our atlas: Even if the
+    // atlas is multisampled, that resolves into analytic coverage before we draw the path to the
+    // main canvas.
     if (GrAAType::kCoverage != args.fAAType || shape.style().hasPathEffect() ||
         args.fViewMatrix->hasPerspective() || shape.inverseFilled()) {
         return CanDrawPath::kNo;
@@ -113,6 +137,10 @@
             }
             // fallthru
         case SkStrokeRec::kHairline_Style: {
+            if (CoverageType::kFP16_CoverageCount != fCoverageType) {
+                // Stroking is not yet supported in MSAA atlas mode.
+                return CanDrawPath::kNo;
+            }
             float inflationRadius;
             GetStrokeDevWidth(*args.fViewMatrix, stroke, &inflationRadius);
             if (!(inflationRadius <= kMaxBoundsInflationFromStroke)) {
@@ -161,14 +189,18 @@
 }
 
 std::unique_ptr<GrFragmentProcessor> GrCoverageCountingPathRenderer::makeClipProcessor(
-        uint32_t opListID, const SkPath& deviceSpacePath, const SkIRect& accessRect, int rtWidth,
-        int rtHeight, const GrCaps& caps) {
-    using MustCheckBounds = GrCCClipProcessor::MustCheckBounds;
-
+        uint32_t opListID, const SkPath& deviceSpacePath, const SkIRect& accessRect,
+        const GrCaps& caps) {
     SkASSERT(!fFlushing);
 
+    uint32_t key = deviceSpacePath.getGenerationID();
+    if (CoverageType::kA8_Multisample == fCoverageType) {
+        // We only need to consider fill rule in MSAA mode. In coverage count mode Even/Odd and
+        // Nonzero both reference the same coverage count mask.
+        key = (key << 1) | (uint32_t)GrFillRuleForSkPath(deviceSpacePath);
+    }
     GrCCClipPath& clipPath =
-            this->lookupPendingPaths(opListID)->fClipPaths[deviceSpacePath.getGenerationID()];
+            this->lookupPendingPaths(opListID)->fClipPaths[key];
     if (!clipPath.isInitialized()) {
         // This ClipPath was just created during lookup. Initialize it.
         const SkRect& pathDevBounds = deviceSpacePath.getBounds();
@@ -177,17 +209,19 @@
             SkPath croppedPath;
             int maxRTSize = caps.maxRenderTargetSize();
             CropPath(deviceSpacePath, SkIRect::MakeWH(maxRTSize, maxRTSize), &croppedPath);
-            clipPath.init(croppedPath, accessRect, rtWidth, rtHeight, caps);
+            clipPath.init(croppedPath, accessRect, fCoverageType, caps);
         } else {
-            clipPath.init(deviceSpacePath, accessRect, rtWidth, rtHeight, caps);
+            clipPath.init(deviceSpacePath, accessRect, fCoverageType, caps);
         }
     } else {
         clipPath.addAccess(accessRect);
     }
 
-    bool mustCheckBounds = !clipPath.pathDevIBounds().contains(accessRect);
-    return skstd::make_unique<GrCCClipProcessor>(&clipPath, MustCheckBounds(mustCheckBounds),
-                                                 deviceSpacePath.getFillType());
+    auto isCoverageCount = GrCCClipProcessor::IsCoverageCount(
+            CoverageType::kFP16_CoverageCount == fCoverageType);
+    auto mustCheckBounds = GrCCClipProcessor::MustCheckBounds(
+            !clipPath.pathDevIBounds().contains(accessRect));
+    return skstd::make_unique<GrCCClipProcessor>(&clipPath, isCoverageCount, mustCheckBounds);
 }
 
 void GrCoverageCountingPathRenderer::preFlush(GrOnFlushResourceProvider* onFlushRP,
@@ -247,7 +281,7 @@
         specs.cancelCopies();
     }
 
-    auto resources = sk_make_sp<GrCCPerFlushResources>(onFlushRP, specs);
+    auto resources = sk_make_sp<GrCCPerFlushResources>(onFlushRP, fCoverageType, specs);
     if (!resources->isMapped()) {
         return;  // Some allocation failed.
     }