Add an "allPathsVolatile" option for testing

Bug: skia:10419
Change-Id: I4bb2dc515448d8c87329ade90d24bf78ca1d7938
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/319097
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/include/core/SkPath.h b/include/core/SkPath.h
index d826b21..78303c8 100644
--- a/include/core/SkPath.h
+++ b/include/core/SkPath.h
@@ -337,9 +337,11 @@
         GPU surface SkPath draws are affected by volatile for some shadows and concave geometries.
 
         @param isVolatile  true if caller will alter SkPath after drawing
+        @return            reference to SkPath
     */
-    void setIsVolatile(bool isVolatile) {
+    SkPath& setIsVolatile(bool isVolatile) {
         fIsVolatile = isVolatile;
+        return *this;
     }
 
     /** Tests if line between SkPoint pair is degenerate.
diff --git a/include/gpu/GrContextOptions.h b/include/gpu/GrContextOptions.h
index 55f478d..2372cf1 100644
--- a/include/gpu/GrContextOptions.h
+++ b/include/gpu/GrContextOptions.h
@@ -269,6 +269,11 @@
     int  fMaxTessellationSegmentsOverride = 0;
 
     /**
+     * If true, then all paths are processed as if "setIsVolatile" had been called.
+     */
+    bool fAllPathsVolatile = false;
+
+    /**
      * Render everything in wireframe
      */
     bool fWireframeMode = false;
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index ecbca1c..5555a19 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -247,6 +247,17 @@
 
 #if !defined(SK_DISABLE_NEW_GR_CLIP_STACK)
 
+void SkGpuDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) {
+#if GR_TEST_UTILS
+    if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
+        this->onClipPath(SkPath(path).setIsVolatile(true), op, aa);
+        return;
+    }
+#endif
+    SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
+    fClip.clipPath(this->localToDevice(), path, GrAA(aa), op);
+}
+
 void SkGpuDevice::onClipRegion(const SkRegion& globalRgn, SkClipOp op) {
     SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
 
@@ -641,6 +652,12 @@
 }
 
 void SkGpuDevice::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool pathIsMutable) {
+#if GR_TEST_UTILS
+    if (fContext->priv().options().fAllPathsVolatile && !origSrcPath.isVolatile()) {
+        this->drawPath(SkPath(origSrcPath).setIsVolatile(true), paint, true);
+        return;
+    }
+#endif
     ASSERT_SINGLE_OWNER
     if (!origSrcPath.isInverseFillType() && !paint.getPathEffect()) {
         SkPoint points[2];
@@ -925,7 +942,12 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void SkGpuDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) {
-
+#if GR_TEST_UTILS
+    if (fContext->priv().options().fAllPathsVolatile && !path.isVolatile()) {
+        this->drawShadow(SkPath(path).setIsVolatile(true), rec);
+        return;
+    }
+#endif
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawShadow", fContext.get());
 
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index e06f3ab..09f62fc 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -157,10 +157,7 @@
         SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
         fClip.clipRRect(this->localToDevice(), rrect, GrAA(aa), op);
     }
-    void onClipPath(const SkPath& path, SkClipOp op, bool aa) override {
-        SkASSERT(op == SkClipOp::kIntersect || op == SkClipOp::kDifference);
-        fClip.clipPath(this->localToDevice(), path, GrAA(aa), op);
-    }
+    void onClipPath(const SkPath& path, SkClipOp op, bool aa) override;
     void onClipShader(sk_sp<SkShader> shader) override {
         fClip.clipShader(std::move(shader));
     }
diff --git a/tools/flags/CommonFlags.h b/tools/flags/CommonFlags.h
index 9354a48..c67f75d 100644
--- a/tools/flags/CommonFlags.h
+++ b/tools/flags/CommonFlags.h
@@ -28,6 +28,7 @@
  *  Helper to set GrContextOptions from common GPU flags, including
  *     --gpuThreads
  *     --cachePathMasks
+ *     --allPathsVolatile
  *     --(no)gs
  *     --(no)ts
  *     --maxTessellationSegments
diff --git a/tools/flags/CommonFlagsGpu.cpp b/tools/flags/CommonFlagsGpu.cpp
index e605581..b0537c5 100644
--- a/tools/flags/CommonFlagsGpu.cpp
+++ b/tools/flags/CommonFlagsGpu.cpp
@@ -16,6 +16,8 @@
 
 static DEFINE_bool(cachePathMasks, true,
                    "Allows path mask textures to be cached in GPU configs.");
+static DEFINE_bool(allPathsVolatile, false,
+                   "Causes all GPU paths to be processed as if 'setIsVolatile' had been called.");
 
 static DEFINE_bool(gs, true, "Enables support for geometry shaders (if hw allows).");
 static DEFINE_bool(ts, true, "Enables support for tessellation shaders (if hw allows.).");
@@ -94,6 +96,7 @@
     ctxOptions->fExecutor                            = gGpuExecutor.get();
     ctxOptions->fDisableCoverageCountingPaths        = !FLAGS_cc;
     ctxOptions->fAllowPathMaskCaching                = FLAGS_cachePathMasks;
+    ctxOptions->fAllPathsVolatile                    = FLAGS_allPathsVolatile;
     ctxOptions->fSuppressGeometryShaders             = !FLAGS_gs;
     ctxOptions->fSuppressTessellationShaders         = !FLAGS_ts;
     ctxOptions->fMaxTessellationSegmentsOverride     = FLAGS_maxTessellationSegments;