Add a "conservative raster" flag for GrFillRectOp

Adds the ability to fill a rect with conservative raster enabled, and
fixes a bug in the gpu tessellation atlas where there were artifacts
from mixed samples.

Change-Id: Ic0b4f2059129ac238fdcb08d43896fc2b9e50211
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/269989
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index d522621..d63b312 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -21,7 +21,6 @@
 #include "src/gpu/glsl/GrGLSLVarying.h"
 #include "src/gpu/ops/GrMeshDrawOp.h"
 #include "src/gpu/ops/GrQuadPerEdgeAA.h"
-#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
 
 namespace {
 
@@ -65,20 +64,21 @@
                                           GrPaint&& paint,
                                           GrAAType aaType,
                                           DrawQuad* quad,
-                                          const GrUserStencilSettings* stencilSettings) {
+                                          const GrUserStencilSettings* stencilSettings,
+                                          Helper::InputFlags inputFlags) {
         // Clean up deviations between aaType and edgeAA
         GrQuadUtils::ResolveAAType(aaType, quad->fEdgeFlags, quad->fDevice,
                                    &aaType, &quad->fEdgeFlags);
         return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, quad,
-                                                 stencilSettings);
+                                                 stencilSettings, inputFlags);
     }
 
     // aaType is passed to Helper in the initializer list, so incongruities between aaType and
     // edgeFlags must be resolved prior to calling this constructor.
     FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
-               DrawQuad* quad, const GrUserStencilSettings* stencil)
+               DrawQuad* quad, const GrUserStencilSettings* stencil, Helper::InputFlags inputFlags)
             : INHERITED(ClassID())
-            , fHelper(args, aaType, stencil)
+            , fHelper(args, aaType, stencil, inputFlags)
             , fQuads(1, !fHelper.isTrivial()) {
         // Set bounds before clipping so we don't have to worry about unioning the bounds of
         // the two potential quads (GrQuad::bounds() is perspective-safe).
@@ -425,8 +425,10 @@
                                              GrPaint&& paint,
                                              GrAAType aaType,
                                              DrawQuad* quad,
-                                             const GrUserStencilSettings* stencil) {
-    return FillRectOp::Make(context, std::move(paint), aaType, std::move(quad), stencil);
+                                             const GrUserStencilSettings* stencil,
+                                             InputFlags inputFlags) {
+    return FillRectOp::Make(context, std::move(paint), aaType, std::move(quad), stencil,
+                            inputFlags);
 }
 
 std::unique_ptr<GrDrawOp> GrFillRectOp::MakeNonAARect(GrRecordingContext* context,
@@ -435,7 +437,8 @@
                                                       const SkRect& rect,
                                                       const GrUserStencilSettings* stencil) {
     DrawQuad quad{GrQuad::MakeFromRect(rect, view), GrQuad(rect), GrQuadAAFlags::kNone};
-    return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, &quad, stencil);
+    return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, &quad, stencil,
+                            InputFlags::kNone);
 }
 
 std::unique_ptr<GrDrawOp> GrFillRectOp::MakeOp(GrRecordingContext* context,
@@ -454,7 +457,7 @@
                   quads[0].fAAFlags};
     paint.setColor4f(quads[0].fColor);
     std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
-                                                    &quad, stencilSettings);
+                                                    &quad, stencilSettings, InputFlags::kNone);
     FillRectOp* fillRects = op->cast<FillRectOp>();
 
     *numConsumed = 1;
diff --git a/src/gpu/ops/GrFillRectOp.h b/src/gpu/ops/GrFillRectOp.h
index e44dae52..947ee7c 100644
--- a/src/gpu/ops/GrFillRectOp.h
+++ b/src/gpu/ops/GrFillRectOp.h
@@ -10,6 +10,7 @@
 
 #include "include/private/GrTypesPriv.h"
 #include "src/gpu/GrRenderTargetContext.h"
+#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
 
 class GrDrawOp;
 class GrPaint;
@@ -27,12 +28,14 @@
  */
 class GrFillRectOp {
 public:
+    using InputFlags = GrSimpleMeshDrawOpHelper::InputFlags;
 
     static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
                                           GrPaint&& paint,
                                           GrAAType aaType,
                                           DrawQuad* quad,
-                                          const GrUserStencilSettings* stencil = nullptr);
+                                          const GrUserStencilSettings* stencil = nullptr,
+                                          InputFlags = InputFlags::kNone);
 
     // Utility function to create a non-AA rect transformed by view. This is used commonly enough
     // in testing and GMs that manage ops without going through GrRTC that it's worth the
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
index 8929af6..acdb16c 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -42,6 +42,7 @@
     enum class InputFlags : uint8_t {
         kNone = 0,
         kSnapVerticesToPixelCenters = (uint8_t)GrPipeline::InputFlags::kSnapVerticesToPixelCenters,
+        kConservativeRaster = (uint8_t)GrPipeline::InputFlags::kConservativeRaster,
     };
     GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(InputFlags);
 
diff --git a/src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp b/src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp
index 3e911b3..1f4c9fd 100644
--- a/src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp
+++ b/src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp
@@ -12,8 +12,9 @@
 #include "src/gpu/GrMemoryPool.h"
 #include "src/gpu/GrRecordingContextPriv.h"
 #include "src/gpu/GrRenderTargetContext.h"
-#include "src/gpu/GrRenderTargetContextPriv.h"
+#include "src/gpu/GrSurfaceContextPriv.h"
 #include "src/gpu/geometry/GrShape.h"
+#include "src/gpu/ops/GrFillRectOp.h"
 #include "src/gpu/tessellate/GrDrawAtlasPathOp.h"
 #include "src/gpu/tessellate/GrTessellatePathOp.h"
 
@@ -173,18 +174,39 @@
         }
     }
 
-    // The next draw will be the final op in the renderTargetContext. So if Ganesh is planning
-    // to discard the stencil values anyway, then we might not actually need to reset the
-    // stencil values back to zero.
-    bool mustResetStencil = !onFlushRP->caps()->discardStencilValuesAfterRenderPass() ||
-                            rtc->numSamples() <= 1;  // Need a stencil reset for mixed samples.
+    // Finally, draw a fullscreen rect to convert our stencilled paths into alpha coverage masks.
+    auto fillRectFlags = GrFillRectOp::InputFlags::kNone;
 
-    // Draw a fullscreen rect to convert our stencilled paths into alpha coverage masks.
+    // This will be the final op in the renderTargetContext. So if Ganesh is planning to discard the
+    // stencil values anyway, then we might not actually need to reset the stencil values back to 0.
+    bool mustResetStencil = !onFlushRP->caps()->discardStencilValuesAfterRenderPass();
+
+    if (rtc->numSamples() <= 1) {
+        // We are mixed sampled. We need to enable conservative raster and ensure stencil values get
+        // reset in order to avoid artifacts along the diagonal of the atlas.
+        fillRectFlags |= GrFillRectOp::InputFlags::kConservativeRaster;
+        mustResetStencil = true;
+    }
+
+    SkRect coverRect = SkRect::MakeIWH(fAtlas.drawBounds().width(), fAtlas.drawBounds().height());
+    const GrUserStencilSettings* stencil;
+    if (mustResetStencil) {
+        // Outset the cover rect in case there are T-junctions in the path bounds.
+        coverRect.outset(1, 1);
+        stencil = &kTestAndResetStencil;
+    } else {
+        stencil = &kTestStencil;
+    }
+
+    GrQuad coverQuad(coverRect);
+    DrawQuad drawQuad{coverQuad, coverQuad, GrQuadAAFlags::kAll};
+
     GrPaint paint;
     paint.setColor4f(SK_PMColor4fWHITE);
-    SkRect drawRect = SkRect::MakeIWH(fAtlas.drawBounds().width(), fAtlas.drawBounds().height());
-    rtc->priv().stencilRect(GrNoClip(), (mustResetStencil) ? &kTestAndResetStencil : &kTestStencil,
-                            std::move(paint), GrAA::kYes, SkMatrix::I(), drawRect, nullptr);
+
+    auto coverOp = GrFillRectOp::Make(rtc->surfPriv().getContext(), std::move(paint),
+                                      GrAAType::kMSAA, &drawQuad, stencil, fillRectFlags);
+    rtc->addDrawOp(GrNoClip(), std::move(coverOp));
 
     if (rtc->asSurfaceProxy()->requiresManualMSAAResolve()) {
         onFlushRP->addTextureResolveTask(sk_ref_sp(rtc->asTextureProxy()),
diff --git a/src/gpu/tessellate/GrTessellatePathOp.cpp b/src/gpu/tessellate/GrTessellatePathOp.cpp
index 53e8382..db7a50f 100644
--- a/src/gpu/tessellate/GrTessellatePathOp.cpp
+++ b/src/gpu/tessellate/GrTessellatePathOp.cpp
@@ -84,7 +84,6 @@
     }
 
     // Fastest CPU approach: emit one cubic wedge per verb, fanning out from the center.
-
     if ((fPathVertexCount = GrPathParser::EmitCenterWedgePatches(fPath, &pathVertexAllocator))) {
         fStencilPathShader = state->allocator()->make<GrStencilWedgeShader>(fViewMatrix);
     }