From e0eb3d588ca59cbe70f1094b6f295d1275f929af Mon Sep 17 00:00:00 2001
From: Greg Daniel <egdaniel@google.com>
Date: Wed, 22 Jul 2026 10:51:38 -0400
Subject: [PATCH] [ganesh] Fully clear initial stencil bits when stencil clear
 is a draw

There is a driver bug where clearing stencil requires a manual draw
(performStencilClearsAsDraws). Previously, we called
internalStencilClear() which only zeroed the stencil clip bit
(fWriteMask == clipBit). However, the initial stencil clear must also
zero the user bits. Otherwise, stencil-then-cover path renderers might
read undefined stencil contents on their first use.

This change records a full-surface draw that zeroes both clip and user
bits when clearing as draw.

Bug: https://issues.chromium.org/issues/536166543

Change-Id: Ibedb70474a5aeabe8e8c9fc84e403faa256dadc1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/1300916
Commit-Queue: Greg Daniel <egdaniel@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
---
 src/gpu/ganesh/SurfaceDrawContext.cpp | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/src/gpu/ganesh/SurfaceDrawContext.cpp b/src/gpu/ganesh/SurfaceDrawContext.cpp
index a8339d276c..c6caae4d25 100644
--- a/src/gpu/ganesh/SurfaceDrawContext.cpp
+++ b/src/gpu/ganesh/SurfaceDrawContext.cpp
@@ -830,7 +830,25 @@ void SurfaceDrawContext::setNeedsStencil() {
         if (this->caps()->performStencilClearsAsDraws()) {
             // There is a driver bug with clearing stencil. We must use an op to manually clear the
             // stencil buffer before the op that required 'setNeedsStencil'.
-            this->internalStencilClear(nullptr, /* inside mask */ false);
+            // NOTE: internalStencilClear() only zeroes the *clip* bit (gZeroStencilClipBit lowers
+            // to fWriteMask == clipBit). The initial clear must also zero the user bits, otherwise
+            // stencil-then-cover path renderers read undefined stencil contents
+            constexpr static GrUserStencilSettings kZeroAllStencilBits(
+                    GrUserStencilSettings::StaticInit<
+                            0x0000,
+                            GrUserStencilTest::kAlways,
+                            0xffff,
+                            GrUserStencilOp::kZeroClipAndUserBits,
+                            GrUserStencilOp::kZeroClipAndUserBits,
+                            0xffff>());
+            GrPaint paint;
+            paint.setXPFactory(GrDisableColorXPFactory::Get());
+            SkRect rtRect =
+                    SkRect::Make(this->asSurfaceProxy()->backingStoreDimensions());
+            this->addDrawOp(nullptr,
+                            FillRectOp::MakeNonAARect(fContext, std::move(paint),
+                                                      SkMatrix::I(), rtRect,
+                                                      &kZeroAllStencilBits));
         } else {
             this->getOpsTask()->setInitialStencilContent(
                     OpsTask::StencilContent::kUserBitsCleared);
-- 
2.43.0

