Make rt bounds dependent on stencil settings for quad optimizations

Before the the consolidation to the internal drawFilledQuad(),
regular draws would use the logical rt bounds to decide if it can be
a fullscreen clear. Stencil rect draws would use the worst case bounds
(needed to pass GrDefaultPathRendererTest).

Initially, the new drawFilledQuad() switched to always using the worst
case bounds to determine fullscreen clears. Since stencil rect draws
used drawFilledQuad(), this was necessary for the path renderer tests to
pass. But this had the side effect of making render targets with approx.
backing storage no longer perform fullscreen clears when a draw would
otherwise cover the logical bounds of the render target.

Normally, this would only be a performance issue, but it also seems to
have exposed a driver bug in the Nexus 5x on Vulkan where the draws
didn't properly fill the backing store. Having attemptQuadOptimization()
choose its rt bounds based on the presence of stencil settings keeps
both tests happy and increases the likelihood of using fullscreen clears.

Change-Id: I6df2c789211f32a4c94bee394d27b7fb4f7293e2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/222278
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Greg Daniel <egdaniel@google.com>
Auto-Submit: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index c579c1c..a7f4bb5 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -537,8 +537,9 @@
 };
 
 GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimization(
-        const GrClip& clip, const SkPMColor4f* constColor, bool allowAAChange,
-        GrAA* aa, GrQuadAAFlags* edgeFlags, GrQuad* deviceQuad, GrQuad* localQuad) {
+        const GrClip& clip, const SkPMColor4f* constColor,
+        const GrUserStencilSettings* stencilSettings, GrAA* aa, GrQuadAAFlags* edgeFlags,
+        GrQuad* deviceQuad, GrQuad* localQuad) {
     // Optimization requirements:
     // 1. kDiscard applies when clip bounds and quad bounds do not intersect
     // 2. kClear applies when constColor and final geom is pixel aligned rect;
@@ -549,10 +550,18 @@
     // 6. kNone always applies
     GrQuadAAFlags newFlags = *edgeFlags;
 
-    // Must use worst case bounds so that stencil buffer updates on approximately sized
-    // render targets don't get corrupted.
-    const SkRect rtRect = SkRect::MakeWH(fRenderTargetProxy->worstCaseWidth(),
-                                         fRenderTargetProxy->worstCaseHeight());
+    SkRect rtRect;
+    if (stencilSettings) {
+        // Must use worst case bounds so that stencil buffer updates on approximately sized render
+        // targets don't get corrupted.
+        rtRect = SkRect::MakeWH(fRenderTargetProxy->worstCaseWidth(),
+                                fRenderTargetProxy->worstCaseHeight());
+    } else {
+        // Use the logical size of the render target, which allows for "fullscreen" clears even if
+        // the render target has an approximate backing fit
+        rtRect = SkRect::MakeWH(this->width(), this->height());
+    }
+
     SkRect drawBounds = deviceQuad->bounds();
     if (constColor) {
         // Don't bother updating local coordinates when the paint will ignore them anyways
@@ -567,7 +576,10 @@
     // Check if clip can be represented as a rounded rect (initialize as if clip fully contained
     // the render target).
     SkRRect clipRRect = SkRRect::MakeRect(rtRect);
-    GrAA clipAA = allowAAChange ? GrAA::kNo : *aa;
+    // We initialize clipAA to *aa when there are stencil settings so that we don't artificially
+    // encounter mixed-aa edges (not allowed for stencil), but we want to start as non-AA for
+    // regular draws so that if we fully cover the render target, that can stop being anti-aliased.
+    GrAA clipAA = stencilSettings ? *aa : GrAA::kNo;
     bool axisAlignedClip = true;
     if (!clip.quickContains(rtRect)) {
         if (!clip.isRRect(rtRect, &clipRRect, &clipAA)) {
@@ -577,7 +589,7 @@
 
     // If the clip rrect is valid (i.e. axis-aligned), we can potentially combine it with the
     // draw geometry so that no clip is needed when drawing.
-    if (axisAlignedClip && (allowAAChange || clipAA == *aa)) {
+    if (axisAlignedClip && (!stencilSettings || clipAA == *aa)) {
         // Tighten clip bounds (if clipRRect.isRect() is true, clipBounds now holds the intersection
         // of the render target and the clip rect)
         SkRect clipBounds = rtRect;
@@ -686,11 +698,8 @@
 
     GrQuad croppedDeviceQuad = deviceQuad;
     GrQuad croppedLocalQuad = localQuad;
-    // Only allow AA settings to change if there are no stencil settings. If they were allowed to
-    // change at this stage, it would bypass higher-level decisions about stencil MSAA.
-    QuadOptimization opt = this->attemptQuadOptimization(clip, constColor, /* allowAAChange */ !ss,
-                                                         &aa, &edgeFlags, &croppedDeviceQuad,
-                                                         &croppedLocalQuad);
+    QuadOptimization opt = this->attemptQuadOptimization(clip, constColor, ss, &aa, &edgeFlags,
+                                                         &croppedDeviceQuad, &croppedLocalQuad);
     if (opt >= QuadOptimization::kClipApplied) {
         // These optimizations require caller to add an op themselves
         const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled()
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index cc46660..6dd958f 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -548,11 +548,11 @@
     // The non-const pointers should be the original draw request on input, and will be updated as
     // appropriate depending on the returned optimization level.
     //
-    // If 'allowAAChange' is true, 'aa' and 'edgeFlags' may be updated to incorporate the AA of the
-    // clip. When it is false, only optimizations that will not change the AA state will be applied.
+    // 'stencilSettings' are provided merely for decision making purposes; When non-null,
+    // optimization strategies that submit special ops are avoided.
     QuadOptimization attemptQuadOptimization(const GrClip& clip,
                                              const SkPMColor4f* constColor,
-                                             bool allowAAChange,
+                                             const GrUserStencilSettings* stencilSettings,
                                              GrAA* aa,
                                              GrQuadAAFlags* edgeFlags,
                                              GrQuad* deviceQuad,