Relandx2 "Remove antialiasing control from GrPaint."

Fixes a bad merge.

This reverts commit 073285c0595d46205d1482cc19af2d7d891bfeae.

Change-Id: I5e92339d9b33d3a6dc58b9fcd2a1b3a5684e8f8a
Reviewed-on: https://skia-review.googlesource.com/5774
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/core/SkGpuBlurUtils.cpp b/src/core/SkGpuBlurUtils.cpp
index 2ae398d..e3463a4 100644
--- a/src/core/SkGpuBlurUtils.cpp
+++ b/src/core/SkGpuBlurUtils.cpp
@@ -84,7 +84,7 @@
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     SkMatrix localMatrix = SkMatrix::MakeTrans(-SkIntToScalar(srcOffset.x()),
                                                -SkIntToScalar(srcOffset.y()));
-    renderTargetContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(),
+    renderTargetContext->fillRectWithLocalMatrix(clip, paint, GrAA::kNo, SkMatrix::I(),
                                                  SkRect::Make(dstRect), localMatrix);
 }
 
@@ -112,7 +112,7 @@
             true, sigmaX, sigmaY));
     paint.addColorFragmentProcessor(std::move(conv));
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    renderTargetContext->fillRectWithLocalMatrix(clip, paint, SkMatrix::I(),
+    renderTargetContext->fillRectWithLocalMatrix(clip, paint, GrAA::kNo, SkMatrix::I(),
                                                  SkRect::Make(dstRect), localMatrix);
 }
 
@@ -289,7 +289,7 @@
         paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
         shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY);
 
-        dstRenderTargetContext->fillRectToRect(clip, paint, SkMatrix::I(),
+        dstRenderTargetContext->fillRectToRect(clip, paint, GrAA::kNo, SkMatrix::I(),
                                                SkRect::Make(dstRect), SkRect::Make(srcRect));
 
         srcRenderTargetContext = dstRenderTargetContext;
@@ -381,7 +381,7 @@
         SkIRect dstRect(srcRect);
         scale_irect(&dstRect, scaleFactorX, scaleFactorY);
 
-        dstRenderTargetContext->fillRectToRect(clip, paint, SkMatrix::I(),
+        dstRenderTargetContext->fillRectToRect(clip, paint, GrAA::kNo, SkMatrix::I(),
                                                SkRect::Make(dstRect), SkRect::Make(srcRect));
 
         srcRenderTargetContext = dstRenderTargetContext;
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index df46a13..2ec441f 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -297,7 +297,7 @@
     SkRect srcRect = SkRect::Make(bounds);
     SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height());
     GrFixedClip clip(dstIRect);
-    renderTargetContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
+    renderTargetContext->fillRectToRect(clip, paint, GrAA::kNo, SkMatrix::I(), dstRect, srcRect);
 
     return SkSpecialImage::MakeDeferredFromGpu(context, dstIRect,
                                                kNeedNewImageUniqueID_SpecialImage,
diff --git a/src/effects/SkAlphaThresholdFilter.cpp b/src/effects/SkAlphaThresholdFilter.cpp
index 43751e1..6cf1ce6 100644
--- a/src/effects/SkAlphaThresholdFilter.cpp
+++ b/src/effects/SkAlphaThresholdFilter.cpp
@@ -114,7 +114,7 @@
     GrFixedClip clip(SkIRect::MakeWH(bounds.width(), bounds.height()));
     while (!iter.done()) {
         SkRect rect = SkRect::Make(iter.rect());
-        rtContext->drawRect(clip, grPaint, inMatrix, rect);
+        rtContext->drawRect(clip, grPaint, GrAA::kNo, inMatrix, rect);
         iter.next();
     }
 
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index e8867ea..0b1d1db 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -1060,7 +1060,8 @@
         return false;
     }
 
-    renderTargetContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), rect, inverse);
+    renderTargetContext->fillRectWithLocalMatrix(clip, *grp, GrAA::kNo, SkMatrix::I(), rect,
+                                                 inverse);
     return true;
 }
 
@@ -1103,8 +1104,7 @@
 static sk_sp<GrTexture> find_or_create_rrect_blur_mask(GrContext* context,
                                                        const SkRRect& rrectToDraw,
                                                        const SkISize& size,
-                                                       float xformedSigma,
-                                                       bool doAA) {
+                                                       float xformedSigma) {
     static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
     GrUniqueKey key;
     GrUniqueKey::Builder builder(&key, kDomain, 9);
@@ -1129,10 +1129,10 @@
         }
 
         GrPaint grPaint;
-        grPaint.setAntiAlias(doAA);
 
         rtc->clear(nullptr, 0x0, true);
-        rtc->drawRRect(GrNoClip(), grPaint, SkMatrix::I(), rrectToDraw, GrStyle::SimpleFill());
+        rtc->drawRRect(GrNoClip(), grPaint, GrAA::kYes, SkMatrix::I(), rrectToDraw,
+                       GrStyle::SimpleFill());
 
         sk_sp<GrTexture> srcTexture(rtc->asTexture());
         if (!srcTexture) {
@@ -1192,8 +1192,7 @@
         return nullptr;
     }
 
-    sk_sp<GrTexture> mask(find_or_create_rrect_blur_mask(context, rrectToDraw, size,
-                                                         xformedSigma, true));
+    sk_sp<GrTexture> mask(find_or_create_rrect_blur_mask(context, rrectToDraw, size, xformedSigma));
     if (!mask) {
         return nullptr;
     }
@@ -1380,12 +1379,11 @@
 
         GrPaint newPaint(*grp);
         newPaint.addCoverageFragmentProcessor(std::move(fp));
-        newPaint.setAntiAlias(false);
 
         SkRect srcProxyRect = srcRRect.rect();
         srcProxyRect.outset(3.0f*fSigma, 3.0f*fSigma);
 
-        renderTargetContext->drawRect(clip, newPaint, viewMatrix, srcProxyRect);
+        renderTargetContext->drawRect(clip, newPaint, GrAA::kNo, viewMatrix, srcProxyRect);
         return true;
     }
 
@@ -1397,7 +1395,6 @@
 
     GrPaint newPaint(*grp);
     newPaint.addCoverageFragmentProcessor(std::move(fp));
-    newPaint.setAntiAlias(false);
 
     if (!this->ignoreXform()) {
         SkRect srcProxyRect = srcRRect.rect();
@@ -1444,8 +1441,8 @@
         proxyRect.outset(extra, extra);
 
 
-        renderTargetContext->fillRectWithLocalMatrix(clip, newPaint, SkMatrix::I(), proxyRect,
-                                                     inverse);
+        renderTargetContext->fillRectWithLocalMatrix(clip, newPaint, GrAA::kNo, SkMatrix::I(),
+                                                     proxyRect, inverse);
     }
 
     return true;
@@ -1538,7 +1535,8 @@
             paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
         }
 
-        renderTargetContext->drawRect(GrNoClip(), paint, SkMatrix::I(), SkRect::Make(clipRect));
+        renderTargetContext->drawRect(GrNoClip(), paint, GrAA::kNo, SkMatrix::I(),
+                                      SkRect::Make(clipRect));
     }
 
     *result = renderTargetContext->asTexture().release();
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index 2d79f9a..661dacd 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -360,7 +360,8 @@
         }
         paint.setGammaCorrect(renderTargetContext->isGammaCorrect());
 
-        renderTargetContext->drawRect(GrNoClip(), paint, matrix, SkRect::Make(colorBounds));
+        renderTargetContext->drawRect(GrNoClip(), paint, GrAA::kNo, matrix,
+                                      SkRect::Make(colorBounds));
 
         offset->fX = bounds.left();
         offset->fY = bounds.top();
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index 75947e8..52c8947 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -400,7 +400,7 @@
                                                               boundaryMode));
     paint.addColorFragmentProcessor(std::move(fp));
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    renderTargetContext->fillRectToRect(clip, paint, SkMatrix::I(), dstRect, srcRect);
+    renderTargetContext->fillRectToRect(clip, paint, GrAA::kNo, SkMatrix::I(), dstRect, srcRect);
 }
 
 sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU(
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index 2fa67a4..130f099 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -407,7 +407,8 @@
     paint.addColorFragmentProcessor(GrMorphologyEffect::Make(tex, direction, radius, morphType,
                                                              bounds));
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    renderTargetContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
+    renderTargetContext->fillRectToRect(clip, paint, GrAA::kNo,
+                                        SkMatrix::I(), SkRect::Make(dstRect),
                                         SkRect::Make(srcRect));
 }
 
@@ -428,8 +429,8 @@
     }
     paint.addColorFragmentProcessor(GrMorphologyEffect::Make(tex, direction, radius, morphType));
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-    renderTargetContext->fillRectToRect(clip, paint, SkMatrix::I(), SkRect::Make(dstRect),
-                                        SkRect::Make(srcRect));
+    renderTargetContext->fillRectToRect(clip, paint, GrAA::kNo, SkMatrix::I(),
+                                        SkRect::Make(dstRect), SkRect::Make(srcRect));
 }
 
 static void apply_morphology_pass(GrTextureProvider* provider,
diff --git a/src/effects/SkShadowMaskFilter.cpp b/src/effects/SkShadowMaskFilter.cpp
index 958ab17..5c54072 100755
--- a/src/effects/SkShadowMaskFilter.cpp
+++ b/src/effects/SkShadowMaskFilter.cpp
@@ -252,7 +252,6 @@
         const SkScalar devSpaceAmbientRadius = srcSpaceAmbientRadius * scaleFactor;
 
         GrPaint newPaint(*grp);
-        newPaint.setAntiAlias(true);
         GrColor4f color = newPaint.getColor4f();
         color.fRGBA[3] *= fAmbientAlpha;
         newPaint.setColor4f(color);
@@ -311,7 +310,6 @@
                               (spotShadowRRect.width() + srcSpaceSpotRadius);
 
         GrPaint newPaint(*grp);
-        newPaint.setAntiAlias(true);
         GrColor4f color = newPaint.getColor4f();
         color.fRGBA[3] *= fSpotAlpha;
         newPaint.setColor4f(color);
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp
index 82d5156..3a1e6e2 100644
--- a/src/effects/SkXfermodeImageFilter.cpp
+++ b/src/effects/SkXfermodeImageFilter.cpp
@@ -303,7 +303,7 @@
 
     SkMatrix matrix;
     matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
-    renderTargetContext->drawRect(GrNoClip(), paint, matrix, SkRect::Make(bounds));
+    renderTargetContext->drawRect(GrNoClip(), paint, GrAA::kNo, matrix, SkRect::Make(bounds));
 
     return SkSpecialImage::MakeDeferredFromGpu(context,
                                                SkIRect::MakeWH(bounds.width(), bounds.height()),
diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp
index 4d89bef..7688605 100644
--- a/src/gpu/GrBlurUtils.cpp
+++ b/src/gpu/GrBlurUtils.cpp
@@ -45,8 +45,8 @@
     if (!viewMatrix.invert(&inverse)) {
         return false;
     }
-    renderTargetContext->fillRectWithLocalMatrix(clip, *grp, SkMatrix::I(), SkRect::Make(maskRect),
-                                                 inverse);
+    renderTargetContext->fillRectWithLocalMatrix(clip, *grp, GrAA::kNo, SkMatrix::I(),
+                                                 SkRect::Make(maskRect), inverse);
     return true;
 }
 
@@ -98,9 +98,9 @@
                                              const SkIRect& maskRect,
                                              const SkPath& devPath,
                                              SkStrokeRec::InitStyle fillOrHairline,
-                                             bool doAA,
+                                             GrAA aa,
                                              int sampleCnt) {
-    if (!doAA) {
+    if (GrAA::kNo == aa) {
         // Don't need MSAA if mask isn't AA
         sampleCnt = 0;
     }
@@ -115,7 +115,6 @@
     rtContext->priv().absClear(nullptr, 0x0);
 
     GrPaint tempPaint;
-    tempPaint.setAntiAlias(doAA);
     tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
 
     // setup new clip
@@ -126,7 +125,7 @@
     // the origin using tempPaint.
     SkMatrix translate;
     translate.setTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop));
-    rtContext->drawPath(clip, tempPaint, translate, devPath, GrStyle(fillOrHairline));
+    rtContext->drawPath(clip, tempPaint, aa, translate, devPath, GrStyle(fillOrHairline));
     return sk_ref_sp(rtContext->asDeferredTexture());
 }
 
@@ -134,6 +133,7 @@
                                        GrRenderTargetContext* renderTargetContext,
                                        const GrClip& clip,
                                        GrPaint* paint,
+                                       GrAA aa,
                                        const SkMatrix& viewMatrix,
                                        const SkMaskFilter* maskFilter,
                                        const GrStyle& style,
@@ -211,7 +211,7 @@
                                                         finalIRect,
                                                         *path,
                                                         fillOrHairline,
-                                                        paint->isAntiAlias(),
+                                                        aa,
                                                         renderTargetContext->numColorSamples()));
         if (maskProxy) {
             GrTexture* filtered;
@@ -242,11 +242,12 @@
                                          const GrClip& clip,
                                          const SkPath& path,
                                          GrPaint* paint,
+                                         GrAA aa,
                                          const SkMatrix& viewMatrix,
                                          const SkMaskFilter* mf,
                                          const GrStyle& style,
                                          bool pathIsMutable) {
-    draw_path_with_mask_filter(context, renderTargetContext, clip, paint, viewMatrix, mf,
+    draw_path_with_mask_filter(context, renderTargetContext, clip, paint, aa, viewMatrix, mf,
                                style, &path, pathIsMutable);
 }
 
@@ -290,14 +291,14 @@
     if (!SkPaintToGrPaint(context, renderTargetContext, paint, viewMatrix, &grPaint)) {
         return;
     }
-
+    GrAA aa = GrBoolToAA(paint.isAntiAlias());
     SkMaskFilter* mf = paint.getMaskFilter();
     if (mf && !mf->asFragmentProcessor(nullptr, nullptr, viewMatrix)) {
         // The MaskFilter wasn't already handled in SkPaintToGrPaint
-        draw_path_with_mask_filter(context, renderTargetContext, clip, &grPaint, viewMatrix,
+        draw_path_with_mask_filter(context, renderTargetContext, clip, &grPaint, aa, viewMatrix,
                                    mf, style,
                                    path, pathIsMutable);
     } else {
-        renderTargetContext->drawPath(clip, grPaint, viewMatrix, *path, style);
+        renderTargetContext->drawPath(clip, grPaint, aa, viewMatrix, *path, style);
     }
 }
diff --git a/src/gpu/GrBlurUtils.h b/src/gpu/GrBlurUtils.h
index 090448f..be0d2fb 100644
--- a/src/gpu/GrBlurUtils.h
+++ b/src/gpu/GrBlurUtils.h
@@ -8,11 +8,13 @@
 #ifndef GrBlurUtils_DEFINED
 #define GrBlurUtils_DEFINED
 
+#include "GrTypes.h"
+
 class GrClip;
 class GrContext;
-class GrRenderTargetContext;
 class GrPaint;
 class GrRenderTarget;
+class GrRenderTargetContext;
 class GrStyle;
 struct SkIRect;
 class SkMaskFilter;
@@ -48,6 +50,7 @@
                                 const GrClip&,
                                 const SkPath& path,
                                 GrPaint*,
+                                GrAA,
                                 const SkMatrix& viewMatrix,
                                 const SkMaskFilter*,
                                 const GrStyle&,
diff --git a/src/gpu/GrClipStackClip.cpp b/src/gpu/GrClipStackClip.cpp
index e2ce046..1172bc6 100644
--- a/src/gpu/GrClipStackClip.cpp
+++ b/src/gpu/GrClipStackClip.cpp
@@ -42,7 +42,7 @@
                                                   SkIntToScalar(fOrigin.fY)));
 }
 
-bool GrClipStackClip::isRRect(const SkRect& origRTBounds, SkRRect* rr, bool* aa) const {
+bool GrClipStackClip::isRRect(const SkRect& origRTBounds, SkRRect* rr, GrAA* aa) const {
     if (!fStack) {
         return false;
     }
@@ -54,7 +54,9 @@
         tempRTBounds.offset(SkIntToScalar(fOrigin.fX), SkIntToScalar(fOrigin.fY));
         rtBounds = &tempRTBounds;
     }
-    if (fStack->isRRect(*rtBounds, rr, aa)) {
+    bool isAA;
+    if (fStack->isRRect(*rtBounds, rr, &isAA)) {
+        *aa = GrBoolToAA(isAA);
         if (origin) {
             rr->offset(-SkIntToScalar(fOrigin.fX), -SkIntToScalar(fOrigin.fY));
         }
@@ -132,9 +134,16 @@
         canDrawArgs.fShaderCaps = context->caps()->shaderCaps();
         canDrawArgs.fViewMatrix = &viewMatrix;
         canDrawArgs.fShape = &shape;
-        canDrawArgs.fAntiAlias = element->isAA();
+        if (!element->isAA()) {
+            canDrawArgs.fAAType = GrAAType::kNone;
+        } else if (renderTargetContext->isUnifiedMultisampled()) {
+            canDrawArgs.fAAType = GrAAType::kMSAA;
+        } else if (renderTargetContext->isStencilBufferMultisampled()){
+            canDrawArgs.fAAType = GrAAType::kMixedSamples;
+        } else {
+            canDrawArgs.fAAType = GrAAType::kCoverage;
+        }
         canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
-        canDrawArgs.fIsStencilBufferMSAA = renderTargetContext->isStencilBufferMultisampled();
 
         // the 'false' parameter disallows use of the SW path renderer
         GrPathRenderer* pr =
@@ -450,6 +459,7 @@
     for (ElementList::Iter iter(reducedClip.elements()); iter.get(); iter.next()) {
         const Element* element = iter.get();
         SkClipOp op = element->getOp();
+        GrAA aa = GrBoolToAA(element->isAA());
 
         if (kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op) {
             // Intersect and reverse difference require modifying pixels outside of the geometry
@@ -459,25 +469,25 @@
             if (kReverseDifference_SkClipOp == op) {
                 SkRect temp = SkRect::Make(reducedClip.ibounds());
                 // invert the entire scene
-                helper.drawRect(temp, SkRegion::kXOR_Op, false, 0xFF);
+                helper.drawRect(temp, SkRegion::kXOR_Op, GrAA::kNo, 0xFF);
             }
             SkPath clipPath;
             element->asPath(&clipPath);
             clipPath.toggleInverseFillType();
             GrShape shape(clipPath, GrStyle::SimpleFill());
-            helper.drawShape(shape, SkRegion::kReplace_Op, element->isAA(), 0x00);
+            helper.drawShape(shape, SkRegion::kReplace_Op, aa, 0x00);
             continue;
         }
 
         // The other ops (union, xor, diff) only affect pixels inside
         // the geometry so they can just be drawn normally
         if (Element::kRect_Type == element->getType()) {
-            helper.drawRect(element->getRect(), (SkRegion::Op)op, element->isAA(), 0xFF);
+            helper.drawRect(element->getRect(), (SkRegion::Op)op, aa, 0xFF);
         } else {
             SkPath path;
             element->asPath(&path);
             GrShape shape(path, GrStyle::SimpleFill());
-            helper.drawShape(shape, (SkRegion::Op)op, element->isAA(), 0xFF);
+            helper.drawShape(shape, (SkRegion::Op)op, aa, 0xFF);
         }
     }
 
diff --git a/src/gpu/GrClipStackClip.h b/src/gpu/GrClipStackClip.h
index afda3eb..42bd373 100644
--- a/src/gpu/GrClipStackClip.h
+++ b/src/gpu/GrClipStackClip.h
@@ -38,7 +38,7 @@
     bool apply(GrContext*, GrRenderTargetContext*, bool useHWAA, bool hasUserStencilSettings,
                GrAppliedClip* out) const final;
 
-    bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const override;
+    bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const override;
 
 private:
     static bool PathNeedsSWRenderer(GrContext* context,
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 34b9abf..ff5b026 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -366,7 +366,7 @@
             paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
             paint.setAllowSRGBInputs(true);
             SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
-            renderTargetContext->drawRect(GrNoClip(), paint, matrix, rect, nullptr);
+            renderTargetContext->drawRect(GrNoClip(), paint, GrAA::kNo, matrix, rect, nullptr);
 
             if (kFlushWrites_PixelOp & pixelOpsFlags) {
                 this->flushSurfaceWrites(surface);
@@ -486,7 +486,7 @@
                 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
                 paint.setAllowSRGBInputs(true);
                 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
-                tempRTC->drawRect(GrNoClip(), paint, SkMatrix::I(), rect, nullptr);
+                tempRTC->drawRect(GrNoClip(), paint, GrAA::kNo, SkMatrix::I(), rect, nullptr);
                 surfaceToRead.reset(tempRTC->asTexture().release());
                 left = 0;
                 top = 0;
diff --git a/src/gpu/GrDrawingManager.cpp b/src/gpu/GrDrawingManager.cpp
index c82f49a..9cbdbbe 100644
--- a/src/gpu/GrDrawingManager.cpp
+++ b/src/gpu/GrDrawingManager.cpp
@@ -222,7 +222,9 @@
                     new GrSoftwarePathRenderer(fContext->textureProvider(),
                                                fOptionsForPathRendererChain.fAllowPathMaskCaching);
         }
-        pr = fSoftwarePathRenderer;
+        if (fSoftwarePathRenderer->canDrawPath(args)) {
+            pr = fSoftwarePathRenderer;
+        }
     }
 
     return pr;
diff --git a/src/gpu/GrFixedClip.cpp b/src/gpu/GrFixedClip.cpp
index 79e2662..d584ee1 100644
--- a/src/gpu/GrFixedClip.cpp
+++ b/src/gpu/GrFixedClip.cpp
@@ -29,7 +29,7 @@
     }
 }
 
-bool GrFixedClip::isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const {
+bool GrFixedClip::isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const {
     if (fWindowRectsState.enabled()) {
         return false;
     }
@@ -39,7 +39,7 @@
             return false;
         }
         rr->setRect(rect);
-        *aa = false;
+        *aa = GrAA::kNo;
         return true;
     }
     return false;
diff --git a/src/gpu/GrFixedClip.h b/src/gpu/GrFixedClip.h
index 6c350d5..7f18c26 100644
--- a/src/gpu/GrFixedClip.h
+++ b/src/gpu/GrFixedClip.h
@@ -42,7 +42,7 @@
 
     bool quickContains(const SkRect&) const override;
     void getConservativeBounds(int w, int h, SkIRect* devResult, bool* iior) const override;
-    bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const override;
+    bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const override;
     bool apply(GrContext*, GrRenderTargetContext*, bool, bool, GrAppliedClip* out) const override;
 
     static const GrFixedClip& Disabled();
diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp
index d5f8d3d..0954505 100644
--- a/src/gpu/GrPaint.cpp
+++ b/src/gpu/GrPaint.cpp
@@ -13,8 +13,7 @@
 #include "effects/GrSimpleTextureEffect.h"
 
 GrPaint::GrPaint()
-    : fAntiAlias(false)
-    , fDisableOutputConversionToSRGB(false)
+    : fDisableOutputConversionToSRGB(false)
     , fAllowSRGBInputs(false)
     , fUsesDistanceVectorField(false)
     , fColor(GrColor4f::OpaqueWhite()) {}
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
index 2b5ccdc..c002c12 100644
--- a/src/gpu/GrPathRenderer.h
+++ b/src/gpu/GrPathRenderer.h
@@ -78,17 +78,16 @@
      * fPipelineBuilder  The pipelineBuilder
      * fViewMatrix       The viewMatrix
      * fShape            The shape to draw
-     * fAntiAlias        True if anti-aliasing is required.
+     * fAntiAlias        The type of anti aliasing required.
      */
     struct CanDrawPathArgs {
         const GrShaderCaps*         fShaderCaps;
         const SkMatrix*             fViewMatrix;
         const GrShape*              fShape;
-        bool                        fAntiAlias;
+        GrAAType                    fAAType;
 
         // These next two are only used by GrStencilAndCoverPathRenderer
         bool                        fHasUserStencilSettings;
-        bool                        fIsStencilBufferMSAA;
 
 #ifdef SK_DEBUG
         void validate() const {
@@ -121,7 +120,7 @@
      * fColor                 Color to render with
      * fViewMatrix            The viewMatrix
      * fShape                 The shape to draw
-     * fAntiAlias             true if anti-aliasing is required.
+     * fAAtype                true if anti-aliasing is required.
      * fGammaCorrect          true if gamma-correct rendering is to be used.
      */
     struct DrawPathArgs {
@@ -133,7 +132,7 @@
         const GrClip*               fClip;
         const SkMatrix*             fViewMatrix;
         const GrShape*              fShape;
-        bool                        fAntiAlias;
+        GrAAType                    fAAType;
         bool                        fGammaCorrect;
 #ifdef SK_DEBUG
         void validate() const {
@@ -159,10 +158,13 @@
         canArgs.fShaderCaps = args.fResourceProvider->caps()->shaderCaps();
         canArgs.fViewMatrix = args.fViewMatrix;
         canArgs.fShape = args.fShape;
-        canArgs.fAntiAlias = args.fAntiAlias;
+        canArgs.fAAType = args.fAAType;
 
         canArgs.fHasUserStencilSettings = !args.fUserStencilSettings->isUnused();
-        canArgs.fIsStencilBufferMSAA = args.fRenderTargetContext->isStencilBufferMultisampled();
+        SkASSERT(!(canArgs.fAAType == GrAAType::kMSAA &&
+                   !args.fRenderTargetContext->isUnifiedMultisampled()));
+        SkASSERT(!(canArgs.fAAType == GrAAType::kMixedSamples &&
+                   !args.fRenderTargetContext->isStencilBufferMultisampled()));
         SkASSERT(this->canDrawPath(canArgs));
         if (!args.fUserStencilSettings->isUnused()) {
             SkPath path;
@@ -180,14 +182,14 @@
      * fRenderTargetContext   The target of the draws
      * fViewMatrix            Matrix applied to the path.
      * fPath                  The path to draw.
-     * fIsAA                  Is the path to be drawn AA (only set when MSAA is available)
+     * fAAType                The type of AA, cannot be kCoverage.
      */
     struct StencilPathArgs {
         GrResourceProvider*    fResourceProvider;
         GrRenderTargetContext* fRenderTargetContext;
         const GrClip*          fClip;
         const SkMatrix*        fViewMatrix;
-        bool                   fIsAA;
+        GrAAType               fAAType;
         const GrShape*         fShape;
 
 #ifdef SK_DEBUG
@@ -197,6 +199,7 @@
             SkASSERT(fViewMatrix);
             SkASSERT(fShape);
             SkASSERT(fShape->style().isSimpleFill());
+            SkASSERT(GrAAType::kCoverage != fAAType);
             SkPath path;
             fShape->asPath(&path);
             SkASSERT(!path.isInverseFillType());
@@ -283,7 +286,7 @@
         drawArgs.fRenderTargetContext = args.fRenderTargetContext;
         drawArgs.fViewMatrix = args.fViewMatrix;
         drawArgs.fShape = args.fShape;
-        drawArgs.fAntiAlias = false;  // In this case the MSAA handles the AA so we want to draw BW
+        drawArgs.fAAType = args.fAAType;
         drawArgs.fGammaCorrect = false;
         this->drawPath(drawArgs);
     }
diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp
index fac5752..f2dd1ac 100644
--- a/src/gpu/GrPipelineBuilder.cpp
+++ b/src/gpu/GrPipelineBuilder.cpp
@@ -15,15 +15,10 @@
 #include "batches/GrOp.h"
 #include "effects/GrPorterDuffXferProcessor.h"
 
-GrPipelineBuilder::GrPipelineBuilder()
-    : fFlags(0x0)
-    , fUserStencilSettings(&GrUserStencilSettings::kUnused)
-    , fDrawFace(GrDrawFace::kBoth) {
-    SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
-}
-
-GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, bool useHWAA)
-    : GrPipelineBuilder() {
+GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, GrAAType aaType)
+        : fFlags(0x0)
+        , fUserStencilSettings(&GrUserStencilSettings::kUnused)
+        , fDrawFace(GrDrawFace::kBoth) {
     SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
 
     for (int i = 0; i < paint.numColorFragmentProcessors(); ++i) {
@@ -36,7 +31,8 @@
 
     fXPFactory.reset(SkSafeRef(paint.getXPFactory()));
 
-    this->setState(GrPipelineBuilder::kHWAntialias_Flag, useHWAA);
+    this->setState(GrPipelineBuilder::kHWAntialias_Flag, GrAAType::kMSAA == aaType ||
+                                                         GrAAType::kMixedSamples == aaType);
     this->setState(GrPipelineBuilder::kDisableOutputConversionToSRGB_Flag,
                    paint.getDisableOutputConversionToSRGB());
     this->setState(GrPipelineBuilder::kAllowSRGBInputs_Flag,
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index fcff2ad..69aa454 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -29,15 +29,14 @@
 
 class GrPipelineBuilder : public SkNoncopyable {
 public:
-    GrPipelineBuilder();
-
+//    GrPipelineBuilder();
     /**
      * Initializes the GrPipelineBuilder based on a GrPaint and MSAA availability. Note
      * that GrPipelineBuilder encompasses more than GrPaint. Aspects of GrPipelineBuilder that have
      * no GrPaint equivalents are set to default values with the exception of vertex attribute state
      * which is unmodified by this function and clipping which will be enabled.
      */
-    GrPipelineBuilder(const GrPaint&, bool useHWAA = false);
+    GrPipelineBuilder(const GrPaint& paint, GrAAType aaType);
 
     virtual ~GrPipelineBuilder();
 
diff --git a/src/gpu/GrReducedClip.cpp b/src/gpu/GrReducedClip.cpp
index c5d764d..8b9090f 100644
--- a/src/gpu/GrReducedClip.cpp
+++ b/src/gpu/GrReducedClip.cpp
@@ -529,8 +529,7 @@
                             const GrUserStencilSettings* ss,
                             const SkMatrix& viewMatrix,
                             const SkClipStack::Element* element) {
-
-    // TODO: Draw rrects directly here.
+    GrAA aa = GrBoolToAA(element->isAA());
     switch (element->getType()) {
         case Element::kEmpty_Type:
             SkDEBUGFAIL("Should never get here with an empty element.");
@@ -538,9 +537,7 @@
         case Element::kRect_Type:
             return rtc->priv().drawAndStencilRect(clip, ss,
                                                   (SkRegion::Op)element->getOp(),
-                                                  element->isInverseFilled(),
-                                                  element->isAA(),
-                                                  viewMatrix,
+                                                  element->isInverseFilled(), aa, viewMatrix,
                                                   element->getRect());
             break;
         default: {
@@ -550,11 +547,8 @@
                 path.toggleInverseFillType();
             }
 
-            return rtc->priv().drawAndStencilPath(clip, ss,
-                                                  (SkRegion::Op)element->getOp(),
-                                                  element->isInverseFilled(),
-                                                  element->isAA(), viewMatrix,
-                                                  path);
+            return rtc->priv().drawAndStencilPath(clip, ss, (SkRegion::Op)element->getOp(),
+                                                  element->isInverseFilled(), aa, viewMatrix, path);
             break;
         }
     }
@@ -565,6 +559,7 @@
 static void draw_element(GrRenderTargetContext* rtc,
                          const GrClip& clip, // TODO: can this just always be WideOpen?
                          const GrPaint &paint,
+                         GrAA aa,
                          const SkMatrix& viewMatrix,
                          const SkClipStack::Element* element) {
 
@@ -574,7 +569,7 @@
             SkDEBUGFAIL("Should never get here with an empty element.");
             break;
         case Element::kRect_Type:
-            rtc->drawRect(clip, paint, viewMatrix, element->getRect());
+            rtc->drawRect(clip, paint, aa, viewMatrix, element->getRect());
             break;
         default: {
             SkPath path;
@@ -583,7 +578,7 @@
                 path.toggleInverseFillType();
             }
 
-            rtc->drawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill());
+            rtc->drawPath(clip, paint, aa, viewMatrix, path, GrStyle::SimpleFill());
             break;
         }
     }
@@ -612,6 +607,7 @@
     for (ElementList::Iter iter(fElements); iter.get(); iter.next()) {
         const Element* element = iter.get();
         SkRegion::Op op = (SkRegion::Op)element->getOp();
+        GrAA aa = GrBoolToAA(element->isAA());
         bool invert = element->isInverseFilled();
         if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
             // draw directly into the result with the stencil set to make the pixels affected
@@ -639,17 +635,16 @@
                      GrUserStencilOp::kZero,
                      0xffff>()
             );
-            if (!rtc->priv().drawAndStencilRect(clip, &kDrawOutsideElement, op, !invert, false,
+            if (!rtc->priv().drawAndStencilRect(clip, &kDrawOutsideElement, op, !invert, GrAA::kNo,
                                                 translate, SkRect::Make(fIBounds))) {
                 return false;
             }
         } else {
             // all the remaining ops can just be directly draw into the accumulation buffer
             GrPaint paint;
-            paint.setAntiAlias(element->isAA());
             paint.setCoverageSetOpXPFactory(op, false);
 
-            draw_element(rtc, clip, paint, translate, element);
+            draw_element(rtc, clip, paint, aa, translate, element);
         }
     }
 
@@ -676,7 +671,7 @@
     void getConservativeBounds(int width, int height, SkIRect* bounds, bool* iior) const override {
         fFixedClip.getConservativeBounds(width, height, bounds, iior);
     }
-    bool isRRect(const SkRect& rtBounds, SkRRect* rr, bool* aa) const override {
+    bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const override {
         return false;
     }
     bool apply(GrContext* context, GrRenderTargetContext* renderTargetContext, bool useHWAA,
@@ -711,11 +706,13 @@
     SkMatrix viewMatrix;
     viewMatrix.setTranslate(SkIntToScalar(-clipOrigin.x()), SkIntToScalar(-clipOrigin.y()));
 
-    // walk through each clip element and perform its set op
-    // with the existing clip.
+    // walk through each clip element and perform its set op with the existing clip.
     for (ElementList::Iter iter(fElements); iter.get(); iter.next()) {
         const Element* element = iter.get();
-        bool useHWAA = element->isAA() && renderTargetContext->isStencilBufferMultisampled();
+        GrAAType aaType = GrAAType::kNone;
+        if (element->isAA() && renderTargetContext->isStencilBufferMultisampled()) {
+            aaType = GrAAType::kMSAA;
+        }
 
         bool fillInverted = false;
 
@@ -742,9 +739,8 @@
             canDrawArgs.fShaderCaps = context->caps()->shaderCaps();
             canDrawArgs.fViewMatrix = &viewMatrix;
             canDrawArgs.fShape = &shape;
-            canDrawArgs.fAntiAlias = false;
+            canDrawArgs.fAAType = aaType;
             canDrawArgs.fHasUserStencilSettings = false;
-            canDrawArgs.fIsStencilBufferMSAA = renderTargetContext->isStencilBufferMultisampled();
 
             GrDrawingManager* dm = context->contextPriv().drawingManager();
             pr = dm->getPathRenderer(canDrawArgs, false,
@@ -778,14 +774,13 @@
             );
             if (Element::kRect_Type == element->getType()) {
                 renderTargetContext->priv().stencilRect(stencilClip.fixedClip(), &kDrawToStencil,
-                                                        useHWAA, viewMatrix, element->getRect());
+                                                        aaType, viewMatrix, element->getRect());
             } else {
                 if (!clipPath.isEmpty()) {
                     GrShape shape(clipPath, GrStyle::SimpleFill());
                     if (canRenderDirectToStencil) {
                         GrPaint paint;
                         paint.setXPFactory(GrDisableColorXPFactory::Make());
-                        paint.setAntiAlias(element->isAA());
 
                         GrPathRenderer::DrawPathArgs args;
                         args.fResourceProvider = context->resourceProvider();
@@ -795,7 +790,7 @@
                         args.fClip = &stencilClip.fixedClip();
                         args.fViewMatrix = &viewMatrix;
                         args.fShape = &shape;
-                        args.fAntiAlias = false;
+                        args.fAAType = aaType;
                         args.fGammaCorrect = false;
                         pr->drawPath(args);
                     } else {
@@ -804,7 +799,7 @@
                         args.fRenderTargetContext = renderTargetContext;
                         args.fClip = &stencilClip.fixedClip();
                         args.fViewMatrix = &viewMatrix;
-                        args.fIsAA = element->isAA();
+                        args.fAAType = aaType;
                         args.fShape = &shape;
                         pr->stencilPath(args);
                     }
@@ -817,13 +812,12 @@
         for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) {
             if (drawDirectToClip) {
                 if (Element::kRect_Type == element->getType()) {
-                    renderTargetContext->priv().stencilRect(stencilClip, *pass, useHWAA, viewMatrix,
+                    renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType, viewMatrix,
                                                             element->getRect());
                 } else {
                     GrShape shape(clipPath, GrStyle::SimpleFill());
                     GrPaint paint;
                     paint.setXPFactory(GrDisableColorXPFactory::Make());
-                    paint.setAntiAlias(element->isAA());
                     GrPathRenderer::DrawPathArgs args;
                     args.fResourceProvider = context->resourceProvider();
                     args.fPaint = &paint;
@@ -832,14 +826,14 @@
                     args.fClip = &stencilClip;
                     args.fViewMatrix = &viewMatrix;
                     args.fShape = &shape;
-                    args.fAntiAlias = false;
+                    args.fAAType = aaType;
                     args.fGammaCorrect = 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, false, viewMatrix,
+                renderTargetContext->priv().stencilRect(stencilClip, *pass, aaType, viewMatrix,
                                                         SkRect::Make(fIBounds));
             }
         }
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index ebdf810..5eec103 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -266,7 +266,7 @@
         // RenderTargetProxy bounds
         fRenderTargetContext->drawNonAAFilledRect(GrNoClip(), paint, SkMatrix::I(),
                                                   SkRect::Make(rtRect),
-                                                  nullptr,nullptr, nullptr, false);
+                                                  nullptr, nullptr, nullptr, GrAAType::kNone);
 
     } else {
         if (!fRenderTargetContext->accessRenderTarget()) {
@@ -324,7 +324,7 @@
         paint.setColor4f(GrColor4f::FromGrColor(color));
         paint.setXPFactory(GrPorterDuffXPFactory::Make(SkBlendMode::kSrc));
 
-        this->drawRect(clip, paint, SkMatrix::I(), SkRect::Make(clearRect));
+        this->drawRect(clip, paint, GrAA::kNo, SkMatrix::I(), SkRect::Make(clearRect));
     } else if (isFull) {
         if (this->accessRenderTarget()) {
             this->getOpList()->fullClear(this->accessRenderTarget(), color);
@@ -342,7 +342,7 @@
 }
 
 void GrRenderTargetContext::drawPaint(const GrClip& clip,
-                                      const GrPaint& origPaint,
+                                      const GrPaint& paint,
                                       const SkMatrix& viewMatrix) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
@@ -353,26 +353,19 @@
     // don't overflow fixed-point implementations
 
     SkRect r = fRenderTargetProxy->getBoundsRect();
-    SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
 
     SkRRect rrect;
-    bool aaRRect;
+    GrAA aa;
     // Check if we can replace a clipRRect()/drawPaint() with a drawRRect(). We only do the
     // transformation for non-rect rrects. Rects caused a performance regression on an Android
     // test that needs investigation. We also skip cases where there are fragment processors
     // because they may depend on having correct local coords and this path draws in device space
     // without a local matrix.
-    if (!paint->numTotalFragmentProcessors() &&
-        clip.isRRect(r, &rrect, &aaRRect) && !rrect.isRect()) {
-        paint.writable()->setAntiAlias(aaRRect);
-        this->drawRRect(GrNoClip(), *paint, SkMatrix::I(), rrect, GrStyle::SimpleFill());
+    if (!paint.numTotalFragmentProcessors() && clip.isRRect(r, &rrect, &aa) && !rrect.isRect()) {
+        this->drawRRect(GrNoClip(), paint, aa, SkMatrix::I(), rrect, GrStyle::SimpleFill());
         return;
     }
 
-    // by definition this fills the entire clip, no need for AA
-    if (paint->isAntiAlias()) {
-        paint.writable()->setAntiAlias(false);
-    }
 
     bool isPerspective = viewMatrix.hasPerspective();
 
@@ -384,7 +377,7 @@
             SkDebugf("Could not invert matrix\n");
             return;
         }
-        this->drawRect(clip, *paint, viewMatrix, r);
+        this->drawRect(clip, paint, GrAA::kNo, viewMatrix, r);
     } else {
         SkMatrix localMatrix;
         if (!viewMatrix.invert(&localMatrix)) {
@@ -394,8 +387,8 @@
 
         AutoCheckFlush acf(fDrawingManager);
 
-        this->drawNonAAFilledRect(clip, *paint, SkMatrix::I(), r, nullptr, &localMatrix, nullptr,
-                                  false /* useHWAA */);
+        this->drawNonAAFilledRect(clip, paint, SkMatrix::I(), r, nullptr, &localMatrix,
+                                  nullptr, GrAAType::kNone);
     }
 }
 
@@ -408,21 +401,6 @@
     return viewMatrix.preservesRightAngles();
 }
 
-static bool should_apply_coverage_aa(const GrPaint& paint, GrRenderTargetProxy* rtp,
-                                     bool* useHWAA = nullptr) {
-    if (!paint.isAntiAlias()) {
-        if (useHWAA) {
-            *useHWAA = false;
-        }
-        return false;
-    } else {
-        if (useHWAA) {
-            *useHWAA = rtp->isUnifiedMultisampled();
-        }
-        return !rtp->isUnifiedMultisampled();
-    }
-}
-
 // Attempts to crop a rect and optional local rect to the clip boundaries.
 // Returns false if the draw can be skipped entirely.
 static bool crop_filled_rect(int width, int height, const GrClip& clip,
@@ -470,6 +448,7 @@
 
 bool GrRenderTargetContext::drawFilledRect(const GrClip& clip,
                                            const GrPaint& paint,
+                                           GrAA aa,
                                            const SkMatrix& viewMatrix,
                                            const SkRect& rect,
                                            const GrUserStencilSettings* ss) {
@@ -479,14 +458,14 @@
     }
 
     sk_sp<GrDrawOp> op;
-    bool useHWAA;
+    GrAAType aaType;
 
     if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
         InstancedRendering* ir = this->getOpList()->instancedRendering();
-        op.reset(ir->recordRect(croppedRect, viewMatrix, paint.getColor(), paint.isAntiAlias(),
-                                fInstancedPipelineInfo, &useHWAA));
+        op.reset(ir->recordRect(croppedRect, viewMatrix, paint.getColor(), aa,
+                                fInstancedPipelineInfo, &aaType));
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             if (ss) {
                 pipelineBuilder.setUserStencil(ss);
             }
@@ -494,8 +473,8 @@
             return true;
         }
     }
-
-    if (should_apply_coverage_aa(paint, fRenderTargetProxy.get(), &useHWAA)) {
+    aaType = this->decideAAType(aa);
+    if (GrAAType::kCoverage == aaType) {
         // The fill path can handle rotation but not skew.
         if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
             SkRect devBoundRect;
@@ -504,7 +483,7 @@
             op.reset(GrRectBatchFactory::CreateAAFill(paint, viewMatrix, rect, croppedRect,
                                                       devBoundRect));
             if (op) {
-                GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+                GrPipelineBuilder pipelineBuilder(paint, aaType);
                 if (ss) {
                     pipelineBuilder.setUserStencil(ss);
                 }
@@ -514,7 +493,7 @@
         }
     } else {
         this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, nullptr, nullptr, ss,
-                                  useHWAA);
+                                  aaType);
         return true;
     }
 
@@ -523,6 +502,7 @@
 
 void GrRenderTargetContext::drawRect(const GrClip& clip,
                                      const GrPaint& paint,
+                                     GrAA aa,
                                      const SkMatrix& viewMatrix,
                                      const SkRect& rect,
                                      const GrStyle* style) {
@@ -569,7 +549,7 @@
             }
         }
 
-        if (this->drawFilledRect(clip, paint, viewMatrix, rect, nullptr)) {
+        if (this->drawFilledRect(clip, paint, aa, viewMatrix, rect, nullptr)) {
             return;
         }
     } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
@@ -580,7 +560,7 @@
             // TODO: Move these stroke->fill fallbacks to GrShape?
             switch (stroke.getJoin()) {
                 case SkPaint::kMiter_Join:
-                    this->drawRect(clip, paint, viewMatrix,
+                    this->drawRect(clip, paint, aa, viewMatrix,
                                    {rect.fLeft - r, rect.fTop - r,
                                     rect.fRight + r, rect.fBottom + r},
                                    &GrStyle::SimpleFill());
@@ -589,16 +569,16 @@
                     // Raster draws nothing when both dimensions are empty.
                     if (rect.width() || rect.height()){
                         SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
-                        this->drawRRect(clip, paint, viewMatrix, rrect, GrStyle::SimpleFill());
+                        this->drawRRect(clip, paint, aa, viewMatrix, rrect, GrStyle::SimpleFill());
                         return;
                     }
                 case SkPaint::kBevel_Join:
                     if (!rect.width()) {
-                        this->drawRect(clip, paint, viewMatrix,
+                        this->drawRect(clip, paint, aa, viewMatrix,
                                        {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
                                        &GrStyle::SimpleFill());
                     } else {
-                        this->drawRect(clip, paint, viewMatrix,
+                        this->drawRect(clip, paint, aa, viewMatrix,
                                        {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
                                        &GrStyle::SimpleFill());
                     }
@@ -606,12 +586,12 @@
                 }
         }
 
-        bool useHWAA;
         bool snapToPixelCenters = false;
         sk_sp<GrDrawOp> op;
 
         GrColor color = paint.getColor();
-        if (should_apply_coverage_aa(paint, fRenderTargetProxy.get(), &useHWAA)) {
+        GrAAType aaType = this->decideAAType(aa);
+        if (GrAAType::kCoverage == aaType) {
             // The stroke path needs the rect to remain axis aligned (no rotation or skew).
             if (viewMatrix.rectStaysRect()) {
                 op.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, stroke));
@@ -627,7 +607,7 @@
         }
 
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
 
             if (snapToPixelCenters) {
                 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
@@ -642,7 +622,7 @@
     SkPath path;
     path.setIsVolatile(true);
     path.addRect(rect);
-    this->internalDrawPath(clip, paint, viewMatrix, path, *style);
+    this->internalDrawPath(clip, paint, aa, viewMatrix, path, *style);
 }
 
 int GrRenderTargetContextPriv::maxWindowRectangles() const {
@@ -666,16 +646,17 @@
 }
 
 void GrRenderTargetContextPriv::stencilPath(const GrClip& clip,
-                                            bool useHWAA,
+                                            GrAAType aaType,
                                             const SkMatrix& viewMatrix,
                                             const GrPath* path) {
-    fRenderTargetContext->getOpList()->stencilPath(fRenderTargetContext, clip, useHWAA, viewMatrix,
+    SkASSERT(aaType != GrAAType::kCoverage);
+    fRenderTargetContext->getOpList()->stencilPath(fRenderTargetContext, clip, aaType, viewMatrix,
                                                    path);
 }
 
 void GrRenderTargetContextPriv::stencilRect(const GrClip& clip,
                                             const GrUserStencilSettings* ss,
-                                            bool useHWAA,
+                                            GrAAType aaType,
                                             const SkMatrix& viewMatrix,
                                             const SkRect& rect) {
     ASSERT_SINGLE_OWNER_PRIV
@@ -683,22 +664,21 @@
     SkDEBUGCODE(fRenderTargetContext->validate();)
     GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
                               "GrRenderTargetContext::stencilRect");
-
+    SkASSERT(GrAAType::kCoverage != aaType);
     AutoCheckFlush acf(fRenderTargetContext->fDrawingManager);
 
     GrPaint paint;
-    paint.setAntiAlias(useHWAA);
     paint.setXPFactory(GrDisableColorXPFactory::Make());
 
     fRenderTargetContext->drawNonAAFilledRect(clip, paint, viewMatrix, rect, nullptr, nullptr, ss,
-                                              useHWAA);
+                                              aaType);
 }
 
 bool GrRenderTargetContextPriv::drawAndStencilRect(const GrClip& clip,
                                                    const GrUserStencilSettings* ss,
                                                    SkRegion::Op op,
                                                    bool invert,
-                                                   bool doAA,
+                                                   GrAA aa,
                                                    const SkMatrix& viewMatrix,
                                                    const SkRect& rect) {
     ASSERT_SINGLE_OWNER_PRIV
@@ -710,21 +690,20 @@
     AutoCheckFlush acf(fRenderTargetContext->fDrawingManager);
 
     GrPaint paint;
-    paint.setAntiAlias(doAA);
     paint.setCoverageSetOpXPFactory(op, invert);
 
-    if (fRenderTargetContext->drawFilledRect(clip, paint, viewMatrix, rect, ss)) {
+    if (fRenderTargetContext->drawFilledRect(clip, paint, aa, viewMatrix, rect, ss)) {
         return true;
     }
-
     SkPath path;
     path.setIsVolatile(true);
     path.addRect(rect);
-    return this->drawAndStencilPath(clip, ss, op, invert, doAA, viewMatrix, path);
+    return this->drawAndStencilPath(clip, ss, op, invert, aa, viewMatrix, path);
 }
 
 void GrRenderTargetContext::fillRectToRect(const GrClip& clip,
                                            const GrPaint& paint,
+                                           GrAA aa,
                                            const SkMatrix& viewMatrix,
                                            const SkRect& rectToDraw,
                                            const SkRect& localRect) {
@@ -741,30 +720,30 @@
     }
 
     AutoCheckFlush acf(fDrawingManager);
-    bool useHWAA;
+    GrAAType aaType;
 
     if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
         InstancedRendering* ir = this->getOpList()->instancedRendering();
         sk_sp<GrDrawOp> op(ir->recordRect(croppedRect, viewMatrix, paint.getColor(),
-                                          croppedLocalRect, paint.isAntiAlias(),
-                                          fInstancedPipelineInfo, &useHWAA));
+                                          croppedLocalRect, aa, fInstancedPipelineInfo, &aaType));
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
             return;
         }
     }
 
-    if (!should_apply_coverage_aa(paint, fRenderTargetProxy.get(), &useHWAA)) {
-        this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, &croppedLocalRect,
-                                  nullptr, nullptr, useHWAA);
+    aaType = this->decideAAType(aa);
+    if (GrAAType::kCoverage != aaType) {
+        this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, &croppedLocalRect, nullptr,
+                                  nullptr, aaType);
         return;
     }
 
     if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
         sk_sp<GrDrawOp> op(GrAAFillRectBatch::CreateWithLocalRect(paint.getColor(), viewMatrix,
                                                                   croppedRect, croppedLocalRect));
-        GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+        GrPipelineBuilder pipelineBuilder(paint, aaType);
         this->addDrawOp(pipelineBuilder, clip, op.get());
         return;
     }
@@ -779,11 +758,12 @@
     SkPath path;
     path.setIsVolatile(true);
     path.addRect(localRect);
-    this->internalDrawPath(clip, paint, viewAndUnLocalMatrix, path, GrStyle());
+    this->internalDrawPath(clip, paint, aa, viewAndUnLocalMatrix, path, GrStyle());
 }
 
 void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
                                                     const GrPaint& paint,
+                                                    GrAA aa,
                                                     const SkMatrix& viewMatrix,
                                                     const SkRect& rectToDraw,
                                                     const SkMatrix& localMatrix) {
@@ -798,29 +778,30 @@
     }
 
     AutoCheckFlush acf(fDrawingManager);
-    bool useHWAA;
+    GrAAType aaType;
 
     if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
         InstancedRendering* ir = this->getOpList()->instancedRendering();
         sk_sp<GrDrawOp> op(ir->recordRect(croppedRect, viewMatrix, paint.getColor(), localMatrix,
-                                          paint.isAntiAlias(), fInstancedPipelineInfo, &useHWAA));
+                                          aa, fInstancedPipelineInfo, &aaType));
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
             return;
         }
     }
 
-    if (!should_apply_coverage_aa(paint, fRenderTargetProxy.get(), &useHWAA)) {
-        this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, nullptr,
-                                  &localMatrix, nullptr, useHWAA);
+    aaType = this->decideAAType(aa);
+    if (GrAAType::kCoverage != aaType) {
+        this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, nullptr, &localMatrix,
+                                  nullptr, aaType);
         return;
     }
 
     if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
         sk_sp<GrDrawOp> op(GrAAFillRectBatch::Create(paint.getColor(), viewMatrix, localMatrix,
                                                      croppedRect));
-        GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+        GrPipelineBuilder pipelineBuilder(paint, aaType);
         this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
         return;
     }
@@ -836,7 +817,7 @@
     path.setIsVolatile(true);
     path.addRect(rectToDraw);
     path.transform(localMatrix);
-    this->internalDrawPath(clip, paint, viewAndUnLocalMatrix, path, GrStyle());
+    this->internalDrawPath(clip, paint, aa, viewAndUnLocalMatrix, path, GrStyle());
 }
 
 void GrRenderTargetContext::drawVertices(const GrClip& clip,
@@ -869,7 +850,7 @@
                                                positions, vertexCount, indices, indexCount, colors,
                                                texCoords, bounds));
 
-    GrPipelineBuilder pipelineBuilder(paint, this->mustUseHWAA(paint));
+    GrPipelineBuilder pipelineBuilder(paint, GrAAType::kNone);
     this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
 }
 
@@ -892,7 +873,7 @@
     sk_sp<GrDrawOp> op(new GrDrawAtlasBatch(paint.getColor(), viewMatrix, spriteCount, xform,
                                             texRect, colors));
 
-    GrPipelineBuilder pipelineBuilder(paint, this->mustUseHWAA(paint));
+    GrPipelineBuilder pipelineBuilder(paint, GrAAType::kNone);
     this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
 }
 
@@ -900,6 +881,7 @@
 
 void GrRenderTargetContext::drawRRect(const GrClip& origClip,
                                       const GrPaint& paint,
+                                      GrAA aa,
                                       const SkMatrix& viewMatrix,
                                       const SkRRect& rrect,
                                       const GrStyle& style) {
@@ -928,21 +910,22 @@
 
     AutoCheckFlush acf(fDrawingManager);
     const SkStrokeRec stroke = style.strokeRec();
-    bool useHWAA;
+    GrAAType aaType;
 
     if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
         stroke.isFillStyle()) {
         InstancedRendering* ir = this->getOpList()->instancedRendering();
-        sk_sp<GrDrawOp> op(ir->recordRRect(rrect, viewMatrix, paint.getColor(), paint.isAntiAlias(),
-                                           fInstancedPipelineInfo, &useHWAA));
+        sk_sp<GrDrawOp> op(ir->recordRRect(rrect, viewMatrix, paint.getColor(), aa,
+                                           fInstancedPipelineInfo, &aaType));
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             this->getOpList()->addDrawOp(pipelineBuilder, this, *clip, op.get());
             return;
         }
     }
 
-    if (should_apply_coverage_aa(paint, fRenderTargetProxy.get(), &useHWAA)) {
+    aaType = this->decideAAType(aa);
+    if (GrAAType::kCoverage == aaType) {
         const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
         sk_sp<GrDrawOp> op(GrOvalRenderer::CreateRRectBatch(paint.getColor(),
                                                             paint.usesDistanceVectorField(),
@@ -951,7 +934,7 @@
                                                             stroke,
                                                             shaderCaps));
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             this->getOpList()->addDrawOp(pipelineBuilder, this, *clip, op.get());
             return;
         }
@@ -960,7 +943,7 @@
     SkPath path;
     path.setIsVolatile(true);
     path.addRRect(rrect);
-    this->internalDrawPath(*clip, paint, viewMatrix, path, style);
+    this->internalDrawPath(*clip, paint, aa, viewMatrix, path, style);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -983,72 +966,55 @@
 
     AutoCheckFlush acf(fDrawingManager);
     const SkStrokeRec stroke = style.strokeRec();
-    bool useHWAA;
+    // TODO: add instancing support?
 
-    // TODO: add instancing support
-    //if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
-    //    stroke.isFillStyle()) {
-    //    InstancedRendering* ir = this->getOpList()->instancedRendering();
-    //    SkAutoTUnref<GrDrawOp> op(ir->recordRRect(rrect, viewMatrix, paint.getColor(),
-    //                                              paint.isAntiAlias(), fInstancedPipelineInfo,
-    //                                              &useHWAA));
-    //    if (op) {
-    //        GrPipelineBuilder pipelineBuilder(paint, useHWAA);
-    //        this->getOpList()->addDrawOp(pipelineBuilder, this, *clip, op);
-    //        return;
-    //    }
-    //}
-
-    if (should_apply_coverage_aa(paint, fRenderTargetProxy.get(), &useHWAA)) {
-        const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
-        sk_sp<GrDrawOp> op(CreateShadowRRectBatch(paint.getColor(),
-                                                  viewMatrix,
-                                                  rrect,
-                                                  blurRadius,
-                                                  stroke,
-                                                  shaderCaps));
-        if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
-            this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
-            return;
-        }
+    const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
+    sk_sp<GrDrawOp> op(CreateShadowRRectBatch(paint.getColor(),
+                                              viewMatrix,
+                                              rrect,
+                                              blurRadius,
+                                              stroke,
+                                              shaderCaps));
+    if (op) {
+        GrPipelineBuilder pipelineBuilder(paint, GrAAType::kNone);
+        this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
+        return;
     }
-
-    SkPath path;
-    path.setIsVolatile(true);
-    path.addRRect(rrect);
-    this->internalDrawPath(clip, paint, viewMatrix, path, style);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
                                              const GrPaint& paintIn,
+                                             GrAA aa,
                                              const SkMatrix& viewMatrix,
                                              const SkRRect& origOuter,
                                              const SkRRect& origInner) {
     SkASSERT(!origInner.isEmpty());
     SkASSERT(!origOuter.isEmpty());
+    GrAAType aaType;
 
     if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
-        bool useHWAA;
         InstancedRendering* ir = this->getOpList()->instancedRendering();
         sk_sp<GrDrawOp> op(ir->recordDRRect(origOuter, origInner, viewMatrix, paintIn.getColor(),
-                                            paintIn.isAntiAlias(), fInstancedPipelineInfo,
-                                            &useHWAA));
+                                            aa, fInstancedPipelineInfo, &aaType));
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paintIn, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paintIn, aaType);
             this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
             return true;
         }
     }
 
-    bool applyAA = paintIn.isAntiAlias() && !fRenderTargetProxy->isUnifiedMultisampled();
+    aaType = this->decideAAType(aa);
 
-    GrPrimitiveEdgeType innerEdgeType = applyAA ? kInverseFillAA_GrProcessorEdgeType :
-                                                  kInverseFillBW_GrProcessorEdgeType;
-    GrPrimitiveEdgeType outerEdgeType = applyAA ? kFillAA_GrProcessorEdgeType :
-                                                  kFillBW_GrProcessorEdgeType;
+    GrPrimitiveEdgeType innerEdgeType, outerEdgeType;
+    if (GrAAType::kCoverage == aaType) {
+        innerEdgeType = kInverseFillAA_GrProcessorEdgeType;
+        outerEdgeType = kFillAA_GrProcessorEdgeType;
+    } else {
+        innerEdgeType = kInverseFillBW_GrProcessorEdgeType;
+        outerEdgeType = kFillBW_GrProcessorEdgeType;
+    }
 
     SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
     SkMatrix inverseVM;
@@ -1067,7 +1033,6 @@
     }
 
     GrPaint grPaint(paintIn);
-    grPaint.setAntiAlias(false);
 
     // TODO these need to be a geometry processors
     sk_sp<GrFragmentProcessor> innerEffect(GrRRectEffect::Make(innerEdgeType, *inner));
@@ -1084,16 +1049,17 @@
     grPaint.addCoverageFragmentProcessor(std::move(outerEffect));
 
     SkRect bounds = outer->getBounds();
-    if (applyAA) {
+    if (GrAAType::kCoverage == aaType) {
         bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
     }
 
-    this->fillRectWithLocalMatrix(clip, grPaint, SkMatrix::I(), bounds, inverseVM);
+    this->fillRectWithLocalMatrix(clip, grPaint, GrAA::kNo, SkMatrix::I(), bounds, inverseVM);
     return true;
 }
 
 void GrRenderTargetContext::drawDRRect(const GrClip& clip,
                                        const GrPaint& paint,
+                                       GrAA aa,
                                        const SkMatrix& viewMatrix,
                                        const SkRRect& outer,
                                        const SkRRect& inner) {
@@ -1107,7 +1073,7 @@
 
     AutoCheckFlush acf(fDrawingManager);
 
-    if (this->drawFilledDRRect(clip, paint, viewMatrix, outer, inner)) {
+    if (this->drawFilledDRRect(clip, paint, aa, viewMatrix, outer, inner)) {
         return;
     }
 
@@ -1117,7 +1083,7 @@
     path.addRRect(outer);
     path.setFillType(SkPath::kEvenOdd_FillType);
 
-    this->internalDrawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill());
+    this->internalDrawPath(clip, paint, aa, viewMatrix, path, GrStyle::SimpleFill());
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -1128,6 +1094,7 @@
 
 void GrRenderTargetContext::drawRegion(const GrClip& clip,
                                        const GrPaint& paint,
+                                       GrAA aa,
                                        const SkMatrix& viewMatrix,
                                        const SkRegion& region,
                                        const GrStyle& style) {
@@ -1136,28 +1103,30 @@
     SkDEBUGCODE(this->validate();)
     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrRenderTargetContext::drawRegion");
 
-    bool needsAA = false;
-    if (paint.isAntiAlias()) {
+    if (GrAA::kYes == aa) {
         // GrRegionBatch performs no antialiasing but is much faster, so here we check the matrix
         // to see whether aa is really required.
-        needsAA = SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) ||
-                  !is_int(viewMatrix.getTranslateX()) ||
-                  !is_int(viewMatrix.getTranslateY());
+        if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
+            is_int(viewMatrix.getTranslateX()) &&
+            is_int(viewMatrix.getTranslateY())) {
+            aa = GrAA::kNo;
+        }
     }
     bool complexStyle = !style.isSimpleFill();
-    if (complexStyle || needsAA) {
+    if (complexStyle || GrAA::kYes == aa) {
         SkPath path;
         region.getBoundaryPath(&path);
-        return this->drawPath(clip, paint, viewMatrix, path, style);
+        return this->drawPath(clip, paint, aa, viewMatrix, path, style);
     }
 
     sk_sp<GrDrawOp> op(GrRegionBatch::Create(paint.getColor(), viewMatrix, region));
-    GrPipelineBuilder pipelineBuilder(paint, false);
+    GrPipelineBuilder pipelineBuilder(paint, GrAAType::kNone);
     this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
 }
 
 void GrRenderTargetContext::drawOval(const GrClip& clip,
                                      const GrPaint& paint,
+                                     GrAA aa,
                                      const SkMatrix& viewMatrix,
                                      const SkRect& oval,
                                      const GrStyle& style) {
@@ -1174,21 +1143,22 @@
 
     AutoCheckFlush acf(fDrawingManager);
     const SkStrokeRec& stroke = style.strokeRec();
-    bool useHWAA;
+    GrAAType aaType;
 
     if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
         stroke.isFillStyle()) {
         InstancedRendering* ir = this->getOpList()->instancedRendering();
-        sk_sp<GrDrawOp> op(ir->recordOval(oval, viewMatrix, paint.getColor(), paint.isAntiAlias(),
-                                          fInstancedPipelineInfo, &useHWAA));
+        sk_sp<GrDrawOp> op(ir->recordOval(oval, viewMatrix, paint.getColor(), aa,
+                                          fInstancedPipelineInfo, &aaType));
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
             return;
         }
     }
 
-    if (should_apply_coverage_aa(paint, fRenderTargetProxy.get(), &useHWAA)) {
+    aaType = this->decideAAType(aa);
+    if (GrAAType::kCoverage == aaType) {
         const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
         sk_sp<GrDrawOp> op(GrOvalRenderer::CreateOvalBatch(paint.getColor(),
                                                            viewMatrix,
@@ -1196,7 +1166,7 @@
                                                            stroke,
                                                            shaderCaps));
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
             return;
         }
@@ -1205,19 +1175,20 @@
     SkPath path;
     path.setIsVolatile(true);
     path.addOval(oval);
-    this->internalDrawPath(clip, paint, viewMatrix, path, style);
+    this->internalDrawPath(clip, paint, aa, viewMatrix, path, style);
 }
 
 void GrRenderTargetContext::drawArc(const GrClip& clip,
                                     const GrPaint& paint,
+                                    GrAA aa,
                                     const SkMatrix& viewMatrix,
                                     const SkRect& oval,
                                     SkScalar startAngle,
                                     SkScalar sweepAngle,
                                     bool useCenter,
                                     const GrStyle& style) {
-    bool useHWAA;
-    if (should_apply_coverage_aa(paint, fRenderTargetProxy.get(), &useHWAA)) {
+    GrAAType aaType = this->decideAAType(aa);
+    if (GrAAType::kCoverage == aaType) {
         const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
         sk_sp<GrDrawOp> op(GrOvalRenderer::CreateArcBatch(paint.getColor(),
                                                           viewMatrix,
@@ -1228,7 +1199,7 @@
                                                           style,
                                                           shaderCaps));
         if (op) {
-            GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
             return;
         }
@@ -1236,8 +1207,7 @@
     SkPath path;
     SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
                                   style.isSimpleFill());
-    this->internalDrawPath(clip, paint, viewMatrix, path, style);
-    return;
+    this->internalDrawPath(clip, paint, aa, viewMatrix, path, style);
 }
 
 void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
@@ -1257,7 +1227,7 @@
     sk_sp<GrDrawOp> op(GrNinePatch::CreateNonAA(paint.getColor(), viewMatrix, imageWidth,
                                                 imageHeight, std::move(iter), dst));
 
-    GrPipelineBuilder pipelineBuilder(paint, this->mustUseHWAA(paint));
+    GrPipelineBuilder pipelineBuilder(paint, GrAAType::kNone);
     this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
 }
 
@@ -1286,11 +1256,12 @@
                                                 const SkRect* localRect,
                                                 const SkMatrix* localMatrix,
                                                 const GrUserStencilSettings* ss,
-                                                bool useHWAA) {
-    SkASSERT(!useHWAA || this->isStencilBufferMultisampled());
+                                                GrAAType hwOrNoneAAType) {
+    SkASSERT(GrAAType::kCoverage != hwOrNoneAAType);
+    SkASSERT(hwOrNoneAAType == GrAAType::kNone || this->isStencilBufferMultisampled());
     sk_sp<GrDrawOp> op( GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rect,
                                                             localRect, localMatrix));
-    GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+    GrPipelineBuilder pipelineBuilder(paint, hwOrNoneAAType);
     if (ss) {
         pipelineBuilder.setUserStencil(ss);
     }
@@ -1392,6 +1363,7 @@
 
 void GrRenderTargetContext::drawPath(const GrClip& clip,
                                      const GrPaint& paint,
+                                     GrAA aa,
                                      const SkMatrix& viewMatrix,
                                      const SkPath& path,
                                      const GrStyle& style) {
@@ -1409,9 +1381,8 @@
 
     AutoCheckFlush acf(fDrawingManager);
 
-    bool useHWAA;
-    if (should_apply_coverage_aa(paint, fRenderTargetProxy.get(), &useHWAA) &&
-                                                                            !style.pathEffect()) {
+    GrAAType aaType = this->decideAAType(aa);
+    if (GrAAType::kCoverage == aaType && !style.pathEffect()) {
         if (style.isSimpleFill() && !path.isConvex()) {
             // Concave AA paths are expensive - try to avoid them for special cases
             SkRect rects[2];
@@ -1419,8 +1390,8 @@
             if (fills_as_nested_rects(viewMatrix, path, rects)) {
                 sk_sp<GrDrawOp> op(GrRectBatchFactory::CreateAAFillNestedRects(
                     paint.getColor(), viewMatrix, rects));
-                if (op) {
-                    GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+              if (op) {
+                    GrPipelineBuilder pipelineBuilder(paint, aaType);
                     this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
                 }
                 return;
@@ -1437,7 +1408,7 @@
                                                                style.strokeRec(),
                                                                shaderCaps));
             if (op) {
-                GrPipelineBuilder pipelineBuilder(paint, useHWAA);
+                GrPipelineBuilder pipelineBuilder(paint, aaType);
                 this->getOpList()->addDrawOp(pipelineBuilder, this, clip, op.get());
                 return;
             }
@@ -1449,23 +1420,24 @@
     // cache. This presents a potential hazard for buffered drawing. However,
     // the writePixels that uploads to the scratch will perform a flush so we're
     // OK.
-    this->internalDrawPath(clip, paint, viewMatrix, path, style);
+    this->internalDrawPath(clip, paint, aa, viewMatrix, path, style);
 }
 
 bool GrRenderTargetContextPriv::drawAndStencilPath(const GrClip& clip,
                                                    const GrUserStencilSettings* ss,
                                                    SkRegion::Op op,
                                                    bool invert,
-                                                   bool doAA,
+                                                   GrAA aa,
                                                    const SkMatrix& viewMatrix,
                                                    const SkPath& path) {
     ASSERT_SINGLE_OWNER_PRIV
     RETURN_FALSE_IF_ABANDONED_PRIV
     SkDEBUGCODE(fRenderTargetContext->validate();)
-    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail, "GrRenderTargetContext::drawPath");
+    GR_AUDIT_TRAIL_AUTO_FRAME(fRenderTargetContext->fAuditTrail,
+                              "GrRenderTargetContextPriv::drawAndStencilPath");
 
     if (path.isEmpty() && path.isInverseFillType()) {
-        this->drawAndStencilRect(clip, ss, op, invert, false, SkMatrix::I(),
+        this->drawAndStencilRect(clip, ss, op, invert, GrAA::kNo, SkMatrix::I(),
                                  SkRect::MakeIWH(fRenderTargetContext->width(),
                                                  fRenderTargetContext->height()));
         return true;
@@ -1477,13 +1449,12 @@
     // 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.
-    bool useCoverageAA = doAA && !fRenderTargetContext->isUnifiedMultisampled();
+    GrAAType aaType = fRenderTargetContext->decideAAType(aa);
     bool hasUserStencilSettings = !ss->isUnused();
-    bool isStencilBufferMSAA = fRenderTargetContext->isStencilBufferMultisampled();
 
-    const GrPathRendererChain::DrawType type =
-        useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
-                      : GrPathRendererChain::kColor_DrawType;
+    const GrPathRendererChain::DrawType type = (GrAAType::kCoverage == aaType)
+                                               ? GrPathRendererChain::kColorAntiAlias_DrawType
+                                               : GrPathRendererChain::kColor_DrawType;
 
     GrShape shape(path, GrStyle::SimpleFill());
     GrPathRenderer::CanDrawPathArgs canDrawArgs;
@@ -1491,9 +1462,8 @@
         fRenderTargetContext->fDrawingManager->getContext()->caps()->shaderCaps();
     canDrawArgs.fViewMatrix = &viewMatrix;
     canDrawArgs.fShape = &shape;
-    canDrawArgs.fAntiAlias = useCoverageAA;
+    canDrawArgs.fAAType = aaType;
     canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
-    canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
 
     // Don't allow the SW renderer
     GrPathRenderer* pr = fRenderTargetContext->fDrawingManager->getPathRenderer(canDrawArgs, false,
@@ -1514,7 +1484,7 @@
     args.fClip = &clip;
     args.fViewMatrix = &viewMatrix;
     args.fShape = &shape;
-    args.fAntiAlias = useCoverageAA;
+    args.fAAType = aaType;
     args.fGammaCorrect = fRenderTargetContext->isGammaCorrect();
     pr->drawPath(args);
     return true;
@@ -1534,55 +1504,71 @@
 
 void GrRenderTargetContext::internalDrawPath(const GrClip& clip,
                                              const GrPaint& paint,
+                                             GrAA aa,
                                              const SkMatrix& viewMatrix,
                                              const SkPath& path,
                                              const GrStyle& style) {
     ASSERT_SINGLE_OWNER
     RETURN_IF_ABANDONED
     SkASSERT(!path.isEmpty());
+    GrShape shape;
 
-    bool useCoverageAA = should_apply_coverage_aa(paint, fRenderTargetProxy.get());
-    constexpr bool kHasUserStencilSettings = false;
-    bool isStencilBufferMSAA = this->isStencilBufferMultisampled();
-
-    const GrPathRendererChain::DrawType type =
-        useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
-                      : GrPathRendererChain::kColor_DrawType;
-
-    GrShape shape(path, style);
-    if (shape.isEmpty()) {
-        return;
+    GrAAType aaType = this->decideAAType(aa, /*allowMixedSamples*/ true);
+    if (style.isSimpleHairline() && aaType == GrAAType::kMixedSamples) {
+        // NVPR cannot handle hairlines, so this will 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.
+        aaType = GrAAType::kCoverage;
     }
     GrPathRenderer::CanDrawPathArgs canDrawArgs;
     canDrawArgs.fShaderCaps = fDrawingManager->getContext()->caps()->shaderCaps();
     canDrawArgs.fViewMatrix = &viewMatrix;
     canDrawArgs.fShape = &shape;
-    canDrawArgs.fAntiAlias = useCoverageAA;
-    canDrawArgs.fHasUserStencilSettings = kHasUserStencilSettings;
-    canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
+    canDrawArgs.fHasUserStencilSettings = false;
 
-    // Try a 1st time without applying any of the style to the geometry (and barring sw)
-    GrPathRenderer* pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
-    SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
+    GrPathRenderer* pr;
+    do {
+        const GrPathRendererChain::DrawType type = GrAAType::kCoverage == aaType
+                ? GrPathRendererChain::kColorAntiAlias_DrawType
+                : GrPathRendererChain::kColor_DrawType;
 
-    if (!pr && shape.style().pathEffect()) {
-        // It didn't work above, so try again with the path effect applied.
-        shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
+        shape = GrShape(path, style);
         if (shape.isEmpty()) {
             return;
         }
+
+        canDrawArgs.fAAType = aaType;
+
+        // Try a 1st time without applying any of the style to the geometry (and barring sw)
         pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
-    }
-    if (!pr) {
-        if (shape.style().applies()) {
-            shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
+        SkScalar styleScale =  GrStyle::MatrixToScaleFactor(viewMatrix);
+
+        if (!pr && shape.style().pathEffect()) {
+            // It didn't work above, so try again with the path effect applied.
+            shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
             if (shape.isEmpty()) {
                 return;
             }
+            pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
         }
-        // This time, allow SW renderer
-        pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type);
-    }
+        if (!pr) {
+            if (shape.style().applies()) {
+                shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
+                if (shape.isEmpty()) {
+                    return;
+                }
+            }
+            // This time, allow SW renderer
+            pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type);
+        }
+        if (!pr && (aaType == GrAAType::kMixedSamples || aaType == GrAAType::kMSAA)) {
+            // There are exceptional cases where we may wind up falling back to coverage based AA
+            // when the target is MSAA (e.g. through disabling path renderers via GrContextOptions).
+            aaType = GrAAType::kCoverage;
+        } else {
+            break;
+        }
+    } while(true);
 
     if (!pr) {
 #ifdef SK_DEBUG
@@ -1598,8 +1584,8 @@
     args.fRenderTargetContext = this;
     args.fClip = &clip;
     args.fViewMatrix = &viewMatrix;
-    args.fShape = canDrawArgs.fShape;
-    args.fAntiAlias = useCoverageAA;
+    args.fShape = &shape;
+    args.fAAType = aaType;
     args.fGammaCorrect = this->isGammaCorrect();
     pr->drawPath(args);
 }
diff --git a/src/gpu/GrRenderTargetContextPriv.h b/src/gpu/GrRenderTargetContextPriv.h
index b2e647d..d53bd56 100644
--- a/src/gpu/GrRenderTargetContextPriv.h
+++ b/src/gpu/GrRenderTargetContextPriv.h
@@ -66,28 +66,33 @@
 
     void stencilRect(const GrClip& clip,
                      const GrUserStencilSettings* ss,
-                     bool useHWAA,
+                     GrAAType,
                      const SkMatrix& viewMatrix,
                      const SkRect& rect);
 
-    void stencilPath(const GrClip&,
-                     bool useHWAA,
-                     const SkMatrix& viewMatrix,
-                     const GrPath*);
+    void stencilPath(const GrClip&, GrAAType, const SkMatrix& viewMatrix, const GrPath*);
 
+    /**
+     * Draws a rect, either AA or not, and touches the stencil buffer with the user stencil settings
+     * for each color sample written.
+     */
     bool drawAndStencilRect(const GrClip&,
                             const GrUserStencilSettings*,
                             SkRegion::Op op,
                             bool invert,
-                            bool doAA,
+                            GrAA,
                             const SkMatrix& viewMatrix,
                             const SkRect&);
 
+    /**
+     * Draws a path, either AA or not, and touches the stencil buffer with the user stencil settings
+     * for each color sample written.
+     */
     bool drawAndStencilPath(const GrClip&,
                             const GrUserStencilSettings*,
                             SkRegion::Op op,
                             bool invert,
-                            bool doAA,
+                            GrAA,
                             const SkMatrix& viewMatrix,
                             const SkPath&);
 
@@ -104,6 +109,7 @@
     }
 
     void testingOnly_drawBatch(const GrPaint&,
+                               GrAAType,
                                GrDrawOp* batch,
                                const GrUserStencilSettings* = nullptr,
                                bool snapToCenters = false);
diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp
index 41c0d4f..80b0a83 100644
--- a/src/gpu/GrRenderTargetOpList.cpp
+++ b/src/gpu/GrRenderTargetOpList.cpp
@@ -351,9 +351,10 @@
 
 void GrRenderTargetOpList::stencilPath(GrRenderTargetContext* renderTargetContext,
                                        const GrClip& clip,
-                                       bool useHWAA,
+                                       GrAAType aaType,
                                        const SkMatrix& viewMatrix,
                                        const GrPath* path) {
+    bool useHWAA = (aaType == GrAAType::kMSAA || aaType == GrAAType::kMixedSamples);
     // TODO: extract portions of checkDraw that are relevant to path stenciling.
     SkASSERT(path);
     SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
diff --git a/src/gpu/GrRenderTargetOpList.h b/src/gpu/GrRenderTargetOpList.h
index d7f8ba1..7ee4470 100644
--- a/src/gpu/GrRenderTargetOpList.h
+++ b/src/gpu/GrRenderTargetOpList.h
@@ -95,7 +95,7 @@
      */
     void stencilPath(GrRenderTargetContext*,
                      const GrClip&,
-                     bool useHWAA,
+                     GrAAType aa,
                      const SkMatrix& viewMatrix,
                      const GrPath*);
 
diff --git a/src/gpu/GrSWMaskHelper.cpp b/src/gpu/GrSWMaskHelper.cpp
index ec76c48..7351ecd 100644
--- a/src/gpu/GrSWMaskHelper.cpp
+++ b/src/gpu/GrSWMaskHelper.cpp
@@ -38,12 +38,11 @@
 /**
  * Draw a single rect element of the clip stack into the accumulation bitmap
  */
-void GrSWMaskHelper::drawRect(const SkRect& rect, SkRegion::Op op,
-                              bool antiAlias, uint8_t alpha) {
+void GrSWMaskHelper::drawRect(const SkRect& rect, SkRegion::Op op, GrAA aa, uint8_t alpha) {
     SkPaint paint;
 
     paint.setBlendMode(op_to_mode(op));
-    paint.setAntiAlias(antiAlias);
+    paint.setAntiAlias(GrAA::kYes == aa);
     paint.setColor(SkColorSetARGB(alpha, alpha, alpha, alpha));
 
     fDraw.drawRect(rect, paint);
@@ -52,12 +51,11 @@
 /**
  * Draw a single path element of the clip stack into the accumulation bitmap
  */
-void GrSWMaskHelper::drawShape(const GrShape& shape, SkRegion::Op op, bool antiAlias,
-                               uint8_t alpha) {
+void GrSWMaskHelper::drawShape(const GrShape& shape, SkRegion::Op op, GrAA aa, uint8_t alpha) {
     SkPaint paint;
     paint.setPathEffect(sk_ref_sp(shape.style().pathEffect()));
     shape.style().strokeRec().applyToPaint(&paint);
-    paint.setAntiAlias(antiAlias);
+    paint.setAntiAlias(GrAA::kYes == aa);
 
     SkPath path;
     shape.asPath(&path);
@@ -141,7 +139,7 @@
 GrTexture* GrSWMaskHelper::DrawShapeMaskToTexture(GrTextureProvider* texProvider,
                                                   const GrShape& shape,
                                                   const SkIRect& resultBounds,
-                                                  bool antiAlias,
+                                                  GrAA aa,
                                                   TextureType textureType,
                                                   const SkMatrix* matrix) {
     GrSWMaskHelper helper(texProvider);
@@ -150,7 +148,7 @@
         return nullptr;
     }
 
-    helper.drawShape(shape, SkRegion::kReplace_Op, antiAlias, 0xFF);
+    helper.drawShape(shape, SkRegion::kReplace_Op, aa, 0xFF);
 
     GrTexture* texture(helper.createTexture(textureType));
     if (!texture) {
@@ -185,7 +183,7 @@
     maskMatrix.preTranslate(SkIntToScalar(-textureOriginInDeviceSpace.fX),
                             SkIntToScalar(-textureOriginInDeviceSpace.fY));
     maskMatrix.preConcat(viewMatrix);
-    GrPipelineBuilder pipelineBuilder(paint, renderTargetContext->mustUseHWAA(paint));
+    GrPipelineBuilder pipelineBuilder(paint, GrAAType::kNone);
     pipelineBuilder.setUserStencil(&userStencilSettings);
 
     pipelineBuilder.addCoverageFragmentProcessor(
diff --git a/src/gpu/GrSWMaskHelper.h b/src/gpu/GrSWMaskHelper.h
index 1846733..0669db9 100644
--- a/src/gpu/GrSWMaskHelper.h
+++ b/src/gpu/GrSWMaskHelper.h
@@ -9,6 +9,7 @@
 #define GrSWMaskHelper_DEFINED
 
 #include "GrColor.h"
+#include "GrRenderTargetContext.h"
 #include "GrTextureProvider.h"
 #include "SkAutoPixmapStorage.h"
 #include "SkBitmap.h"
@@ -51,10 +52,10 @@
     bool init(const SkIRect& resultBounds, const SkMatrix* matrix);
 
     // Draw a single rect into the accumulation bitmap using the specified op
-    void drawRect(const SkRect& rect, SkRegion::Op op, bool antiAlias, uint8_t alpha);
+    void drawRect(const SkRect& rect, SkRegion::Op op, GrAA, uint8_t alpha);
 
     // Draw a single path into the accumuation bitmap using the specified op
-    void drawShape(const GrShape&, SkRegion::Op op, bool antiAlias, uint8_t alpha);
+    void drawShape(const GrShape&, SkRegion::Op op, GrAA, uint8_t alpha);
 
     // Move the mask generation results from the internal bitmap to the gpu.
     void toTexture(GrTexture* texture);
@@ -67,7 +68,6 @@
         fPixels.erase(SkColorSetARGB(alpha, 0xFF, 0xFF, 0xFF));
     }
 
-
     enum class TextureType {
         kExactFit,
         kApproximateFit
@@ -78,7 +78,7 @@
     static GrTexture* DrawShapeMaskToTexture(GrTextureProvider*,
                                              const GrShape&,
                                              const SkIRect& resultBounds,
-                                             bool antiAlias,
+                                             GrAA,
                                              TextureType,
                                              const SkMatrix* matrix);
 
diff --git a/src/gpu/GrSoftwarePathRenderer.cpp b/src/gpu/GrSoftwarePathRenderer.cpp
index 8b941eb..73080a6 100644
--- a/src/gpu/GrSoftwarePathRenderer.cpp
+++ b/src/gpu/GrSoftwarePathRenderer.cpp
@@ -18,7 +18,8 @@
 bool GrSoftwarePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
     // 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.
-    return !args.fShape->style().applies() && SkToBool(fTexProvider);
+    return !args.fShape->style().applies() && SkToBool(fTexProvider) &&
+           (args.fAAType == GrAAType::kCoverage || args.fAAType == GrAAType::kNone);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -71,9 +72,8 @@
                                                               viewMatrix, rect,
                                                               nullptr, &localMatrix));
 
-    GrPipelineBuilder pipelineBuilder(paint, renderTargetContext->mustUseHWAA(paint));
+    GrPipelineBuilder pipelineBuilder(paint, GrAAType::kNone);
     pipelineBuilder.setUserStencil(&userStencilSettings);
-
     renderTargetContext->addDrawOp(pipelineBuilder, clip, batch.get());
 }
 
@@ -135,7 +135,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() && args.fAntiAlias;
+                    args.fShape->hasUnstyledKey() && GrAAType::kCoverage == args.fAAType;
 
     if (!get_shape_and_clip_bounds(args.fRenderTargetContext->width(),
                                    args.fRenderTargetContext->height(),
@@ -193,6 +193,8 @@
         builder[3] = SkFloat2Bits(ky);
         builder[4] = fracX | (fracY >> 8);
         args.fShape->writeUnstyledKey(&builder[5]);
+        // FIXME: Doesn't the key need to consider whether we're using AA or not? In practice that
+        // should always be true, though.
     }
 
     sk_sp<GrTexture> texture;
@@ -200,25 +202,24 @@
         texture.reset(args.fResourceProvider->findAndRefTextureByUniqueKey(maskKey));
     }
     if (!texture) {
-         GrSWMaskHelper::TextureType type = useCache ? GrSWMaskHelper::TextureType::kExactFit
-                                                     : GrSWMaskHelper::TextureType::kApproximateFit;
-         texture.reset(GrSWMaskHelper::DrawShapeMaskToTexture(fTexProvider, *args.fShape,
-                                                              *boundsForMask, args.fAntiAlias,
-                                                              type, args.fViewMatrix));
-         if (!texture) {
-             return false;
-         }
-         if (useCache) {
-             texture->resourcePriv().setUniqueKey(maskKey);
-         }
+        GrSWMaskHelper::TextureType type = useCache ? GrSWMaskHelper::TextureType::kExactFit
+                                                    : GrSWMaskHelper::TextureType::kApproximateFit;
+        GrAA aa = GrAAType::kCoverage == args.fAAType ? GrAA::kYes : GrAA::kNo;
+        texture.reset(GrSWMaskHelper::DrawShapeMaskToTexture(fTexProvider, *args.fShape,
+                                                             *boundsForMask, aa,
+                                                             type, args.fViewMatrix));
+        if (!texture) {
+            return false;
+        }
+        if (useCache) {
+            texture->resourcePriv().setUniqueKey(maskKey);
+        }
     }
-
     GrSWMaskHelper::DrawToTargetWithShapeMask(texture.get(), args.fRenderTargetContext,
                                               *args.fPaint, *args.fUserStencilSettings,
                                               *args.fClip, *args.fViewMatrix,
                                               SkIPoint {boundsForMask->fLeft, boundsForMask->fTop},
                                               *boundsForMask);
-
     if (inverseFilled) {
         DrawAroundInvPath(args.fRenderTargetContext, *args.fPaint, *args.fUserStencilSettings,
                           *args.fClip,
diff --git a/src/gpu/GrTextureProducer.cpp b/src/gpu/GrTextureProducer.cpp
index 14e2c29..8b64fea 100644
--- a/src/gpu/GrTextureProducer.cpp
+++ b/src/gpu/GrTextureProducer.cpp
@@ -69,7 +69,7 @@
     }
 
     SkRect dstRect = SkRect::MakeIWH(copyParams.fWidth, copyParams.fHeight);
-    copyRTC->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect);
+    copyRTC->fillRectToRect(GrNoClip(), paint, GrAA::kNo, SkMatrix::I(), dstRect, localRect);
     return copyRTC->asTexture().release();
 }
 
diff --git a/src/gpu/GrTextureToYUVPlanes.cpp b/src/gpu/GrTextureToYUVPlanes.cpp
index ff6c707..6268bef 100644
--- a/src/gpu/GrTextureToYUVPlanes.cpp
+++ b/src/gpu/GrTextureToYUVPlanes.cpp
@@ -43,7 +43,7 @@
     GrPaint paint;
     paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
     paint.addColorFragmentProcessor(std::move(fp));
-    dst->drawRect(GrNoClip(), paint, SkMatrix::I(), SkRect::MakeIWH(dstW, dstH));
+    dst->drawRect(GrNoClip(), paint, GrAA::kNo, SkMatrix::I(), SkRect::MakeIWH(dstW, dstH));
     return true;
 }
 
diff --git a/src/gpu/GrYUVProvider.cpp b/src/gpu/GrYUVProvider.cpp
index 13e84da..6fbad18 100644
--- a/src/gpu/GrYUVProvider.cpp
+++ b/src/gpu/GrYUVProvider.cpp
@@ -147,7 +147,7 @@
     const SkRect r = SkRect::MakeIWH(yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fWidth,
             yuvInfo.fSizeInfo.fSizes[SkYUVSizeInfo::kY].fHeight);
 
-    renderTargetContext->drawRect(GrNoClip(), paint, SkMatrix::I(), r);
+    renderTargetContext->drawRect(GrNoClip(), paint, GrAA::kNo, SkMatrix::I(), r);
 
     return renderTargetContext->asTexture();
 }
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 1b4c56e..3cdc34e 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -342,7 +342,8 @@
         path.setIsVolatile(true);
         path.moveTo(pts[0]);
         path.lineTo(pts[1]);
-        fRenderTargetContext->drawPath(fClip, grPaint, *draw.fMatrix, path, style);
+        fRenderTargetContext->drawPath(fClip, grPaint, GrBoolToAA(paint.isAntiAlias()),
+                                       *draw.fMatrix, path, style);
         return;
     }
 
@@ -418,13 +419,13 @@
     }
 
     GrStyle style(paint);
-    fRenderTargetContext->drawRect(fClip, grPaint, *draw.fMatrix, rect, &style);
+    fRenderTargetContext->drawRect(fClip, grPaint, GrBoolToAA(paint.isAntiAlias()), *draw.fMatrix,
+                                   rect, &style);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
-void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect,
-                            const SkPaint& paint) {
+void SkGpuDevice::drawRRect(const SkDraw& draw, const SkRRect& rrect, const SkPaint& paint) {
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext.get());
     CHECK_SHOULD_DRAW(draw);
@@ -483,7 +484,8 @@
 
     SkASSERT(!style.pathEffect());
 
-    fRenderTargetContext->drawRRect(fClip, grPaint, *draw.fMatrix, rrect, style);
+    fRenderTargetContext->drawRRect(fClip, grPaint, GrBoolToAA(paint.isAntiAlias()), *draw.fMatrix,
+                                    rrect, style);
 }
 
 
@@ -510,7 +512,8 @@
             return;
         }
 
-        fRenderTargetContext->drawDRRect(fClip, grPaint, *draw.fMatrix, outer, inner);
+        fRenderTargetContext->drawDRRect(fClip, grPaint, GrBoolToAA(paint.isAntiAlias()),
+                                         *draw.fMatrix, outer, inner);
         return;
     }
 
@@ -542,7 +545,8 @@
         return;
     }
 
-    fRenderTargetContext->drawRegion(fClip, grPaint, *draw.fMatrix, region, GrStyle(paint));
+    fRenderTargetContext->drawRegion(fClip, grPaint, GrBoolToAA(paint.isAntiAlias()), *draw.fMatrix,
+                                     region, GrStyle(paint));
 }
 
 void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval, const SkPaint& paint) {
@@ -571,7 +575,8 @@
         return;
     }
 
-    fRenderTargetContext->drawOval(fClip, grPaint, *draw.fMatrix, oval, GrStyle(paint));
+    fRenderTargetContext->drawOval(fClip, grPaint, GrBoolToAA(paint.isAntiAlias()), *draw.fMatrix,
+                                   oval, GrStyle(paint));
 }
 
 void SkGpuDevice::drawArc(const SkDraw& draw, const SkRect& oval, SkScalar startAngle,
@@ -590,8 +595,8 @@
         return;
     }
 
-    fRenderTargetContext->drawArc(fClip, grPaint, *draw.fMatrix, oval, startAngle, sweepAngle,
-                                  useCenter, GrStyle(paint));
+    fRenderTargetContext->drawArc(fClip, grPaint, GrBoolToAA(paint.isAntiAlias()), *draw.fMatrix,
+                                  oval, startAngle, sweepAngle, useCenter, GrStyle(paint));
 }
 
 #include "SkMaskFilter.h"
@@ -647,7 +652,9 @@
         return;
     }
 
-    fRenderTargetContext->fillRectWithLocalMatrix(fClip, grPaint, m, rect, local);
+    fRenderTargetContext->fillRectWithLocalMatrix(fClip, grPaint,
+                                                  GrBoolToAA(newPaint.isAntiAlias()), m, rect,
+                                                  local);
 }
 
 void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
@@ -1096,7 +1103,10 @@
         return;
     }
 
-    fRenderTargetContext->drawRect(fClip, grPaint, viewMatrix, dstRect);
+    // Coverage-based AA would cause seams between tiles.
+    GrAA aa = GrBoolToAA(paint.isAntiAlias() &&
+                         fRenderTargetContext->isStencilBufferMultisampled());
+    fRenderTargetContext->drawRect(fClip, grPaint, aa, viewMatrix, dstRect);
 }
 
 void SkGpuDevice::drawSprite(const SkDraw& draw, const SkBitmap& bitmap,
@@ -1190,6 +1200,7 @@
 
     fRenderTargetContext->fillRectToRect(fClip,
                                          grPaint,
+                                         GrBoolToAA(paint.isAntiAlias()),
                                          SkMatrix::I(),
                                          SkRect::Make(SkIRect::MakeXYWH(left + offset.fX,
                                                                         top + offset.fY,
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index 6501fca..7dc0893 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -213,15 +213,15 @@
                                      fp, producer->isAlphaOnly(), &grPaint)) {
         return;
     }
-
+    GrAA aa = GrBoolToAA(paint.isAntiAlias());
     if (canUseTextureCoordsAsLocalCoords) {
-        fRenderTargetContext->fillRectToRect(clip, grPaint, viewMatrix, clippedDstRect,
+        fRenderTargetContext->fillRectToRect(clip, grPaint, aa, viewMatrix, clippedDstRect,
                                              clippedSrcRect);
         return;
     }
 
     if (!mf) {
-        fRenderTargetContext->drawRect(clip, grPaint, viewMatrix, clippedDstRect);
+        fRenderTargetContext->drawRect(clip, grPaint, aa, viewMatrix, clippedDstRect);
         return;
     }
 
@@ -247,6 +247,6 @@
     rectPath.addRect(clippedDstRect);
     rectPath.setIsVolatile(true);
     GrBlurUtils::drawPathWithMaskFilter(this->context(), fRenderTargetContext.get(), fClip,
-                                        rectPath, &grPaint, viewMatrix, mf, GrStyle::SimpleFill(),
-                                        true);
+                                        rectPath, &grPaint, aa, viewMatrix, mf,
+                                        GrStyle::SimpleFill(), true);
 }
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 4e04601..4147855 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -560,7 +560,6 @@
                                            SkBlendMode* primColorMode,
                                            bool primitiveIsSrc,
                                            GrPaint* grPaint) {
-    grPaint->setAntiAlias(skPaint.isAntiAlias());
     grPaint->setAllowSRGBInputs(rtc->isGammaCorrect());
 
     // Convert SkPaint color to 4f format, including optional linearizing and gamut conversion.
diff --git a/src/gpu/batches/GrAAConvexPathRenderer.cpp b/src/gpu/batches/GrAAConvexPathRenderer.cpp
index 56a5e7a..cc31f49 100644
--- a/src/gpu/batches/GrAAConvexPathRenderer.cpp
+++ b/src/gpu/batches/GrAAConvexPathRenderer.cpp
@@ -672,7 +672,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    return (args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
+    return (args.fShaderCaps->shaderDerivativeSupport() && (GrAAType::kCoverage == args.fAAType) &&
             args.fShape->style().isSimpleFill() && !args.fShape->inverseFilled() &&
             args.fShape->knownToBeConvex());
 }
@@ -1002,7 +1002,7 @@
 
     sk_sp<GrDrawOp> batch(new AAConvexPathBatch(args.fPaint->getColor(), *args.fViewMatrix, path));
 
-    GrPipelineBuilder pipelineBuilder(*args.fPaint);
+    GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fAAType);
     pipelineBuilder.setUserStencil(args.fUserStencilSettings);
 
     args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, batch.get());
diff --git a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
index 0aa451d..71b9000 100644
--- a/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
+++ b/src/gpu/batches/GrAADistanceFieldPathRenderer.cpp
@@ -90,8 +90,8 @@
     if (!args.fShape->style().isSimpleFill()) {
         return false;
     }
-    // This does non-inverse antialiased fills.
-    if (!args.fAntiAlias) {
+    // This does non-inverse coverage-based antialiased fills.
+    if (GrAAType::kCoverage != args.fAAType) {
         return false;
     }
     // TODO: Support inverse fill
@@ -128,7 +128,6 @@
 
     AADistanceFieldPathBatch(GrColor color,
                              const GrShape& shape,
-                             bool antiAlias,
                              const SkMatrix& viewMatrix,
                              GrBatchAtlas* atlas,
                              ShapeCache* shapeCache, ShapeDataList* shapeList,
@@ -136,7 +135,7 @@
             : INHERITED(ClassID()) {
         SkASSERT(shape.hasUnstyledKey());
         fBatch.fViewMatrix = viewMatrix;
-        fGeoData.emplace_back(Geometry{color, shape, antiAlias});
+        fGeoData.emplace_back(Geometry{color, shape});
 
         fAtlas = atlas;
         fShapeCache = shapeCache;
@@ -157,7 +156,7 @@
     SkString dumpInfo() const override {
         SkString string;
         for (const auto& geo : fGeoData) {
-            string.appendf("Color: 0x%08x AA:%d\n", geo.fColor, geo.fAntiAlias);
+            string.appendf("Color: 0x%08x\n", geo.fColor);
         }
         string.append(DumpPipelineInfo(*this->pipeline()));
         string.append(INHERITED::dumpInfo());
@@ -274,7 +273,6 @@
                                           atlas,
                                           shapeData,
                                           args.fShape,
-                                          args.fAntiAlias,
                                           desiredDimension,
                                           scale)) {
                     delete shapeData;
@@ -300,8 +298,8 @@
     }
 
     bool addPathToAtlas(GrMeshDrawOp::Target* target, FlushInfo* flushInfo, GrBatchAtlas* atlas,
-                        ShapeData* shapeData, const GrShape& shape, bool antiAlias,
-                        uint32_t dimension, SkScalar scale) const {
+                        ShapeData* shapeData, const GrShape& shape, uint32_t dimension,
+                        SkScalar scale) const {
         const SkRect& bounds = shape.bounds();
 
         // generate bounding rect for bitmap draw
@@ -348,7 +346,7 @@
         // rasterize path
         SkPaint paint;
         paint.setStyle(SkPaint::kFill_Style);
-        paint.setAntiAlias(antiAlias);
+        paint.setAntiAlias(true);
 
         SkDraw draw;
         sk_bzero(&draw, sizeof(draw));
@@ -502,7 +500,6 @@
     struct Geometry {
         GrColor fColor;
         GrShape fShape;
-        bool fAntiAlias;
     };
 
     BatchTracker fBatch;
@@ -518,8 +515,6 @@
 bool GrAADistanceFieldPathRenderer::onDrawPath(const DrawPathArgs& args) {
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
                               "GrAADistanceFieldPathRenderer::onDrawPath");
-    SkASSERT(!args.fRenderTargetContext->isUnifiedMultisampled());
-    SkASSERT(args.fShape->style().isSimpleFill());
 
     // we've already bailed on inverse filled paths, so this is safe
     SkASSERT(!args.fShape->isEmpty());
@@ -536,11 +531,10 @@
     }
 
     sk_sp<GrDrawOp> batch(new AADistanceFieldPathBatch(args.fPaint->getColor(),
-                                                       *args.fShape,
-                                                       args.fAntiAlias, *args.fViewMatrix,
+                                                       *args.fShape, *args.fViewMatrix,
                                                        fAtlas.get(), &fShapeCache, &fShapeList,
                                                        args.fGammaCorrect));
-    GrPipelineBuilder pipelineBuilder(*args.fPaint);
+    GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fAAType);
     pipelineBuilder.setUserStencil(args.fUserStencilSettings);
 
     args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, batch.get());
@@ -614,11 +608,9 @@
 
     // This path renderer only allows fill styles.
     GrShape shape(GrTest::TestPath(random), GrStyle::SimpleFill());
-    bool antiAlias = random->nextBool();
 
     return new AADistanceFieldPathBatch(color,
                                         shape,
-                                        antiAlias,
                                         viewMatrix,
                                         gTestStruct.fAtlas.get(),
                                         &gTestStruct.fShapeCache,
diff --git a/src/gpu/batches/GrAAHairLinePathRenderer.cpp b/src/gpu/batches/GrAAHairLinePathRenderer.cpp
index 662010f..732d694 100644
--- a/src/gpu/batches/GrAAHairLinePathRenderer.cpp
+++ b/src/gpu/batches/GrAAHairLinePathRenderer.cpp
@@ -617,7 +617,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool GrAAHairLinePathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    if (!args.fAntiAlias) {
+    if (GrAAType::kCoverage != args.fAAType) {
         return false;
     }
 
@@ -981,7 +981,7 @@
                                                 *args.fViewMatrix, path,
                                                 args.fShape->style(), devClipBounds));
 
-    GrPipelineBuilder pipelineBuilder(*args.fPaint);
+    GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fAAType);
     pipelineBuilder.setUserStencil(args.fUserStencilSettings);
     args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, batch.get());
 
diff --git a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
index f961c5e..cbf526c 100644
--- a/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
+++ b/src/gpu/batches/GrAALinearizingConvexPathRenderer.cpp
@@ -37,7 +37,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    if (!args.fAntiAlias) {
+    if (GrAAType::kCoverage != args.fAAType) {
         return false;
     }
     if (!args.fShape->knownToBeConvex()) {
@@ -361,7 +361,7 @@
                                                           stroke.getStyle(),
                                                           join, miterLimit));
 
-    GrPipelineBuilder pipelineBuilder(*args.fPaint);
+    GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fAAType);
     pipelineBuilder.setUserStencil(args.fUserStencilSettings);
 
     args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, batch.get());
diff --git a/src/gpu/batches/GrDashLinePathRenderer.cpp b/src/gpu/batches/GrDashLinePathRenderer.cpp
index d2a420d..9304885 100644
--- a/src/gpu/batches/GrDashLinePathRenderer.cpp
+++ b/src/gpu/batches/GrDashLinePathRenderer.cpp
@@ -16,6 +16,9 @@
     SkPoint pts[2];
     bool inverted;
     if (args.fShape->style().isDashed() && args.fShape->asLine(pts, &inverted)) {
+        if (args.fAAType == GrAAType::kMixedSamples) {
+            return false;
+        }
         // We should never have an inverse dashed case.
         SkASSERT(!inverted);
         return GrDashingEffect::CanDrawDashLine(pts, args.fShape->style(), *args.fViewMatrix);
@@ -26,16 +29,19 @@
 bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) {
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
                               "GrDashLinePathRenderer::onDrawPath");
-    bool useHWAA = args.fRenderTargetContext->isUnifiedMultisampled();
-    GrDashingEffect::AAMode aaMode;
-    if (useHWAA) {
-        // We ignore args.fAntiAlias here and force anti aliasing when using MSAA. Otherwise,
-        // we can wind up with external edges antialiased and internal edges unantialiased.
-        aaMode = GrDashingEffect::AAMode::kCoverageWithMSAA;
-    } else if (args.fAntiAlias) {
-        aaMode = GrDashingEffect::AAMode::kCoverage;
-    } else {
-        aaMode = GrDashingEffect::AAMode::kNone;
+    GrDashingEffect::AAMode aaMode = GrDashingEffect::AAMode::kNone;
+    switch (args.fAAType) {
+        case GrAAType::kNone:
+            break;
+        case GrAAType::kCoverage:
+        case GrAAType::kMixedSamples:
+            aaMode = GrDashingEffect::AAMode::kCoverage;
+            break;
+        case GrAAType::kMSAA:
+            // 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 = GrDashingEffect::AAMode::kCoverageWithMSAA;
+            break;
     }
     SkPoint pts[2];
     SkAssertResult(args.fShape->asLine(pts, nullptr));
@@ -48,7 +54,7 @@
         return false;
     }
 
-    GrPipelineBuilder pipelineBuilder(*args.fPaint, useHWAA);
+    GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fAAType);
     pipelineBuilder.setUserStencil(args.fUserStencilSettings);
 
     args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, batch.get());
diff --git a/src/gpu/batches/GrDefaultPathRenderer.cpp b/src/gpu/batches/GrDefaultPathRenderer.cpp
index f3f9e73..0b688c5 100644
--- a/src/gpu/batches/GrDefaultPathRenderer.cpp
+++ b/src/gpu/batches/GrDefaultPathRenderer.cpp
@@ -424,11 +424,13 @@
 
 bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext,
                                              const GrPaint& paint,
+                                             GrAAType aaType,
                                              const GrUserStencilSettings& userStencilSettings,
                                              const GrClip& clip,
                                              const SkMatrix& viewMatrix,
                                              const GrShape& shape,
                                              bool stencilOnly) {
+    SkASSERT(GrAAType::kCoverage != aaType);
     SkPath path;
     shape.asPath(&path);
 
@@ -567,23 +569,20 @@
                                                         &localMatrix));
 
             SkASSERT(GrDrawFace::kBoth == drawFace[p]);
-            GrPipelineBuilder pipelineBuilder(paint, renderTargetContext->mustUseHWAA(paint));
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             pipelineBuilder.setDrawFace(drawFace[p]);
             pipelineBuilder.setUserStencil(passes[p]);
-
             renderTargetContext->addDrawOp(pipelineBuilder, clip, batch.get());
         } else {
             sk_sp<GrDrawOp> batch(new DefaultPathBatch(paint.getColor(), path, srcSpaceTol,
                                                        newCoverage, viewMatrix, isHairline,
                                                        devBounds));
-
-            GrPipelineBuilder pipelineBuilder(paint, renderTargetContext->mustUseHWAA(paint));
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             pipelineBuilder.setDrawFace(drawFace[p]);
             pipelineBuilder.setUserStencil(passes[p]);
             if (passCount > 1) {
                 pipelineBuilder.setDisableColorXPFactory();
             }
-
             renderTargetContext->addDrawOp(pipelineBuilder, clip, batch.get());
         }
     }
@@ -591,8 +590,8 @@
 }
 
 bool GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
-    // this class can draw any path with any simple fill style but doesn't do any anti-aliasing.
-    return !args.fAntiAlias &&
+    // This can draw any path with any simple fill style but doesn't do coverage-based antialiasing.
+    return GrAAType::kCoverage != args.fAAType &&
            (args.fShape->style().isSimpleFill() ||
             IsStrokeHairlineOrEquivalent(args.fShape->style(), *args.fViewMatrix, nullptr));
 }
@@ -602,6 +601,7 @@
                               "GrDefaultPathRenderer::onDrawPath");
     return this->internalDrawPath(args.fRenderTargetContext,
                                   *args.fPaint,
+                                  args.fAAType,
                                   *args.fUserStencilSettings,
                                   *args.fClip,
                                   *args.fViewMatrix,
@@ -616,10 +616,10 @@
 
     GrPaint paint;
     paint.setXPFactory(GrDisableColorXPFactory::Make());
-    paint.setAntiAlias(args.fIsAA);
 
-    this->internalDrawPath(args.fRenderTargetContext, paint, GrUserStencilSettings::kUnused,
-                           *args.fClip, *args.fViewMatrix, *args.fShape, true);
+    this->internalDrawPath(args.fRenderTargetContext, paint, args.fAAType,
+                           GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix,
+                           *args.fShape, true);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/batches/GrDefaultPathRenderer.h b/src/gpu/batches/GrDefaultPathRenderer.h
index 243d4e7..8e19247 100644
--- a/src/gpu/batches/GrDefaultPathRenderer.h
+++ b/src/gpu/batches/GrDefaultPathRenderer.h
@@ -32,6 +32,7 @@
 
     bool internalDrawPath(GrRenderTargetContext*,
                           const GrPaint&,
+                          GrAAType,
                           const GrUserStencilSettings&,
                           const GrClip&,
                           const SkMatrix& viewMatrix,
diff --git a/src/gpu/batches/GrMSAAPathRenderer.cpp b/src/gpu/batches/GrMSAAPathRenderer.cpp
index f073db0..930f7f9 100644
--- a/src/gpu/batches/GrMSAAPathRenderer.cpp
+++ b/src/gpu/batches/GrMSAAPathRenderer.cpp
@@ -562,6 +562,7 @@
 
 bool GrMSAAPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext,
                                           const GrPaint& paint,
+                                          GrAAType aaType,
                                           const GrUserStencilSettings& userStencilSettings,
                                           const GrClip& clip,
                                           const SkMatrix& viewMatrix,
@@ -662,7 +663,7 @@
                     GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewM, bounds, nullptr,
                                                         &localMatrix));
 
-            GrPipelineBuilder pipelineBuilder(paint, renderTargetContext->mustUseHWAA(paint));
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             pipelineBuilder.setUserStencil(passes[p]);
 
             renderTargetContext->addDrawOp(pipelineBuilder, clip, batch.get());
@@ -673,12 +674,11 @@
                 return false;
             }
 
-            GrPipelineBuilder pipelineBuilder(paint, renderTargetContext->mustUseHWAA(paint));
+            GrPipelineBuilder pipelineBuilder(paint, aaType);
             pipelineBuilder.setUserStencil(passes[p]);
             if (passCount > 1) {
                 pipelineBuilder.setDisableColorXPFactory();
             }
-
             renderTargetContext->addDrawOp(pipelineBuilder, clip, batch.get());
         }
     }
@@ -689,7 +689,7 @@
     // This path renderer only fills and relies on MSAA for antialiasing. Stroked shapes are
     // handled by passing on the original shape and letting the caller compute the stroked shape
     // which will have a fill style.
-    return args.fShape->style().isSimpleFill() && !args.fAntiAlias;
+    return args.fShape->style().isSimpleFill() && (GrAAType::kCoverage != args.fAAType);
 }
 
 bool GrMSAAPathRenderer::onDrawPath(const DrawPathArgs& args) {
@@ -704,6 +704,7 @@
     }
     return this->internalDrawPath(args.fRenderTargetContext,
                                   *args.fPaint,
+                                  args.fAAType,
                                   *args.fUserStencilSettings,
                                   *args.fClip,
                                   *args.fViewMatrix,
@@ -719,10 +720,10 @@
 
     GrPaint paint;
     paint.setXPFactory(GrDisableColorXPFactory::Make());
-    paint.setAntiAlias(args.fIsAA);
 
-    this->internalDrawPath(args.fRenderTargetContext, paint, GrUserStencilSettings::kUnused,
-                           *args.fClip, *args.fViewMatrix, *args.fShape, true);
+    this->internalDrawPath(args.fRenderTargetContext, paint, args.fAAType,
+                           GrUserStencilSettings::kUnused, *args.fClip, *args.fViewMatrix,
+                           *args.fShape, true);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/batches/GrMSAAPathRenderer.h b/src/gpu/batches/GrMSAAPathRenderer.h
index 3a70bcb..a112c62 100644
--- a/src/gpu/batches/GrMSAAPathRenderer.h
+++ b/src/gpu/batches/GrMSAAPathRenderer.h
@@ -23,6 +23,7 @@
 
     bool internalDrawPath(GrRenderTargetContext*,
                           const GrPaint&,
+                          GrAAType,
                           const GrUserStencilSettings&,
                           const GrClip&,
                           const SkMatrix& viewMatrix,
diff --git a/src/gpu/batches/GrPLSPathRenderer.cpp b/src/gpu/batches/GrPLSPathRenderer.cpp
index 6dd2199..269fde1 100644
--- a/src/gpu/batches/GrPLSPathRenderer.cpp
+++ b/src/gpu/batches/GrPLSPathRenderer.cpp
@@ -758,7 +758,7 @@
     // seams. Disable in the presence of even-odd for now.
     SkPath path;
     args.fShape->asPath(&path);
-    return args.fShaderCaps->shaderDerivativeSupport() && args.fAntiAlias &&
+    return args.fShaderCaps->shaderDerivativeSupport() && GrAAType::kCoverage == args.fAAType &&
             args.fShape->style().isSimpleFill() && !path.isInverseFillType() &&
             path.getFillType() == SkPath::FillType::kWinding_FillType;
 }
@@ -936,13 +936,10 @@
     args.fShape->asPath(&path);
 
     sk_sp<GrDrawOp> batch(new PLSPathBatch(args.fPaint->getColor(), path, *args.fViewMatrix));
-
-    GrPipelineBuilder pipelineBuilder(*args.fPaint,
-                                      args.fRenderTargetContext->mustUseHWAA(*args.fPaint));
+    GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fAAType);
     pipelineBuilder.setUserStencil(args.fUserStencilSettings);
 
     args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, batch.get());
-
     SkDEBUGCODE(inPLSDraw = false;)
     return true;
 
diff --git a/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp b/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
index 97287d2..ac9ed90 100644
--- a/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
@@ -44,11 +44,8 @@
     if (args.fHasUserStencilSettings) {
         return false;
     }
-    if (args.fAntiAlias) {
-        return args.fIsStencilBufferMSAA;
-    } else {
-        return true; // doesn't do per-path AA, relies on the target having MSAA
-    }
+    // doesn't do per-path AA, relies on the target having MSAA.
+    return (GrAAType::kCoverage != args.fAAType);
 }
 
 static GrPath* get_gr_path(GrResourceProvider* resourceProvider, const GrShape& shape) {
@@ -80,18 +77,14 @@
 void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) {
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
                               "GrStencilAndCoverPathRenderer::onStencilPath");
-    SkASSERT(!args.fIsAA || args.fRenderTargetContext->isStencilBufferMultisampled());
-
     sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape));
-    args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fIsAA,
+    args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType,
                                                   *args.fViewMatrix, p.get());
 }
 
 bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
     GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
                               "GrStencilAndCoverPathRenderer::onDrawPath");
-    SkASSERT(!args.fPaint->isAntiAlias() ||
-             args.fRenderTargetContext->isStencilBufferMultisampled());
     SkASSERT(!args.fShape->style().strokeRec().isHairlineStyle());
 
     const SkMatrix& viewMatrix = *args.fViewMatrix;
@@ -125,8 +118,8 @@
                                                     nullptr, &invert));
 
         // fake inverse with a stencil and cover
-        args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fPaint->isAntiAlias(),
-                                                      viewMatrix, path.get());
+        args.fRenderTargetContext->priv().stencilPath(*args.fClip, args.fAAType, viewMatrix,
+                                                      path.get());
 
         {
             static constexpr GrUserStencilSettings kInvertedCoverPass(
@@ -141,10 +134,13 @@
                     GrUserStencilOp::kZero,
                     0xffff>()
             );
-
-            GrPipelineBuilder pipelineBuilder(*args.fPaint,
-                                              args.fPaint->isAntiAlias() &&
-                                              !args.fRenderTargetContext->hasMixedSamples());
+            // 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;
+            }
+            GrPipelineBuilder pipelineBuilder(*args.fPaint, coverAAType);
             pipelineBuilder.setUserStencil(&kInvertedCoverPass);
 
             args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, coverBatch.get());
@@ -163,13 +159,8 @@
         sk_sp<GrDrawOp> batch(GrDrawPathBatch::Create(viewMatrix, args.fPaint->getColor(),
                                                       path.get()));
 
-        GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fPaint->isAntiAlias());
+        GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fAAType);
         pipelineBuilder.setUserStencil(&kCoverPass);
-        if (args.fAntiAlias) {
-            SkASSERT(args.fRenderTargetContext->isStencilBufferMultisampled());
-            pipelineBuilder.enableState(GrPipelineBuilder::kHWAntialias_Flag);
-        }
-
         args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, batch.get());
     }
 
diff --git a/src/gpu/batches/GrTessellatingPathRenderer.cpp b/src/gpu/batches/GrTessellatingPathRenderer.cpp
index afa9fe7..4b3ef00 100644
--- a/src/gpu/batches/GrTessellatingPathRenderer.cpp
+++ b/src/gpu/batches/GrTessellatingPathRenderer.cpp
@@ -140,7 +140,7 @@
     if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
         return false;
     }
-    if (args.fAntiAlias) {
+    if (GrAAType::kCoverage == args.fAAType) {
 #ifdef SK_DISABLE_SCREENSPACE_TESS_AA_PATH_RENDERER
         return false;
 #else
@@ -364,14 +364,10 @@
                                                         *args.fShape,
                                                         *args.fViewMatrix,
                                                         clipBoundsI,
-                                                        args.fAntiAlias));
-
-    GrPipelineBuilder pipelineBuilder(*args.fPaint,
-                                      args.fRenderTargetContext->mustUseHWAA(*args.fPaint));
+                                                        GrAAType::kCoverage == args.fAAType));
+    GrPipelineBuilder pipelineBuilder(*args.fPaint, args.fAAType);
     pipelineBuilder.setUserStencil(args.fUserStencilSettings);
-
     args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, batch.get());
-
     return true;
 }
 
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index f700312..f6f8334 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -237,19 +237,19 @@
         paint1.addColorFragmentProcessor(std::move(pmToUPM1));
         paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
-        readRTC->fillRectToRect(GrNoClip(), paint1, SkMatrix::I(), kDstRect, kSrcRect);
+        readRTC->fillRectToRect(GrNoClip(), paint1, GrAA::kNo, SkMatrix::I(), kDstRect, kSrcRect);
 
         readRTC->asTexture()->readPixels(0, 0, kSize, kSize, kConfig, firstRead);
 
         paint2.addColorFragmentProcessor(std::move(upmToPM));
         paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
-        tempRTC->fillRectToRect(GrNoClip(), paint2, SkMatrix::I(), kDstRect, kSrcRect);
+        tempRTC->fillRectToRect(GrNoClip(), paint2, GrAA::kNo, SkMatrix::I(), kDstRect, kSrcRect);
 
         paint3.addColorFragmentProcessor(std::move(pmToUPM2));
         paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
-        readRTC->fillRectToRect(GrNoClip(), paint3, SkMatrix::I(), kDstRect, kSrcRect);
+        readRTC->fillRectToRect(GrNoClip(), paint3, GrAA::kNo, SkMatrix::I(), kDstRect, kSrcRect);
 
         readRTC->asTexture()->readPixels(0, 0, kSize, kSize, kConfig, secondRead);
 
diff --git a/src/gpu/instanced/InstancedRendering.cpp b/src/gpu/instanced/InstancedRendering.cpp
index 135a061..faecfe5 100644
--- a/src/gpu/instanced/InstancedRendering.cpp
+++ b/src/gpu/instanced/InstancedRendering.cpp
@@ -22,28 +22,27 @@
 }
 
 GrDrawOp* InstancedRendering::recordRect(const SkRect& rect, const SkMatrix& viewMatrix,
-                                         GrColor color, bool antialias,
-                                         const GrInstancedPipelineInfo& info, bool* useHWAA) {
-    return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect, antialias, info,
-                             useHWAA);
+                                         GrColor color, GrAA aa,
+                                         const GrInstancedPipelineInfo& info, GrAAType* aaType) {
+    return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect, aa, info, aaType);
 }
 
 GrDrawOp* InstancedRendering::recordRect(const SkRect& rect, const SkMatrix& viewMatrix,
-                                         GrColor color, const SkRect& localRect, bool antialias,
-                                         const GrInstancedPipelineInfo& info, bool* useHWAA) {
-    return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, localRect, antialias, info,
-                             useHWAA);
+                                         GrColor color, const SkRect& localRect, GrAA aa,
+                                         const GrInstancedPipelineInfo& info, GrAAType* aaType) {
+    return this->recordShape(ShapeType::kRect, rect, viewMatrix, color, localRect, aa, info,
+                             aaType);
 }
 
 GrDrawOp* InstancedRendering::recordRect(const SkRect& rect, const SkMatrix& viewMatrix,
                                          GrColor color, const SkMatrix& localMatrix,
-                                         bool antialias, const GrInstancedPipelineInfo& info,
-                                         bool* useHWAA) {
+                                         GrAA aa, const GrInstancedPipelineInfo& info,
+                                         GrAAType* aaType) {
     if (localMatrix.hasPerspective()) {
         return nullptr; // Perspective is not yet supported in the local matrix.
     }
-    if (Batch* batch = this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect, antialias,
-                                         info, useHWAA)) {
+    if (Batch* batch = this->recordShape(ShapeType::kRect, rect, viewMatrix, color, rect, aa,
+                                         info, aaType)) {
         batch->getSingleInstance().fInfo |= kLocalMatrix_InfoFlag;
         batch->appendParamsTexel(localMatrix.getScaleX(), localMatrix.getSkewX(),
                                  localMatrix.getTranslateX());
@@ -56,17 +55,16 @@
 }
 
 GrDrawOp* InstancedRendering::recordOval(const SkRect& oval, const SkMatrix& viewMatrix,
-                                         GrColor color, bool antialias,
-                                         const GrInstancedPipelineInfo& info, bool* useHWAA) {
-    return this->recordShape(ShapeType::kOval, oval, viewMatrix, color, oval, antialias, info,
-                             useHWAA);
+                                         GrColor color, GrAA aa,
+                                         const GrInstancedPipelineInfo& info, GrAAType* aaType) {
+    return this->recordShape(ShapeType::kOval, oval, viewMatrix, color, oval, aa, info, aaType);
 }
 
 GrDrawOp* InstancedRendering::recordRRect(const SkRRect& rrect, const SkMatrix& viewMatrix,
-                                          GrColor color, bool antialias,
-                                          const GrInstancedPipelineInfo& info, bool* useHWAA) {
+                                          GrColor color, GrAA aa,
+                                          const GrInstancedPipelineInfo& info, GrAAType* aaType) {
     if (Batch* batch = this->recordShape(GetRRectShapeType(rrect), rrect.rect(), viewMatrix, color,
-                                         rrect.rect(), antialias, info, useHWAA)) {
+                                         rrect.rect(), aa, info, aaType)) {
         batch->appendRRectParams(rrect);
         return batch;
     }
@@ -75,16 +73,16 @@
 
 GrDrawOp* InstancedRendering::recordDRRect(const SkRRect& outer, const SkRRect& inner,
                                            const SkMatrix& viewMatrix, GrColor color,
-                                           bool antialias, const GrInstancedPipelineInfo& info,
-                                           bool* useHWAA) {
+                                           GrAA aa, const GrInstancedPipelineInfo& info,
+                                           GrAAType* aaType) {
     if (inner.getType() > SkRRect::kSimple_Type) {
        return nullptr; // Complex inner round rects are not yet supported.
     }
     if (SkRRect::kEmpty_Type == inner.getType()) {
-        return this->recordRRect(outer, viewMatrix, color, antialias, info, useHWAA);
+        return this->recordRRect(outer, viewMatrix, color, aa, info, aaType);
     }
     if (Batch* batch = this->recordShape(GetRRectShapeType(outer), outer.rect(), viewMatrix, color,
-                                         outer.rect(), antialias, info, useHWAA)) {
+                                         outer.rect(), aa, info, aaType)) {
         batch->appendRRectParams(outer);
         ShapeType innerShapeType = GetRRectShapeType(inner);
         batch->fInfo.fInnerShapeTypes |= GetShapeFlag(innerShapeType);
@@ -99,9 +97,9 @@
 InstancedRendering::Batch* InstancedRendering::recordShape(ShapeType type, const SkRect& bounds,
                                                            const SkMatrix& viewMatrix,
                                                            GrColor color, const SkRect& localRect,
-                                                           bool antialias,
+                                                           GrAA aa,
                                                            const GrInstancedPipelineInfo& info,
-                                                           bool* useHWAA) {
+                                                           GrAAType* aaType) {
     SkASSERT(State::kRecordingDraws == fState);
 
     if (info.fIsRenderingToFloat && fGpu->caps()->avoidInstancedDrawsToFPTargets()) {
@@ -109,7 +107,7 @@
     }
 
     AntialiasMode antialiasMode;
-    if (!this->selectAntialiasMode(viewMatrix, antialias, info, useHWAA, &antialiasMode)) {
+    if (!this->selectAntialiasMode(viewMatrix, aa, info, aaType, &antialiasMode)) {
         return nullptr;
     }
 
@@ -193,27 +191,28 @@
     return batch;
 }
 
-inline bool InstancedRendering::selectAntialiasMode(const SkMatrix& viewMatrix, bool antialias,
+inline bool InstancedRendering::selectAntialiasMode(const SkMatrix& viewMatrix, GrAA aa,
                                                     const GrInstancedPipelineInfo& info,
-                                                    bool* useHWAA, AntialiasMode* antialiasMode) {
+                                                    GrAAType* aaType,
+                                                    AntialiasMode* antialiasMode) {
     SkASSERT(!info.fColorDisabled || info.fDrawingShapeToStencil);
     SkASSERT(!info.fIsMixedSampled || info.fIsMultisampled);
     SkASSERT(GrCaps::InstancedSupport::kNone != fGpu->caps()->instancedSupport());
 
     if (!info.fIsMultisampled || fGpu->caps()->multisampleDisableSupport()) {
-        if (!antialias) {
+        if (GrAA::kNo == aa) {
             if (info.fDrawingShapeToStencil && !info.fCanDiscard) {
                 // We can't draw to the stencil buffer without discard (or sample mask if MSAA).
                 return false;
             }
             *antialiasMode = AntialiasMode::kNone;
-            *useHWAA = false;
+            *aaType = GrAAType::kNone;
             return true;
         }
 
         if (info.canUseCoverageAA() && viewMatrix.preservesRightAngles()) {
             *antialiasMode = AntialiasMode::kCoverage;
-            *useHWAA = false;
+            *aaType = GrAAType::kCoverage;
             return true;
         }
     }
@@ -222,12 +221,12 @@
         fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMultisampled) {
         if (!info.fIsMixedSampled || info.fColorDisabled) {
             *antialiasMode = AntialiasMode::kMSAA;
-            *useHWAA = true;
+            *aaType = GrAAType::kMSAA;
             return true;
         }
         if (fGpu->caps()->instancedSupport() >= GrCaps::InstancedSupport::kMixedSampled) {
             *antialiasMode = AntialiasMode::kMixedSamples;
-            *useHWAA = true;
+            *aaType = GrAAType::kMixedSamples;
             return true;
         }
     }
diff --git a/src/gpu/instanced/InstancedRendering.h b/src/gpu/instanced/InstancedRendering.h
index d3a0152..9036974 100644
--- a/src/gpu/instanced/InstancedRendering.h
+++ b/src/gpu/instanced/InstancedRendering.h
@@ -46,28 +46,25 @@
      * draws between beginFlush() and endFlush().
      */
     GrDrawOp* SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&, GrColor,
-                                               bool antialias, const GrInstancedPipelineInfo&,
-                                               bool* useHWAA);
+                                               GrAA, const GrInstancedPipelineInfo&, GrAAType*);
 
     GrDrawOp* SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&, GrColor,
-                                               const SkRect& localRect, bool antialias,
-                                               const GrInstancedPipelineInfo&, bool* useHWAA);
+                                               const SkRect& localRect, GrAA,
+                                               const GrInstancedPipelineInfo&, GrAAType*);
 
     GrDrawOp* SK_WARN_UNUSED_RESULT recordRect(const SkRect&, const SkMatrix&, GrColor,
-                                               const SkMatrix& localMatrix, bool antialias,
-                                               const GrInstancedPipelineInfo&, bool* useHWAA);
+                                               const SkMatrix& localMatrix, GrAA,
+                                               const GrInstancedPipelineInfo&, GrAAType*);
 
     GrDrawOp* SK_WARN_UNUSED_RESULT recordOval(const SkRect&, const SkMatrix&, GrColor,
-                                               bool antialias, const GrInstancedPipelineInfo&,
-                                               bool* useHWAA);
+                                               GrAA, const GrInstancedPipelineInfo&, GrAAType*);
 
     GrDrawOp* SK_WARN_UNUSED_RESULT recordRRect(const SkRRect&, const SkMatrix&, GrColor,
-                                                bool antialias, const GrInstancedPipelineInfo&,
-                                                bool* useHWAA);
+                                                GrAA, const GrInstancedPipelineInfo&, GrAAType*);
 
     GrDrawOp* SK_WARN_UNUSED_RESULT recordDRRect(const SkRRect& outer, const SkRRect& inner,
-                                                 const SkMatrix&, GrColor, bool antialias,
-                                                 const GrInstancedPipelineInfo&, bool* useHWAA);
+                                                 const SkMatrix&, GrColor, GrAA,
+                                                 const GrInstancedPipelineInfo&, GrAAType*);
 
     /**
      * Compiles all recorded draws into GPU buffers and allows the client to begin flushing the
@@ -182,11 +179,11 @@
 
     Batch* SK_WARN_UNUSED_RESULT recordShape(ShapeType, const SkRect& bounds,
                                              const SkMatrix& viewMatrix, GrColor,
-                                             const SkRect& localRect, bool antialias,
-                                             const GrInstancedPipelineInfo&, bool* requireHWAA);
+                                             const SkRect& localRect, GrAA aa,
+                                             const GrInstancedPipelineInfo&, GrAAType*);
 
-    bool selectAntialiasMode(const SkMatrix& viewMatrix, bool antialias,
-                             const GrInstancedPipelineInfo&, bool* useHWAA, AntialiasMode*);
+    bool selectAntialiasMode(const SkMatrix& viewMatrix, GrAA aa, const GrInstancedPipelineInfo&,
+                             GrAAType*, AntialiasMode*);
 
     virtual Batch* createBatch() = 0;
 
diff --git a/src/gpu/instanced/InstancedRenderingTypes.h b/src/gpu/instanced/InstancedRenderingTypes.h
index 97f8946..2ed269a 100644
--- a/src/gpu/instanced/InstancedRenderingTypes.h
+++ b/src/gpu/instanced/InstancedRenderingTypes.h
@@ -42,6 +42,7 @@
 };
 constexpr int kNumAttribs = 1 + (int)Attrib::kLocalRect;
 
+// TODO: replace with GrAAType?
 enum class AntialiasMode : uint8_t {
     kNone,
     kCoverage,
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp
index 5b35f84..1fb4f2c 100644
--- a/src/gpu/text/GrAtlasTextBlob.cpp
+++ b/src/gpu/text/GrAtlasTextBlob.cpp
@@ -323,8 +323,7 @@
                                                 distanceAdjustTable,
                                                 rtc->isGammaCorrect(),
                                                 cache));
-
-        GrPipelineBuilder pipelineBuilder(grPaint, rtc->mustUseHWAA(grPaint));
+        GrPipelineBuilder pipelineBuilder(grPaint, GrAAType::kNone);
 
         rtc->addDrawOp(pipelineBuilder, clip, batch.get());
     }
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp
index ba98784..b573b83 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp
@@ -224,10 +224,8 @@
 
     TextBlob::Iter iter(blob);
     for (TextRun* run = iter.get(); run; run = iter.next()) {
-        // The run's "font" overrides the anti-aliasing of the passed in paint!
-        paint.setAntiAlias(run->isAntiAlias());
-        run->draw(context, rtc, paint, clip, viewMatrix, props,  x, y,
-                  clipBounds, fFallbackTextContext, skPaint);
+        run->draw(context, rtc, paint, clip, viewMatrix, props,  x, y, clipBounds,
+                  fFallbackTextContext, skPaint);
         run->releaseGlyphCache();
     }
 }
@@ -605,8 +603,9 @@
                                                  const SkIRect& clipBounds,
                                                  GrAtlasTextContext* fallbackTextContext,
                                                  const SkPaint& originalSkPaint) const {
+    GrAA runAA = this->isAntiAlias();
     SkASSERT(fInstanceData);
-    SkASSERT(renderTargetContext->isStencilBufferMultisampled() || !grPaint.isAntiAlias());
+    SkASSERT(renderTargetContext->isStencilBufferMultisampled() || GrAA::kNo == runAA);
 
     if (fInstanceData->count()) {
         static constexpr GrUserStencilSettings kCoverPass(
@@ -640,8 +639,16 @@
                                          GrPathRendering::kWinding_FillType, glyphs.get(),
                                          fInstanceData.get(), bounds));
 
-        GrPipelineBuilder pipelineBuilder(grPaint);
-        pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, grPaint.isAntiAlias());
+        // The run's "font" overrides the anti-aliasing of the passed in SkPaint!
+        GrAAType aaType = GrAAType::kNone;
+        if (GrAA::kYes == runAA) {
+            if (renderTargetContext->isUnifiedMultisampled()) {
+                aaType = GrAAType::kMSAA;
+            } else if (renderTargetContext->isStencilBufferMultisampled()) {
+                aaType = GrAAType::kMixedSamples;
+            }
+        }
+        GrPipelineBuilder pipelineBuilder(grPaint, aaType);
         pipelineBuilder.setUserStencil(&kCoverPass);
 
         renderTargetContext->addDrawOp(pipelineBuilder, clip, batch.get());
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.h b/src/gpu/text/GrStencilAndCoverTextContext.h
index f4773ff..1ba113b 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.h
+++ b/src/gpu/text/GrStencilAndCoverTextContext.h
@@ -88,7 +88,7 @@
 
         size_t computeSizeInCache() const;
 
-        bool isAntiAlias() const { return fFont.isAntiAlias(); }
+        GrAA isAntiAlias() const { return fFont.isAntiAlias() ? GrAA::kYes : GrAA::kNo; }
 
     private:
         typedef GrDrawPathRangeBatch::InstanceData InstanceData;
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index ffd3ae0..cc11f6d 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -277,7 +277,7 @@
 
     const SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
 
-    renderTargetContext->drawRect(GrNoClip(), paint, SkMatrix::I(), rect);
+    renderTargetContext->drawRect(GrNoClip(), paint, GrAA::kNo, SkMatrix::I(), rect);
 
     if (!renderTargetContext->accessRenderTarget()) {
         return nullptr;