Replace GrAAType with flags for path renderers

Replaces the single GrAAType with a set of flags indicating which AA
types are acceptable for the path renderer to use.

Bug: skia:
Change-Id: I773565c904a360355e771966b6cddba697e1165f
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/200840
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index a840bf5..dd31406 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -114,6 +114,12 @@
             path.toggleInverseFillType();
         }
 
+        // We only use this method when rendering coverage clip masks.
+        SkASSERT(GrFSAAType::kNone == renderTargetContext->fsaaType());
+        auto aaTypeFlags = (element->isAA())
+                ? GrPathRenderer::AATypeFlags::kCoverage
+                : GrPathRenderer::AATypeFlags::kNone;
+
         GrPathRendererChain::DrawType type =
                 needsStencil ? GrPathRendererChain::DrawType::kStencilAndColor
                              : GrPathRendererChain::DrawType::kColor;
@@ -124,10 +130,7 @@
         canDrawArgs.fClipConservativeBounds = &scissorRect;
         canDrawArgs.fViewMatrix = &viewMatrix;
         canDrawArgs.fShape = &shape;
-        canDrawArgs.fAAType = GrChooseAAType(GrAA(element->isAA()),
-                                             renderTargetContext->fsaaType(),
-                                             GrAllowMixedSamples::kYes,
-                                             *context->priv().caps());
+        canDrawArgs.fAATypeFlags = aaTypeFlags;
         SkASSERT(!renderTargetContext->wrapsVkSecondaryCB());
         canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
         canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
diff --git a/src/gpu/GrPathRenderer.cpp b/src/gpu/GrPathRenderer.cpp
index 83e8b5b..1595207 100644
--- a/src/gpu/GrPathRenderer.cpp
+++ b/src/gpu/GrPathRenderer.cpp
@@ -22,7 +22,6 @@
     SkASSERT(fViewMatrix);
     SkASSERT(fShape);
     SkASSERT(fShape->style().isSimpleFill());
-    SkASSERT(GrAAType::kCoverage != fAAType);
     SkPath path;
     fShape->asPath(&path);
     SkASSERT(!path.isInverseFillType());
@@ -49,15 +48,14 @@
     canArgs.fClipConservativeBounds = args.fClipConservativeBounds;
     canArgs.fViewMatrix = args.fViewMatrix;
     canArgs.fShape = args.fShape;
-    canArgs.fAAType = args.fAAType;
+    canArgs.fAATypeFlags = args.fAATypeFlags;
     canArgs.fTargetIsWrappedVkSecondaryCB = args.fRenderTargetContext->wrapsVkSecondaryCB();
     canArgs.validate();
 
     canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
-    SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA &&
-               GrFSAAType::kUnifiedMSAA != args.fRenderTargetContext->fsaaType()));
-    SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples &&
-               GrFSAAType::kMixedSamples != args.fRenderTargetContext->fsaaType()));
+    if (AATypeFlags::kMixedSampledStencilThenCover & canArgs.fAATypeFlags) {
+        SkASSERT(GrFSAAType::kMixedSamples == args.fRenderTargetContext->fsaaType());
+    }
     SkASSERT(CanDrawPath::kNo != this->canDrawPath(canArgs));
     if (!args.fUserStencilSettings->isUnused()) {
         SkPath path;
@@ -118,7 +116,9 @@
                           args.fClipConservativeBounds,
                           args.fViewMatrix,
                           args.fShape,
-                          args.fAAType,
+                          (GrAA::kYes == args.fDoStencilMSAA)
+                                  ? AATypeFlags::kMSAA
+                                  : AATypeFlags::kNone,
                           false};
     this->drawPath(drawArgs);
 }
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
index 7101878..aac401e 100644
--- a/src/gpu/GrPathRenderer.h
+++ b/src/gpu/GrPathRenderer.h
@@ -72,6 +72,17 @@
         kYes
     };
 
+    /**
+     * This enum defines a set of flags indicating which AA methods would be acceptable for a path
+     * renderer to employ (if any) while drawing a given path.
+     */
+    enum class AATypeFlags {
+        kNone = 0,
+        kCoverage = (1 << 0),
+        kMSAA = (1 << 1),
+        kMixedSampledStencilThenCover = (1 << 2),
+    };
+
     struct CanDrawPathArgs {
         SkDEBUGCODE(CanDrawPathArgs() { memset(this, 0, sizeof(*this)); }) // For validation.
 
@@ -79,7 +90,7 @@
         const SkIRect*              fClipConservativeBounds;
         const SkMatrix*             fViewMatrix;
         const GrShape*              fShape;
-        GrAAType                    fAAType;
+        AATypeFlags                 fAATypeFlags;
         bool                        fTargetIsWrappedVkSecondaryCB;
 
         // This is only used by GrStencilAndCoverPathRenderer
@@ -114,7 +125,7 @@
         const SkIRect*               fClipConservativeBounds;
         const SkMatrix*              fViewMatrix;
         const GrShape*               fShape;
-        GrAAType                     fAAType;
+        AATypeFlags                  fAATypeFlags;
         bool                         fGammaCorrect;
 #ifdef SK_DEBUG
         void validate() const {
@@ -145,8 +156,8 @@
         const GrHardClip*      fClip;
         const SkIRect*         fClipConservativeBounds;
         const SkMatrix*        fViewMatrix;
-        GrAAType               fAAType;
         const GrShape*         fShape;
+        GrAA                   fDoStencilMSAA;
 
         SkDEBUGCODE(void validate() const);
     };
@@ -202,4 +213,6 @@
     typedef SkRefCnt INHERITED;
 };
 
+GR_MAKE_BITFIELD_CLASS_OPS(GrPathRenderer::AATypeFlags);
+
 #endif
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index 2624d86..74bd2d5 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -824,12 +824,13 @@
 
     // walk through each clip element and perform its set op with the existing clip.
     for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) {
+        using AATypeFlags = GrPathRenderer::AATypeFlags;
         const Element* element = iter.get();
-        GrAAType aaType = GrAAType::kNone;
-        if (element->isAA() && GrFSAAType::kNone != renderTargetContext->fsaaType()) {
-            aaType = GrAAType::kMSAA;
-        }
-
+        bool doStencilMSAA =
+                element->isAA() && GrFSAAType::kNone != renderTargetContext->fsaaType();
+        // Since we are only drawing to the stencil buffer, we can use kMSAA even if the render
+        // target is mixed sampled.
+        auto pathAATypeFlags = (doStencilMSAA) ? AATypeFlags::kMSAA : AATypeFlags::kNone;
         bool fillInverted = false;
 
         // This will be used to determine whether the clip shape can be rendered into the
@@ -856,7 +857,7 @@
             canDrawArgs.fClipConservativeBounds = &stencilClip.fixedClip().scissorRect();
             canDrawArgs.fViewMatrix = &SkMatrix::I();
             canDrawArgs.fShape = &shape;
-            canDrawArgs.fAAType = aaType;
+            canDrawArgs.fAATypeFlags = pathAATypeFlags;
             canDrawArgs.fHasUserStencilSettings = false;
             canDrawArgs.fTargetIsWrappedVkSecondaryCB = renderTargetContext->wrapsVkSecondaryCB();
 
@@ -890,9 +891,9 @@
                      0xffff>()
             );
             if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
-                renderTargetContext->priv().stencilRect(stencilClip.fixedClip(), &kDrawToStencil,
-                                                        aaType, SkMatrix::I(),
-                                                        element->getDeviceSpaceRect());
+                renderTargetContext->priv().stencilRect(
+                        stencilClip.fixedClip(), &kDrawToStencil, GrAA(doStencilMSAA),
+                        SkMatrix::I(), element->getDeviceSpaceRect());
             } else {
                 if (!clipPath.isEmpty()) {
                     GrShape shape(clipPath, GrStyle::SimpleFill());
@@ -908,7 +909,7 @@
                                                           &stencilClip.fixedClip().scissorRect(),
                                                           &SkMatrix::I(),
                                                           &shape,
-                                                          aaType,
+                                                          pathAATypeFlags,
                                                           false};
                         pr->drawPath(args);
                     } else {
@@ -918,7 +919,7 @@
                         args.fClip = &stencilClip.fixedClip();
                         args.fClipConservativeBounds = &stencilClip.fixedClip().scissorRect();
                         args.fViewMatrix = &SkMatrix::I();
-                        args.fAAType = aaType;
+                        args.fDoStencilMSAA = GrAA(doStencilMSAA);
                         args.fShape = &shape;
                         pr->stencilPath(args);
                     }
@@ -931,9 +932,9 @@
         for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) {
             if (drawDirectToClip) {
                 if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
-                    renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType,
-                                                            SkMatrix::I(),
-                                                            element->getDeviceSpaceRect());
+                    renderTargetContext->priv().stencilRect(
+                            stencilClip, *pass, GrAA(doStencilMSAA), SkMatrix::I(),
+                            element->getDeviceSpaceRect());
                 } else {
                     GrShape shape(clipPath, GrStyle::SimpleFill());
                     GrPaint paint;
@@ -946,15 +947,16 @@
                                                       &stencilClip.fixedClip().scissorRect(),
                                                       &SkMatrix::I(),
                                                       &shape,
-                                                      aaType,
+                                                      pathAATypeFlags,
                                                       false};
                     pr->drawPath(args);
                 }
             } else {
                 // The view matrix is setup to do clip space -> stencil space translation, so
                 // draw rect in clip space.
-                renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType, SkMatrix::I(),
-                                                        SkRect::Make(fScissor));
+                renderTargetContext->priv().stencilRect(
+                        stencilClip, *pass, GrAA(doStencilMSAA), SkMatrix::I(),
+                        SkRect::Make(fScissor));
             }
         }
     }
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index a148cef..8fff430 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -142,6 +142,29 @@
     return GrAAType::kNone;
 }
 
+static inline GrPathRenderer::AATypeFlags choose_path_aa_type_flags(
+        GrAA aa, GrFSAAType fsaaType, const GrCaps& caps) {
+    using AATypeFlags = GrPathRenderer::AATypeFlags;
+    if (GrAA::kNo == aa) {
+        // On some devices we cannot disable MSAA if it is enabled so we make the AA type flags
+        // reflect that.
+        if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) {
+            return AATypeFlags::kMSAA;
+        }
+        return AATypeFlags::kNone;
+    }
+    switch (fsaaType) {
+        case GrFSAAType::kNone:
+            return AATypeFlags::kCoverage;
+        case GrFSAAType::kMixedSamples:
+            return AATypeFlags::kCoverage | AATypeFlags::kMixedSampledStencilThenCover;
+        case GrFSAAType::kUnifiedMSAA:
+            return AATypeFlags::kMSAA;
+    }
+    SK_ABORT("Invalid GrFSAAType.");
+    return AATypeFlags::kNone;
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 class AutoCheckFlush {
@@ -793,7 +816,7 @@
 }
 
 void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
-                                            GrAAType aaType,
+                                            GrAA doStencilMSAA,
                                             const SkMatrix& viewMatrix,
                                             const GrPath* path) {
     ASSERT_SINGLE_OWNER_PRIV
@@ -802,9 +825,6 @@
     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
                                    fRenderTargetContext->fContext);
 
-    SkASSERT(aaType != GrAAType::kCoverage);
-
-    bool useHWAA = GrAATypeIsHW(aaType);
     // TODO: extract portions of checkDraw that are relevant to path stenciling.
     SkASSERT(path);
     SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
@@ -824,7 +844,7 @@
 
     std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext,
                                                      viewMatrix,
-                                                     useHWAA,
+                                                     GrAA::kYes == doStencilMSAA,
                                                      path->getFillType(),
                                                      appliedClip.hasStencilClip(),
                                                      appliedClip.scissorState(),
@@ -838,7 +858,7 @@
 
 void GrRenderTargetContextPriv::stencilRect(const GrHardClip& clip,
                                             const GrUserStencilSettings* ss,
-                                            GrAAType aaType,
+                                            GrAA doStencilMSAA,
                                             const SkMatrix& viewMatrix,
                                             const SkRect& rect) {
     ASSERT_SINGLE_OWNER_PRIV
@@ -847,11 +867,11 @@
     GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilRect",
                                    fRenderTargetContext->fContext);
 
-    SkASSERT(GrAAType::kCoverage != aaType);
     AutoCheckFlush acf(fRenderTargetContext->drawingManager());
 
     GrPaint paint;
     paint.setXPFactory(GrDisableColorXPFactory::Get());
+    auto aaType = (GrAA::kYes == doStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
     std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
             fRenderTargetContext->fContext, std::move(paint), aaType, viewMatrix,  rect, ss);
     fRenderTargetContext->addDrawOp(clip, std::move(op));
@@ -1866,7 +1886,8 @@
     // the src color (either the input alpha or in the frag shader) to implement
     // aa. If we have some future driver-mojo path AA that can do the right
     // thing WRT to the blend then we'll need some query on the PR.
-    GrAAType aaType = fRenderTargetContext->chooseAAType(aa, GrAllowMixedSamples::kNo);
+    auto aaTypeFlags = choose_path_aa_type_flags(
+            aa, fRenderTargetContext->fsaaType(), *fRenderTargetContext->caps());
     bool hasUserStencilSettings = !ss->isUnused();
 
     SkIRect clipConservativeBounds;
@@ -1879,7 +1900,7 @@
     canDrawArgs.fViewMatrix = &viewMatrix;
     canDrawArgs.fShape = &shape;
     canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
-    canDrawArgs.fAAType = aaType;
+    canDrawArgs.fAATypeFlags = aaTypeFlags;
     SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
     canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
     canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
@@ -1902,7 +1923,7 @@
                                       &clipConservativeBounds,
                                       &viewMatrix,
                                       &shape,
-                                      aaType,
+                                      aaTypeFlags,
                                       fRenderTargetContext->colorSpaceInfo().isLinearlyBlended()};
     pr->drawPath(args);
     return true;
@@ -1937,13 +1958,8 @@
     clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
 
     GrShape tempShape;
-    // NVPR cannot handle hairlines, so this would get picked up by a different stencil and
-    // cover path renderer (i.e. default path renderer). The hairline renderer produces much
-    // smoother hairlines than MSAA.
-    GrAllowMixedSamples allowMixedSamples = originalShape.style().isSimpleHairline()
-                                                    ? GrAllowMixedSamples::kNo
-                                                    : GrAllowMixedSamples::kYes;
-    GrAAType aaType = this->chooseAAType(aa, allowMixedSamples);
+    auto aaTypeFlags = choose_path_aa_type_flags(aa, this->fsaaType(), *this->caps());
+
     GrPathRenderer::CanDrawPathArgs canDrawArgs;
     canDrawArgs.fCaps = this->caps();
     canDrawArgs.fViewMatrix = &viewMatrix;
@@ -1958,7 +1974,7 @@
         return;
     }
 
-    canDrawArgs.fAAType = aaType;
+    canDrawArgs.fAATypeFlags = aaTypeFlags;
 
     // Try a 1st time without applying any of the style to the geometry (and barring sw)
     pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
@@ -2003,7 +2019,7 @@
                                       &clipConservativeBounds,
                                       &viewMatrix,
                                       canDrawArgs.fShape,
-                                      aaType,
+                                      aaTypeFlags,
                                       this->colorSpaceInfo().isLinearlyBlended()};
     pr->drawPath(args);
 }
diff --git a/src/gpu/GrRenderTargetContextPriv.h b/src/gpu/GrRenderTargetContextPriv.h
index 3e3b619..0858749 100644
--- a/src/gpu/GrRenderTargetContextPriv.h
+++ b/src/gpu/GrRenderTargetContextPriv.h
@@ -62,13 +62,12 @@
      */
     void absClear(const SkIRect* rect, const SkPMColor4f& color);
 
-    void stencilRect(const GrHardClip&,
-                     const GrUserStencilSettings* ss,
-                     GrAAType,
-                     const SkMatrix& viewMatrix,
-                     const SkRect& rect);
+    void stencilRect(
+            const GrHardClip&, const GrUserStencilSettings* ss, GrAA doStencilMSAA,
+            const SkMatrix& viewMatrix, const SkRect& rect);
 
-    void stencilPath(const GrHardClip&, GrAAType, const SkMatrix& viewMatrix, const GrPath*);
+    void stencilPath(
+            const GrHardClip&, GrAA doStencilMSAA, const SkMatrix& viewMatrix, const GrPath*);
 
     /**
      * Draws a rect, either AA or not, and touches the stencil buffer with the user stencil settings
@@ -78,7 +77,7 @@
                             const GrUserStencilSettings*,
                             SkRegion::Op op,
                             bool invert,
-                            GrAA,
+                            GrAA doStencilMSAA,
                             const SkMatrix& viewMatrix,
                             const SkRect&);
 
@@ -90,7 +89,7 @@
                             const GrUserStencilSettings*,
                             SkRegion::Op op,
                             bool invert,
-                            GrAA,
+                            GrAA doStencilMSAA,
                             const SkMatrix& viewMatrix,
                             const SkPath&);
 
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index 2264141..2fee0fb 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -32,7 +32,7 @@
     // Pass on any style that applies. The caller will apply the style if a suitable renderer is
     // not found and try again with the new GrShape.
     if (!args.fShape->style().applies() && SkToBool(fProxyProvider) &&
-        (args.fAAType == GrAAType::kCoverage || args.fAAType == GrAAType::kNone)) {
+        ((args.fAATypeFlags & AATypeFlags::kCoverage) || args.fAATypeFlags == AATypeFlags::kNone)) {
         // This is the fallback renderer for when a path is too complicated for the GPU ones.
         return CanDrawPath::kAsBackup;
     }
@@ -257,7 +257,7 @@
     // To prevent overloading the cache with entries during animations we limit the cache of masks
     // to cases where the matrix preserves axis alignment.
     bool useCache = fAllowCaching && !inverseFilled && args.fViewMatrix->preservesAxisAlignment() &&
-                    args.fShape->hasUnstyledKey() && GrAAType::kCoverage == args.fAAType;
+                    args.fShape->hasUnstyledKey() && (AATypeFlags::kCoverage & args.fAATypeFlags);
 
     if (!GetShapeAndClipBounds(args.fRenderTargetContext,
                                *args.fClip, *args.fShape,
@@ -332,7 +332,7 @@
     }
     if (!proxy) {
         SkBackingFit fit = useCache ? SkBackingFit::kExact : SkBackingFit::kApprox;
-        GrAA aa = GrAAType::kCoverage == args.fAAType ? GrAA::kYes : GrAA::kNo;
+        GrAA aa = GrAA(SkToBool(AATypeFlags::kCoverage & args.fAATypeFlags));
 
         SkTaskGroup* taskGroup = nullptr;
         if (auto direct = args.fContext->priv().asDirectContext()) {
diff --git a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
index 077b0ec..484bd08 100644
--- a/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
+++ b/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp
@@ -56,7 +56,7 @@
 GrPathRenderer::CanDrawPath GrCoverageCountingPathRenderer::onCanDrawPath(
         const CanDrawPathArgs& args) const {
     const GrShape& shape = *args.fShape;
-    if (GrAAType::kCoverage != args.fAAType || shape.style().hasPathEffect() ||
+    if (!(AATypeFlags::kCoverage & args.fAATypeFlags) || shape.style().hasPathEffect() ||
         args.fViewMatrix->hasPerspective() || shape.inverseFilled()) {
         return CanDrawPath::kNo;
     }
diff --git a/src/gpu/ops/GrAAConvexPathRenderer.cpp b/src/gpu/ops/GrAAConvexPathRenderer.cpp
index bb45932..294649c 100644
--- a/src/gpu/ops/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAAConvexPathRenderer.cpp
@@ -654,7 +654,7 @@
 GrPathRenderer::CanDrawPath
 GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     if (args.fCaps->shaderCaps()->shaderDerivativeSupport() &&
-        (GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() &&
+        (AATypeFlags::kCoverage & args.fAATypeFlags) && args.fShape->style().isSimpleFill() &&
         !args.fShape->inverseFilled() && args.fShape->knownToBeConvex()) {
         return CanDrawPath::kYes;
     }
diff --git a/src/gpu/ops/GrAAHairLinePathRenderer.cpp b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
index b97e578..46a32fe 100644
--- a/src/gpu/ops/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/ops/GrAAHairLinePathRenderer.cpp
@@ -713,7 +713,7 @@
 
 GrPathRenderer::CanDrawPath
 GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    if (GrAAType::kCoverage != args.fAAType) {
+    if (!(AATypeFlags::kCoverage & args.fAATypeFlags)) {
         return CanDrawPath::kNo;
     }
 
diff --git a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
index 74a5572..22dc05a 100644
--- a/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp
@@ -39,7 +39,7 @@
 
 GrPathRenderer::CanDrawPath
 GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    if (GrAAType::kCoverage != args.fAAType) {
+    if (!(AATypeFlags::kCoverage & args.fAATypeFlags)) {
         return CanDrawPath::kNo;
     }
     if (!args.fShape->knownToBeConvex()) {
diff --git a/src/gpu/ops/GrDashLinePathRenderer.cpp b/src/gpu/ops/GrDashLinePathRenderer.cpp
index 5e9b369..6bd8441 100644
--- a/src/gpu/ops/GrDashLinePathRenderer.cpp
+++ b/src/gpu/ops/GrDashLinePathRenderer.cpp
@@ -18,7 +18,7 @@
     SkPoint pts[2];
     bool inverted;
     if (args.fShape->style().isDashed() && args.fShape->asLine(pts, &inverted)) {
-        if (args.fAAType == GrAAType::kMixedSamples) {
+        if (args.fAATypeFlags == AATypeFlags::kMixedSampledStencilThenCover) {
             return CanDrawPath::kNo;
         }
         // We should never have an inverse dashed case.
@@ -35,18 +35,15 @@
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
                               "GrDashLinePathRenderer::onDrawPath");
     GrDashOp::AAMode aaMode = GrDashOp::AAMode::kNone;
-    switch (args.fAAType) {
-        case GrAAType::kNone:
-            break;
-        case GrAAType::kCoverage:
-        case GrAAType::kMixedSamples:
-            aaMode = GrDashOp::AAMode::kCoverage;
-            break;
-        case GrAAType::kMSAA:
+    if (AATypeFlags::kNone != args.fAATypeFlags) {
+        if (AATypeFlags::kMSAA & args.fAATypeFlags) {
             // In this mode we will use aa between dashes but the outer border uses MSAA. Otherwise,
             // we can wind up with external edges antialiased and internal edges unantialiased.
             aaMode = GrDashOp::AAMode::kCoverageWithMSAA;
-            break;
+        } else {
+            SkASSERT(AATypeFlags::kCoverage & args.fAATypeFlags);
+            aaMode = GrDashOp::AAMode::kCoverage;
+        }
     }
     SkPoint pts[2];
     SkAssertResult(args.fShape->asLine(pts, nullptr));
diff --git a/src/gpu/ops/GrDefaultPathRenderer.cpp b/src/gpu/ops/GrDefaultPathRenderer.cpp
index 04444d0..6eb257b 100644
--- a/src/gpu/ops/GrDefaultPathRenderer.cpp
+++ b/src/gpu/ops/GrDefaultPathRenderer.cpp
@@ -637,15 +637,19 @@
 
 GrPathRenderer::CanDrawPath
 GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    bool isHairline = IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr);
+    bool isHairline = IsStrokeHairlineOrEquivalent(
+            args.fShape->style(), *args.fViewMatrix, nullptr);
     // If we aren't a single_pass_shape or hairline, we require stencil buffers.
     if (!(single_pass_shape(*args.fShape) || isHairline) &&
         (args.fCaps->avoidStencilBuffers() || args.fTargetIsWrappedVkSecondaryCB)) {
         return CanDrawPath::kNo;
     }
-    // This can draw any path with any simple fill style but doesn't do coverage-based antialiasing.
-    if (GrAAType::kCoverage == args.fAAType ||
-        (!args.fShape->style().isSimpleFill() && !isHairline)) {
+    // If antialiasing is required, we only support MSAA.
+    if (AATypeFlags::kNone != args.fAATypeFlags && !(AATypeFlags::kMSAA & args.fAATypeFlags)) {
+        return CanDrawPath::kNo;
+    }
+    // This can draw any path with any simple fill style.
+    if (!args.fShape->style().isSimpleFill() && !isHairline) {
         return CanDrawPath::kNo;
     }
     // This is the fallback renderer for when a path is too complicated for the others to draw.
@@ -655,14 +659,13 @@
 bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
                               "GrDefaultPathRenderer::onDrawPath");
-    return this->internalDrawPath(args.fRenderTargetContext,
-                                  std::move(args.fPaint),
-                                  args.fAAType,
-                                  *args.fUserStencilSettings,
-                                  *args.fClip,
-                                  *args.fViewMatrix,
-                                  *args.fShape,
-                                  false);
+    GrAAType aaType = (AATypeFlags::kNone != args.fAATypeFlags)
+            ? GrAAType::kMSAA
+            : GrAAType::kNone;
+
+    return this->internalDrawPath(
+            args.fRenderTargetContext, std::move(args.fPaint), aaType, *args.fUserStencilSettings,
+            *args.fClip, *args.fViewMatrix, *args.fShape, false);
 }
 
 void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
@@ -673,9 +676,11 @@
     GrPaint paint;
     paint.setXPFactory(GrDisableColorXPFactory::Get());
 
-    this->internalDrawPath(args.fRenderTargetContext, std::move(paint), args.fAAType,
-                           GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix,
-                           *args.fShape, true);
+    auto aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
+
+    this->internalDrawPath(
+            args.fRenderTargetContext, std::move(paint), aaType, GrUserStencilSettings::kUnused,
+            *args.fClip, *args.fViewMatrix, *args.fShape, true);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/ops/GrDrawPathOp.cpp b/src/gpu/ops/GrDrawPathOp.cpp
index f73bbbe..acbcf94 100644
--- a/src/gpu/ops/GrDrawPathOp.cpp
+++ b/src/gpu/ops/GrDrawPathOp.cpp
@@ -25,12 +25,12 @@
 };
 
 GrDrawPathOpBase::GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&& paint,
-                                   GrPathRendering::FillType fill, GrAAType aaType)
+                                   GrPathRendering::FillType fill, GrAA aa)
         : INHERITED(classID)
         , fViewMatrix(viewMatrix)
         , fInputColor(paint.getColor4f())
         , fFillType(fill)
-        , fAAType(aaType)
+        , fDoAA(GrAA::kYes == aa)
         , fProcessorSet(std::move(paint)) {}
 
 #ifdef SK_DEBUG
@@ -44,7 +44,7 @@
 
 GrPipeline::InitArgs GrDrawPathOpBase::pipelineInitArgs(const GrOpFlushState& state) {
     GrPipeline::InitArgs args;
-    if (GrAATypeIsHW(fAAType)) {
+    if (fDoAA) {
         args.fFlags |= GrPipeline::kHWAntialias_Flag;
     }
     args.fUserStencil = &kCoverPass;
@@ -77,11 +77,11 @@
 std::unique_ptr<GrDrawOp> GrDrawPathOp::Make(GrRecordingContext* context,
                                              const SkMatrix& viewMatrix,
                                              GrPaint&& paint,
-                                             GrAAType aaType,
+                                             GrAA aa,
                                              GrPath* path) {
     GrOpMemoryPool* pool = context->priv().opMemoryPool();
 
-    return pool->allocate<GrDrawPathOp>(viewMatrix, std::move(paint), aaType, path);
+    return pool->allocate<GrDrawPathOp>(viewMatrix, std::move(paint), aa, path);
 }
 
 void GrDrawPathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
diff --git a/src/gpu/ops/GrDrawPathOp.h b/src/gpu/ops/GrDrawPathOp.h
index 89a294f..d2447bb 100644
--- a/src/gpu/ops/GrDrawPathOp.h
+++ b/src/gpu/ops/GrDrawPathOp.h
@@ -22,13 +22,12 @@
 class GrDrawPathOpBase : public GrDrawOp {
 protected:
     GrDrawPathOpBase(uint32_t classID, const SkMatrix& viewMatrix, GrPaint&&,
-                     GrPathRendering::FillType, GrAAType);
+                     GrPathRendering::FillType, GrAA);
 
     FixedFunctionFlags fixedFunctionFlags() const override {
-        if (GrAATypeIsHW(fAAType)) {
-            return FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil;
-        }
-        return FixedFunctionFlags::kUsesStencil;
+        return (fDoAA)
+                ? FixedFunctionFlags::kUsesHWAA | FixedFunctionFlags::kUsesStencil
+                : FixedFunctionFlags::kUsesStencil;
     }
     GrProcessorSet::Analysis finalize(
             const GrCaps& caps, const GrAppliedClip* clip, GrFSAAType fsaaType) override {
@@ -60,7 +59,7 @@
     SkPMColor4f fInputColor;
     GrProcessorSet::Analysis fAnalysis;
     GrPathRendering::FillType fFillType;
-    GrAAType fAAType;
+    bool fDoAA;
     GrProcessorSet fProcessorSet;
 
     typedef GrDrawOp INHERITED;
@@ -70,11 +69,8 @@
 public:
     DEFINE_OP_CLASS_ID
 
-    static std::unique_ptr<GrDrawOp> Make(GrRecordingContext*,
-                                          const SkMatrix& viewMatrix,
-                                          GrPaint&&,
-                                          GrAAType,
-                                          GrPath*);
+    static std::unique_ptr<GrDrawOp> Make(
+            GrRecordingContext*, const SkMatrix& viewMatrix, GrPaint&&, GrAA, GrPath*);
 
     const char* name() const override { return "DrawPath"; }
 
@@ -85,8 +81,9 @@
 private:
     friend class GrOpMemoryPool; // for ctor
 
-    GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAAType aaType, const GrPath* path)
-            : GrDrawPathOpBase(ClassID(), viewMatrix, std::move(paint), path->getFillType(), aaType)
+    GrDrawPathOp(const SkMatrix& viewMatrix, GrPaint&& paint, GrAA aa, const GrPath* path)
+            : GrDrawPathOpBase(
+                    ClassID(), viewMatrix, std::move(paint), path->getFillType(), aa)
             , fPath(path) {
         this->setTransformedBounds(path->getBounds(), viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
     }
diff --git a/src/gpu/ops/GrSmallPathRenderer.cpp b/src/gpu/ops/GrSmallPathRenderer.cpp
index e04c307..f7b1af3 100644
--- a/src/gpu/ops/GrSmallPathRenderer.cpp
+++ b/src/gpu/ops/GrSmallPathRenderer.cpp
@@ -188,7 +188,7 @@
         return CanDrawPath::kNo;
     }
     // This does non-inverse coverage-based antialiased fills.
-    if (GrAAType::kCoverage != args.fAAType) {
+    if (!(AATypeFlags::kCoverage & args.fAATypeFlags)) {
         return CanDrawPath::kNo;
     }
     // TODO: Support inverse fill
diff --git a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
index 68782d3..1da8fa5 100644
--- a/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp
@@ -46,7 +46,7 @@
         return CanDrawPath::kNo;
     }
     // doesn't do per-path AA, relies on the target having MSAA.
-    if (GrAAType::kCoverage == args.fAAType) {
+    if (AATypeFlags::kCoverage == args.fAATypeFlags) {
         return CanDrawPath::kNo;
     }
     return CanDrawPath::kYes;
@@ -81,8 +81,8 @@
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
                               "GrStencilAndCoverPathRenderer::onStencilPath");
     sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape));
-    args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType,
-                                                  *args.fViewMatrix, p.get());
+    args.fRenderTargetContext->priv().stencilPath(
+            *args.fClip, args.fDoStencilMSAA, *args.fViewMatrix, p.get());
 }
 
 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
@@ -92,6 +92,9 @@
 
     const SkMatrix& viewMatrix = *args.fViewMatrix;
 
+    bool doStencilMSAA = AATypeFlags::kNone != args.fAATypeFlags;
+    SkASSERT(!doStencilMSAA ||
+             (AATypeFlags::kMSAA | AATypeFlags::kMixedSampledStencilThenCover) & args.fAATypeFlags);
 
     sk_sp<GrPath> path(get_gr_path(fResourceProvider, *args.fShape));
 
@@ -106,8 +109,9 @@
 
         // fake inverse with a stencil and cover
         GrAppliedClip appliedClip;
-        if (!args.fClip->apply(args.fContext, args.fRenderTargetContext,
-                               GrAATypeIsHW(args.fAAType), true, &appliedClip, &devBounds)) {
+        if (!args.fClip->apply(
+                args.fContext, args.fRenderTargetContext, doStencilMSAA, true, &appliedClip,
+                &devBounds)) {
             return true;
         }
         GrStencilClip stencilClip(appliedClip.stencilStackID());
@@ -120,8 +124,8 @@
         }
         // Just ignore the analytic FPs (if any) during the stencil pass. They will still clip the
         // final draw and it is meaningless to multiply by coverage when drawing to stencil.
-        args.fRenderTargetContext->priv().stencilPath(stencilClip, args.fAAType, viewMatrix,
-                                                      path.get());
+        args.fRenderTargetContext->priv().stencilPath(
+                stencilClip, GrAA(doStencilMSAA), viewMatrix, path.get());
 
         {
             static constexpr GrUserStencilSettings kInvertedCoverPass(
@@ -153,23 +157,22 @@
 
             // We have to suppress enabling MSAA for mixed samples or we will get seams due to
             // coverage modulation along the edge where two triangles making up the rect meet.
-            GrAAType coverAAType = args.fAAType;
-            if (GrAAType::kMixedSamples == coverAAType) {
-                coverAAType = GrAAType::kNone;
+            GrAAType coverAAType = GrAAType::kNone;
+            if (AATypeFlags::kMSAA & args.fAATypeFlags) {
+                SkASSERT(!(AATypeFlags::kMixedSampledStencilThenCover & args.fAATypeFlags));
+                coverAAType = GrAAType::kMSAA;
             }
             // This is a non-coverage aa rect operation
             SkASSERT(coverAAType == GrAAType::kNone || coverAAType == GrAAType::kMSAA);
             std::unique_ptr<GrDrawOp> op = GrFillRectOp::MakeWithLocalMatrix(
-                                                         args.fContext, std::move(args.fPaint),
-                                                         coverAAType, coverMatrix, localMatrix,
-                                                         coverBounds, &kInvertedCoverPass);
+                    args.fContext, std::move(args.fPaint), coverAAType, coverMatrix, localMatrix,
+                    coverBounds, &kInvertedCoverPass);
 
             args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
         }
     } else {
-        std::unique_ptr<GrDrawOp> op =
-                GrDrawPathOp::Make(args.fContext, viewMatrix, std::move(args.fPaint),
-                                   args.fAAType, path.get());
+        std::unique_ptr<GrDrawOp> op = GrDrawPathOp::Make(
+                args.fContext, viewMatrix, std::move(args.fPaint), GrAA(doStencilMSAA), path.get());
         args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
     }
 
diff --git a/src/gpu/ops/GrTessellatingPathRenderer.cpp b/src/gpu/ops/GrTessellatingPathRenderer.cpp
index 09f09ad..41ec465 100644
--- a/src/gpu/ops/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/ops/GrTessellatingPathRenderer.cpp
@@ -145,21 +145,25 @@
     // This path renderer can draw fill styles, and can do screenspace antialiasing via a
     // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
     // ones to simpler algorithms. We pass on paths that have styles, though they may come back
-    // around after applying the styling information to the geometry to create a filled path. In
-    // the non-AA case, We skip paths that don't have a key since the real advantage of this path
-    // renderer comes from caching the tessellated geometry. In the AA case, we do not cache, so we
-    // accept paths without keys.
+    // around after applying the styling information to the geometry to create a filled path.
     if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
         return CanDrawPath::kNo;
     }
-    if (GrAAType::kCoverage == args.fAAType) {
+    if (AATypeFlags::kNone == args.fAATypeFlags || (AATypeFlags::kMSAA & args.fAATypeFlags)) {
+        // Prefer MSAA, if any antialiasing. In the non-analytic-AA case, We skip paths that don't
+        // have a key since the real advantage of this path renderer comes from caching the
+        // tessellated geometry.
+        if (!args.fShape->hasUnstyledKey()) {
+            return CanDrawPath::kNo;
+        }
+    } else if (AATypeFlags::kCoverage & args.fAATypeFlags) {
+        // Use analytic AA if we don't have MSAA. In this case, we do not cache, so we accept paths
+        // without keys.
         SkPath path;
         args.fShape->asPath(&path);
         if (path.countVerbs() > GR_AA_TESSELLATOR_MAX_VERB_COUNT) {
             return CanDrawPath::kNo;
         }
-    } else if (!args.fShape->hasUnstyledKey()) {
-        return CanDrawPath::kNo;
     }
     return CanDrawPath::kYes;
 }
@@ -390,13 +394,15 @@
     args.fClip->getConservativeBounds(args.fRenderTargetContext->width(),
                                       args.fRenderTargetContext->height(),
                                       &clipBoundsI);
-    std::unique_ptr<GrDrawOp> op = TessellatingPathOp::Make(args.fContext,
-                                                            std::move(args.fPaint),
-                                                            *args.fShape,
-                                                            *args.fViewMatrix,
-                                                            clipBoundsI,
-                                                            args.fAAType,
-                                                            args.fUserStencilSettings);
+    GrAAType aaType = GrAAType::kNone;
+    if (AATypeFlags::kMSAA & args.fAATypeFlags) {
+        aaType = GrAAType::kMSAA;
+    } else if (AATypeFlags::kCoverage & args.fAATypeFlags) {
+        aaType = GrAAType::kCoverage;
+    }
+    std::unique_ptr<GrDrawOp> op = TessellatingPathOp::Make(
+            args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, clipBoundsI,
+            aaType, args.fUserStencilSettings);
     args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
     return true;
 }