[Impeller] Add StC color source/clip behavior + constexpr flag for enabling StC. (#50817)

Included in this PR is:
- Behavior for clips/restores when StC is enabled.
- Behavior for color source drawing when StC is enabled.
- New filled path tessellator behavior.
- A constexpr flag for enabling StC.

This patch shouldn't actually change any behavior when StC is off.
diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc
index d65d527..1c8c963 100644
--- a/impeller/aiks/canvas.cc
+++ b/impeller/aiks/canvas.cc
@@ -219,8 +219,10 @@
   }
 
   transform_stack_.pop_back();
-  if (num_clips > 0) {
-    RestoreClip();
+  if constexpr (!ContentContext::kEnableStencilThenCover) {
+    if (num_clips > 0) {
+      RestoreClip();
+    }
   }
 
   return true;
@@ -597,7 +599,6 @@
   entity.SetContents(std::make_shared<ClipRestoreContents>());
   entity.SetClipDepth(GetClipDepth());
 
-  // TODO(bdero): To be removed when swapping the clip strategy.
   AddEntityToCurrentPass(std::move(entity));
 }
 
diff --git a/impeller/entity/contents/clip_contents.cc b/impeller/entity/contents/clip_contents.cc
index 22b81e5..b85beac 100644
--- a/impeller/entity/contents/clip_contents.cc
+++ b/impeller/entity/contents/clip_contents.cc
@@ -73,9 +73,97 @@
 
 void ClipContents::SetInheritedOpacity(Scalar opacity) {}
 
-bool ClipContents::Render(const ContentContext& renderer,
-                          const Entity& entity,
-                          RenderPass& pass) const {
+bool ClipContents::RenderDepthClip(const ContentContext& renderer,
+                                   const Entity& entity,
+                                   RenderPass& pass,
+                                   Entity::ClipOperation clip_op,
+                                   const Geometry& geometry) const {
+  using VS = ClipPipeline::VertexShader;
+
+  VS::FrameInfo info;
+  info.depth = entity.GetShaderClipDepth();
+
+  auto geometry_result = geometry.GetPositionBuffer(renderer, entity, pass);
+  auto options = OptionsFromPass(pass);
+  options.blend_mode = BlendMode::kDestination;
+
+  pass.SetStencilReference(0);
+
+  /// Stencil preparation draw.
+
+  options.depth_write_enabled = false;
+  options.primitive_type = geometry_result.type;
+  pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
+  switch (geometry_result.mode) {
+    case GeometryResult::Mode::kNonZero:
+      pass.SetCommandLabel("Clip stencil preparation (NonZero)");
+      options.stencil_mode =
+          ContentContextOptions::StencilMode::kStencilNonZeroFill;
+      break;
+    case GeometryResult::Mode::kEvenOdd:
+      pass.SetCommandLabel("Clip stencil preparation (EvenOdd)");
+      options.stencil_mode =
+          ContentContextOptions::StencilMode::kStencilEvenOddFill;
+      break;
+    case GeometryResult::Mode::kNormal:
+    case GeometryResult::Mode::kPreventOverdraw:
+      pass.SetCommandLabel("Clip stencil preparation (Increment)");
+      options.stencil_mode =
+          ContentContextOptions::StencilMode::kLegacyClipIncrement;
+      break;
+  }
+  pass.SetPipeline(renderer.GetClipPipeline(options));
+
+  info.mvp = geometry_result.transform;
+  VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
+
+  if (!pass.Draw().ok()) {
+    return false;
+  }
+
+  /// Write depth.
+
+  options.depth_write_enabled = true;
+  options.primitive_type = PrimitiveType::kTriangleStrip;
+  Rect cover_area;
+  switch (clip_op) {
+    case Entity::ClipOperation::kIntersect:
+      pass.SetCommandLabel("Intersect Clip");
+      options.stencil_mode =
+          ContentContextOptions::StencilMode::kCoverCompareInverted;
+      cover_area = Rect::MakeSize(pass.GetRenderTargetSize());
+      break;
+    case Entity::ClipOperation::kDifference:
+      pass.SetCommandLabel("Difference Clip");
+      options.stencil_mode = ContentContextOptions::StencilMode::kCoverCompare;
+      std::optional<Rect> maybe_cover_area =
+          geometry.GetCoverage(entity.GetTransform());
+      if (!maybe_cover_area.has_value()) {
+        return true;
+      }
+      cover_area = maybe_cover_area.value();
+      break;
+  }
+  auto points = cover_area.GetPoints();
+  auto vertices =
+      VertexBufferBuilder<VS::PerVertexData>{}
+          .AddVertices({{points[0]}, {points[1]}, {points[2]}, {points[3]}})
+          .CreateVertexBuffer(renderer.GetTransientsBuffer());
+  pass.SetVertexBuffer(std::move(vertices));
+
+  pass.SetPipeline(renderer.GetClipPipeline(options));
+
+  info.mvp = pass.GetOrthographicTransform();
+  VS::BindFrameInfo(pass, renderer.GetTransientsBuffer().EmplaceUniform(info));
+
+  return pass.Draw().ok();
+}
+
+bool ClipContents::RenderStencilClip(const ContentContext& renderer,
+                                     const Entity& entity,
+                                     RenderPass& pass,
+                                     Entity::ClipOperation clip_op,
+                                     const Geometry& geometry) const {
   using VS = ClipPipeline::VertexShader;
 
   VS::FrameInfo info;
@@ -85,7 +173,7 @@
   options.blend_mode = BlendMode::kDestination;
   pass.SetStencilReference(entity.GetClipDepth());
 
-  if (clip_op_ == Entity::ClipOperation::kDifference) {
+  if (clip_op == Entity::ClipOperation::kDifference) {
     {
       pass.SetCommandLabel("Difference Clip (Increment)");
 
@@ -123,7 +211,7 @@
         ContentContextOptions::StencilMode::kLegacyClipIncrement;
   }
 
-  auto geometry_result = geometry_->GetPositionBuffer(renderer, entity, pass);
+  auto geometry_result = geometry.GetPositionBuffer(renderer, entity, pass);
   options.primitive_type = geometry_result.type;
   pass.SetPipeline(renderer.GetClipPipeline(options));
 
@@ -135,6 +223,19 @@
   return pass.Draw().ok();
 }
 
+bool ClipContents::Render(const ContentContext& renderer,
+                          const Entity& entity,
+                          RenderPass& pass) const {
+  if (!geometry_) {
+    return true;
+  }
+  if constexpr (ContentContext::kEnableStencilThenCover) {
+    return RenderDepthClip(renderer, entity, pass, clip_op_, *geometry_);
+  } else {
+    return RenderStencilClip(renderer, entity, pass, clip_op_, *geometry_);
+  }
+}
+
 /*******************************************************************************
  ******* ClipRestoreContents
  ******************************************************************************/
diff --git a/impeller/entity/contents/clip_contents.h b/impeller/entity/contents/clip_contents.h
index b519cc2..8d7f162 100644
--- a/impeller/entity/contents/clip_contents.h
+++ b/impeller/entity/contents/clip_contents.h
@@ -49,6 +49,17 @@
   void SetInheritedOpacity(Scalar opacity) override;
 
  private:
+  bool RenderDepthClip(const ContentContext& renderer,
+                       const Entity& entity,
+                       RenderPass& pass,
+                       Entity::ClipOperation clip_op,
+                       const Geometry& geometry) const;
+  bool RenderStencilClip(const ContentContext& renderer,
+                         const Entity& entity,
+                         RenderPass& pass,
+                         Entity::ClipOperation clip_op,
+                         const Geometry& geometry) const;
+
   std::shared_ptr<Geometry> geometry_;
   Entity::ClipOperation clip_op_ = Entity::ClipOperation::kIntersect;
 
diff --git a/impeller/entity/contents/color_source_contents.h b/impeller/entity/contents/color_source_contents.h
index d89e522..4951494 100644
--- a/impeller/entity/contents/color_source_contents.h
+++ b/impeller/entity/contents/color_source_contents.h
@@ -5,7 +5,9 @@
 #ifndef FLUTTER_IMPELLER_ENTITY_CONTENTS_COLOR_SOURCE_CONTENTS_H_
 #define FLUTTER_IMPELLER_ENTITY_CONTENTS_COLOR_SOURCE_CONTENTS_H_
 
+#include "fml/logging.h"
 #include "impeller/entity/contents/clip_contents.h"
+#include "impeller/entity/contents/content_context.h"
 #include "impeller/entity/contents/contents.h"
 #include "impeller/entity/geometry/geometry.h"
 #include "impeller/geometry/matrix.h"
@@ -118,6 +120,71 @@
                     typename VertexShaderT::FrameInfo frame_info,
                     const BindFragmentCallback& bind_fragment_callback) const {
     auto options = OptionsFromPassAndEntity(pass, entity);
+    options.primitive_type = geometry_result.type;
+
+    // Take the pre-populated vertex shader uniform struct and set managed
+    // values.
+    frame_info.depth = entity.GetShaderClipDepth();
+    frame_info.mvp = geometry_result.transform;
+
+    pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
+
+    if constexpr (ContentContext::kEnableStencilThenCover) {
+      const bool is_stencil_then_cover =
+          geometry_result.mode == GeometryResult::Mode::kNonZero ||
+          geometry_result.mode == GeometryResult::Mode::kEvenOdd;
+      if (is_stencil_then_cover) {
+        pass.SetStencilReference(0);
+
+        /// Stencil preparation draw.
+
+        options.blend_mode = BlendMode::kDestination;
+        switch (geometry_result.mode) {
+          case GeometryResult::Mode::kNonZero:
+            pass.SetCommandLabel("Stencil preparation (NonZero)");
+            options.stencil_mode =
+                ContentContextOptions::StencilMode::kStencilNonZeroFill;
+            break;
+          case GeometryResult::Mode::kEvenOdd:
+            pass.SetCommandLabel("Stencil preparation (EvenOdd)");
+            options.stencil_mode =
+                ContentContextOptions::StencilMode::kStencilEvenOddFill;
+            break;
+          default:
+            FML_UNREACHABLE();
+        }
+        pass.SetPipeline(renderer.GetClipPipeline(options));
+        ClipPipeline::VertexShader::FrameInfo clip_frame_info;
+        clip_frame_info.depth = entity.GetShaderClipDepth();
+        clip_frame_info.mvp = geometry_result.transform;
+        ClipPipeline::VertexShader::BindFrameInfo(
+            pass,
+            renderer.GetTransientsBuffer().EmplaceUniform(clip_frame_info));
+
+        if (!pass.Draw().ok()) {
+          return false;
+        }
+
+        /// Cover draw.
+
+        options.stencil_mode =
+            ContentContextOptions::StencilMode::kCoverCompare;
+        std::optional<Rect> maybe_cover_area =
+            GetGeometry()->GetCoverage(entity.GetTransform());
+        if (!maybe_cover_area.has_value()) {
+          return true;
+        }
+        auto points = maybe_cover_area.value().GetPoints();
+        auto vertices =
+            VertexBufferBuilder<typename VertexShaderT::PerVertexData>{}
+                .AddVertices(
+                    {{points[0]}, {points[1]}, {points[2]}, {points[3]}})
+                .CreateVertexBuffer(renderer.GetTransientsBuffer());
+        pass.SetVertexBuffer(std::move(vertices));
+
+        frame_info.mvp = pass.GetOrthographicTransform();
+      }
+    }
 
     // If overdraw prevention is enabled (like when drawing stroke paths), we
     // increment the stencil buffer as we draw, preventing overlapping fragments
@@ -127,14 +194,11 @@
       options.stencil_mode =
           ContentContextOptions::StencilMode::kLegacyClipIncrement;
     }
-    options.primitive_type = geometry_result.type;
-    pass.SetVertexBuffer(std::move(geometry_result.vertex_buffer));
-    pass.SetStencilReference(entity.GetClipDepth());
-
-    // Take the pre-populated vertex shader uniform struct and set managed
-    // values.
-    frame_info.depth = entity.GetShaderClipDepth();
-    frame_info.mvp = geometry_result.transform;
+    if constexpr (ContentContext::kEnableStencilThenCover) {
+      pass.SetStencilReference(0);
+    } else {
+      pass.SetStencilReference(entity.GetClipDepth());
+    }
 
     VertexShaderT::BindFrameInfo(
         pass, renderer.GetTransientsBuffer().EmplaceUniform(frame_info));
@@ -159,7 +223,13 @@
     if (geometry_result.mode == GeometryResult::Mode::kPreventOverdraw) {
       auto restore = ClipRestoreContents();
       restore.SetRestoreCoverage(GetCoverage(entity));
-      return restore.Render(renderer, entity, pass);
+      if constexpr (ContentContext::kEnableStencilThenCover) {
+        Entity restore_entity = entity.Clone();
+        restore_entity.SetClipDepth(0);
+        return restore.Render(renderer, restore_entity, pass);
+      } else {
+        return restore.Render(renderer, entity, pass);
+      }
     }
     return true;
   }
diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc
index 05397d3..270e817 100644
--- a/impeller/entity/contents/content_context.cc
+++ b/impeller/entity/contents/content_context.cc
@@ -164,28 +164,32 @@
         front_stencil.depth_stencil_pass = StencilOperation::kKeep;
         desc.SetStencilAttachmentDescriptors(front_stencil);
         break;
-      case StencilMode::kSetToRef:
-        front_stencil.stencil_compare = CompareFunction::kEqual;
-        front_stencil.depth_stencil_pass = StencilOperation::kKeep;
-        front_stencil.stencil_failure = StencilOperation::kSetToReferenceValue;
-        desc.SetStencilAttachmentDescriptors(front_stencil);
-        break;
-      case StencilMode::kNonZeroWrite:
+      case StencilMode::kStencilNonZeroFill:
+        // The stencil ref should be 0 on commands that use this mode.
         front_stencil.stencil_compare = CompareFunction::kAlways;
         front_stencil.depth_stencil_pass = StencilOperation::kIncrementWrap;
         back_stencil.stencil_compare = CompareFunction::kAlways;
         back_stencil.depth_stencil_pass = StencilOperation::kDecrementWrap;
         desc.SetStencilAttachmentDescriptors(front_stencil, back_stencil);
         break;
-      case StencilMode::kEvenOddWrite:
+      case StencilMode::kStencilEvenOddFill:
+        // The stencil ref should be 0 on commands that use this mode.
         front_stencil.stencil_compare = CompareFunction::kEqual;
         front_stencil.depth_stencil_pass = StencilOperation::kIncrementWrap;
         front_stencil.stencil_failure = StencilOperation::kDecrementWrap;
         desc.SetStencilAttachmentDescriptors(front_stencil);
         break;
       case StencilMode::kCoverCompare:
+        // The stencil ref should be 0 on commands that use this mode.
         front_stencil.stencil_compare = CompareFunction::kNotEqual;
-        front_stencil.depth_stencil_pass = StencilOperation::kKeep;
+        front_stencil.depth_stencil_pass =
+            StencilOperation::kSetToReferenceValue;
+        desc.SetStencilAttachmentDescriptors(front_stencil);
+        break;
+      case StencilMode::kCoverCompareInverted:
+        // The stencil ref should be 0 on commands that use this mode.
+        front_stencil.stencil_compare = CompareFunction::kEqual;
+        front_stencil.stencil_failure = StencilOperation::kSetToReferenceValue;
         desc.SetStencilAttachmentDescriptors(front_stencil);
         break;
       case StencilMode::kLegacyClipRestore:
diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h
index 4b813e9..67e8407 100644
--- a/impeller/entity/contents/content_context.h
+++ b/impeller/entity/contents/content_context.h
@@ -287,21 +287,34 @@
 /// but they shouldn't require e.g. 10s of thousands.
 struct ContentContextOptions {
   enum class StencilMode : uint8_t {
-    // Operations used for stencil-then-cover
-
     /// Turn the stencil test off. Used when drawing without stencil-then-cover.
     kIgnore,
-    /// Overwrite the stencil content to the ref value. Used for resetting the
-    /// stencil buffer after a stencil-then-cover operation.
-    kSetToRef,
-    /// Draw the stencil for the nonzero fill path rule.
-    kNonZeroWrite,
-    /// Draw the stencil for the evenoff fill path rule.
-    kEvenOddWrite,
+
+    // Operations used for stencil-then-cover
+
+    /// Draw the stencil for the NonZero fill path rule.
+    ///
+    /// The stencil ref should always be 0 on commands using this mode.
+    kStencilNonZeroFill,
+    /// Draw the stencil for the EvenOdd fill path rule.
+    ///
+    /// The stencil ref should always be 0 on commands using this mode.
+    kStencilEvenOddFill,
     /// Used for draw calls which fill in the stenciled area. Intended to be
-    /// used after `kNonZeroWrite` or `kEvenOddWrite` is used to set up the
-    /// stencil buffer.
+    /// used after `kStencilNonZeroFill` or `kStencilEvenOddFill` is used to set
+    /// up the stencil buffer. Also cleans up the stencil buffer by resetting
+    /// everything to zero.
+    ///
+    /// The stencil ref should always be 0 on commands using this mode.
     kCoverCompare,
+    /// The opposite of `kCoverCompare`. Used for draw calls which fill in the
+    /// non-stenciled area (intersection clips). Intended to be used after
+    /// `kStencilNonZeroFill` or `kStencilEvenOddFill` is used to set up the
+    /// stencil buffer. Also cleans up the stencil buffer by resetting
+    /// everything to zero.
+    ///
+    /// The stencil ref should always be 0 on commands using this mode.
+    kCoverCompareInverted,
 
     // Operations to control the legacy clip implementation, which forms a
     // heightmap on the stencil buffer.
@@ -387,6 +400,16 @@
 
   bool IsValid() const;
 
+  /// This setting does two things:
+  /// 1. Enables clipping with the depth buffer, freeing up the stencil buffer.
+  ///    See also: https://github.com/flutter/flutter/issues/138460
+  /// 2. Switches the generic tessellation fallback to use stencil-then-cover.
+  ///    See also: https://github.com/flutter/flutter/issues/123671
+  ///
+  // TODO(bdero): Remove this setting once StC is fully de-risked
+  //              https://github.com/flutter/flutter/issues/123671
+  static constexpr bool kEnableStencilThenCover = false;
+
 #if IMPELLER_ENABLE_3D
   std::shared_ptr<scene::SceneContext> GetSceneContext() const;
 #endif  // IMPELLER_ENABLE_3D
diff --git a/impeller/entity/contents/contents.cc b/impeller/entity/contents/contents.cc
index 681c160..b71ceca 100644
--- a/impeller/entity/contents/contents.cc
+++ b/impeller/entity/contents/contents.cc
@@ -27,6 +27,10 @@
   FML_DCHECK(pass.HasDepthAttachment() == pass.HasStencilAttachment());
 
   opts.has_depth_stencil_attachments = has_depth_stencil_attachments;
+  if constexpr (ContentContext::kEnableStencilThenCover) {
+    opts.depth_compare = CompareFunction::kGreater;
+    opts.stencil_mode = ContentContextOptions::StencilMode::kIgnore;
+  }
   return opts;
 }
 
diff --git a/impeller/entity/entity.cc b/impeller/entity/entity.cc
index e1f26f6..472f4b5 100644
--- a/impeller/entity/entity.cc
+++ b/impeller/entity/entity.cc
@@ -110,7 +110,7 @@
 static const Scalar kDepthEpsilon = 1.0f / std::pow(2, 18);
 
 float Entity::GetShaderClipDepth() const {
-  return new_clip_depth_ * kDepthEpsilon;
+  return std::clamp(new_clip_depth_ * kDepthEpsilon, 0.0f, 1.0f);
 }
 
 void Entity::IncrementStencilDepth(uint32_t increment) {
diff --git a/impeller/entity/entity_pass.cc b/impeller/entity/entity_pass.cc
index 608545b..76a5d31 100644
--- a/impeller/entity/entity_pass.cc
+++ b/impeller/entity/entity_pass.cc
@@ -4,6 +4,7 @@
 
 #include "impeller/entity/entity_pass.h"
 
+#include <limits>
 #include <memory>
 #include <utility>
 #include <variant>
@@ -765,6 +766,7 @@
     Entity msaa_backdrop_entity;
     msaa_backdrop_entity.SetContents(std::move(msaa_backdrop_contents));
     msaa_backdrop_entity.SetBlendMode(BlendMode::kSource);
+    msaa_backdrop_entity.SetNewClipDepth(std::numeric_limits<uint32_t>::max());
     if (!msaa_backdrop_entity.Render(renderer, *result.pass)) {
       VALIDATION_LOG << "Failed to render MSAA backdrop filter entity.";
       return false;
@@ -923,6 +925,7 @@
     backdrop_entity.SetTransform(
         Matrix::MakeTranslation(Vector3(-local_pass_position)));
     backdrop_entity.SetClipDepth(clip_depth_floor);
+    backdrop_entity.SetNewClipDepth(std::numeric_limits<uint32_t>::max());
 
     RenderElement(backdrop_entity, clip_depth_floor, pass_context, pass_depth,
                   renderer, clip_coverage_stack, global_pass_position);
diff --git a/impeller/entity/entity_unittests.cc b/impeller/entity/entity_unittests.cc
index e5a6adc..07b065d 100644
--- a/impeller/entity/entity_unittests.cc
+++ b/impeller/entity/entity_unittests.cc
@@ -2758,6 +2758,40 @@
 }
 #endif
 
+TEST_P(EntityTest, FillPathGeometryGetPositionBufferReturnsExpectedMode) {
+  RenderTarget target;
+  testing::MockRenderPass mock_pass(GetContext(), target);
+
+  auto get_result = [this, &mock_pass](const Path& path) {
+    auto geometry = Geometry::MakeFillPath(
+        path, /* inner rect */ Rect::MakeLTRB(0, 0, 100, 100));
+    return geometry->GetPositionBuffer(*GetContentContext(), {}, mock_pass);
+  };
+
+  // Convex path
+  {
+    GeometryResult result =
+        get_result(PathBuilder{}
+                       .AddRect(Rect::MakeLTRB(0, 0, 100, 100))
+                       .SetConvexity(Convexity::kConvex)
+                       .TakePath());
+    EXPECT_EQ(result.mode, GeometryResult::Mode::kNormal);
+  }
+
+  // Concave path
+  {
+    Path path = PathBuilder{}
+                    .MoveTo({0, 0})
+                    .LineTo({100, 0})
+                    .LineTo({100, 100})
+                    .LineTo({50, 50})
+                    .Close()
+                    .TakePath();
+    GeometryResult result = get_result(path);
+    EXPECT_EQ(result.mode, GeometryResult::Mode::kNormal);
+  }
+}
+
 }  // namespace testing
 }  // namespace impeller
 
diff --git a/impeller/entity/geometry/fill_path_geometry.cc b/impeller/entity/geometry/fill_path_geometry.cc
index 5cd721a..959d858 100644
--- a/impeller/entity/geometry/fill_path_geometry.cc
+++ b/impeller/entity/geometry/fill_path_geometry.cc
@@ -3,7 +3,11 @@
 // found in the LICENSE file.
 
 #include "impeller/entity/geometry/fill_path_geometry.h"
+
+#include "fml/logging.h"
 #include "impeller/core/formats.h"
+#include "impeller/entity/contents/content_context.h"
+#include "impeller/entity/geometry/geometry.h"
 
 namespace impeller {
 
@@ -11,6 +15,21 @@
                                    std::optional<Rect> inner_rect)
     : path_(path), inner_rect_(inner_rect) {}
 
+static GeometryResult::Mode GetGeometryMode(const Path& path) {
+  if (!ContentContext::kEnableStencilThenCover || path.IsConvex()) {
+    return GeometryResult::Mode::kNormal;
+  }
+
+  switch (path.GetFillType()) {
+    case FillType::kNonZero:
+      return GeometryResult::Mode::kNonZero;
+    case FillType::kOdd:
+      return GeometryResult::Mode::kEvenOdd;
+  }
+
+  FML_UNREACHABLE();
+}
+
 GeometryResult FillPathGeometry::GetPositionBuffer(
     const ContentContext& renderer,
     const Entity& entity,
@@ -18,49 +37,51 @@
   auto& host_buffer = renderer.GetTransientsBuffer();
   VertexBuffer vertex_buffer;
 
-  if (path_.GetFillType() == FillType::kNonZero &&  //
-      path_.IsConvex()) {
-    auto points = renderer.GetTessellator()->TessellateConvex(
-        path_, entity.GetTransform().GetMaxBasisLength());
-
-    vertex_buffer.vertex_buffer = host_buffer.Emplace(
-        points.data(), points.size() * sizeof(Point), alignof(Point));
-    vertex_buffer.index_buffer = {}, vertex_buffer.vertex_count = points.size();
-    vertex_buffer.index_type = IndexType::kNone;
-
-    return GeometryResult{
-        .type = PrimitiveType::kTriangleStrip,
-        .vertex_buffer = vertex_buffer,
-        .transform = pass.GetOrthographicTransform() * entity.GetTransform(),
-    };
+  if constexpr (!ContentContext::kEnableStencilThenCover) {
+    if (!path_.IsConvex()) {
+      auto tesselation_result = renderer.GetTessellator()->Tessellate(
+          path_, entity.GetTransform().GetMaxBasisLength(),
+          [&vertex_buffer, &host_buffer](
+              const float* vertices, size_t vertices_count,
+              const uint16_t* indices, size_t indices_count) {
+            vertex_buffer.vertex_buffer = host_buffer.Emplace(
+                vertices, vertices_count * sizeof(float) * 2, alignof(float));
+            if (indices != nullptr) {
+              vertex_buffer.index_buffer = host_buffer.Emplace(
+                  indices, indices_count * sizeof(uint16_t), alignof(uint16_t));
+              vertex_buffer.vertex_count = indices_count;
+              vertex_buffer.index_type = IndexType::k16bit;
+            } else {
+              vertex_buffer.index_buffer = {};
+              vertex_buffer.vertex_count = vertices_count;
+              vertex_buffer.index_type = IndexType::kNone;
+            }
+            return true;
+          });
+      if (tesselation_result != Tessellator::Result::kSuccess) {
+        return {};
+      }
+      return GeometryResult{
+          .type = PrimitiveType::kTriangle,
+          .vertex_buffer = vertex_buffer,
+          .transform = pass.GetOrthographicTransform() * entity.GetTransform(),
+      };
+    }
   }
 
-  auto tesselation_result = renderer.GetTessellator()->Tessellate(
-      path_, entity.GetTransform().GetMaxBasisLength(),
-      [&vertex_buffer, &host_buffer](
-          const float* vertices, size_t vertices_count, const uint16_t* indices,
-          size_t indices_count) {
-        vertex_buffer.vertex_buffer = host_buffer.Emplace(
-            vertices, vertices_count * sizeof(float) * 2, alignof(float));
-        if (indices != nullptr) {
-          vertex_buffer.index_buffer = host_buffer.Emplace(
-              indices, indices_count * sizeof(uint16_t), alignof(uint16_t));
-          vertex_buffer.vertex_count = indices_count;
-          vertex_buffer.index_type = IndexType::k16bit;
-        } else {
-          vertex_buffer.index_buffer = {};
-          vertex_buffer.vertex_count = vertices_count;
-          vertex_buffer.index_type = IndexType::kNone;
-        }
-        return true;
-      });
-  if (tesselation_result != Tessellator::Result::kSuccess) {
-    return {};
-  }
+  auto points = renderer.GetTessellator()->TessellateConvex(
+      path_, entity.GetTransform().GetMaxBasisLength());
+
+  vertex_buffer.vertex_buffer = host_buffer.Emplace(
+      points.data(), points.size() * sizeof(Point), alignof(Point));
+  vertex_buffer.index_buffer = {}, vertex_buffer.vertex_count = points.size();
+  vertex_buffer.index_type = IndexType::kNone;
+
   return GeometryResult{
-      .type = PrimitiveType::kTriangle,
+      .type = PrimitiveType::kTriangleStrip,
       .vertex_buffer = vertex_buffer,
       .transform = pass.GetOrthographicTransform() * entity.GetTransform(),
+      .mode = GetGeometryMode(path_),
   };
 }
 
@@ -76,57 +97,59 @@
   auto uv_transform =
       texture_coverage.GetNormalizingTransform() * effect_transform;
 
-  if (path_.GetFillType() == FillType::kNonZero &&  //
-      path_.IsConvex()) {
-    auto points = renderer.GetTessellator()->TessellateConvex(
-        path_, entity.GetTransform().GetMaxBasisLength());
-
-    VertexBufferBuilder<VS::PerVertexData> vertex_builder;
-    vertex_builder.Reserve(points.size());
-    for (auto i = 0u; i < points.size(); i++) {
-      VS::PerVertexData data;
-      data.position = points[i];
-      data.texture_coords = uv_transform * points[i];
-      vertex_builder.AppendVertex(data);
+  if constexpr (!ContentContext::kEnableStencilThenCover) {
+    if (!path_.IsConvex()) {
+      VertexBufferBuilder<VS::PerVertexData> vertex_builder;
+      auto tesselation_result = renderer.GetTessellator()->Tessellate(
+          path_, entity.GetTransform().GetMaxBasisLength(),
+          [&vertex_builder, &uv_transform](
+              const float* vertices, size_t vertices_count,
+              const uint16_t* indices, size_t indices_count) {
+            for (auto i = 0u; i < vertices_count * 2; i += 2) {
+              VS::PerVertexData data;
+              Point vtx = {vertices[i], vertices[i + 1]};
+              data.position = vtx;
+              data.texture_coords = uv_transform * vtx;
+              vertex_builder.AppendVertex(data);
+            }
+            FML_DCHECK(vertex_builder.GetVertexCount() == vertices_count);
+            if (indices != nullptr) {
+              for (auto i = 0u; i < indices_count; i++) {
+                vertex_builder.AppendIndex(indices[i]);
+              }
+            }
+            return true;
+          });
+      if (tesselation_result != Tessellator::Result::kSuccess) {
+        return {};
+      }
+      return GeometryResult{
+          .type = PrimitiveType::kTriangle,
+          .vertex_buffer =
+              vertex_builder.CreateVertexBuffer(renderer.GetTransientsBuffer()),
+          .transform = pass.GetOrthographicTransform() * entity.GetTransform(),
+      };
     }
-
-    return GeometryResult{
-        .type = PrimitiveType::kTriangleStrip,
-        .vertex_buffer =
-            vertex_builder.CreateVertexBuffer(renderer.GetTransientsBuffer()),
-        .transform = pass.GetOrthographicTransform() * entity.GetTransform(),
-    };
   }
 
+  auto points = renderer.GetTessellator()->TessellateConvex(
+      path_, entity.GetTransform().GetMaxBasisLength());
+
   VertexBufferBuilder<VS::PerVertexData> vertex_builder;
-  auto tesselation_result = renderer.GetTessellator()->Tessellate(
-      path_, entity.GetTransform().GetMaxBasisLength(),
-      [&vertex_builder, &uv_transform](
-          const float* vertices, size_t vertices_count, const uint16_t* indices,
-          size_t indices_count) {
-        for (auto i = 0u; i < vertices_count * 2; i += 2) {
-          VS::PerVertexData data;
-          Point vtx = {vertices[i], vertices[i + 1]};
-          data.position = vtx;
-          data.texture_coords = uv_transform * vtx;
-          vertex_builder.AppendVertex(data);
-        }
-        FML_DCHECK(vertex_builder.GetVertexCount() == vertices_count);
-        if (indices != nullptr) {
-          for (auto i = 0u; i < indices_count; i++) {
-            vertex_builder.AppendIndex(indices[i]);
-          }
-        }
-        return true;
-      });
-  if (tesselation_result != Tessellator::Result::kSuccess) {
-    return {};
+  vertex_builder.Reserve(points.size());
+  for (auto i = 0u; i < points.size(); i++) {
+    VS::PerVertexData data;
+    data.position = points[i];
+    data.texture_coords = uv_transform * points[i];
+    vertex_builder.AppendVertex(data);
   }
+
   return GeometryResult{
-      .type = PrimitiveType::kTriangle,
+      .type = PrimitiveType::kTriangleStrip,
       .vertex_buffer =
           vertex_builder.CreateVertexBuffer(renderer.GetTransientsBuffer()),
       .transform = pass.GetOrthographicTransform() * entity.GetTransform(),
+      .mode = GetGeometryMode(path_),
   };
 }
 
diff --git a/impeller/entity/inline_pass_context.cc b/impeller/entity/inline_pass_context.cc
index d9258ac..7fcaf51 100644
--- a/impeller/entity/inline_pass_context.cc
+++ b/impeller/entity/inline_pass_context.cc
@@ -146,6 +146,18 @@
   color0.store_action =
       is_msaa ? StoreAction::kMultisampleResolve : StoreAction::kStore;
 
+  if (ContentContext::kEnableStencilThenCover) {
+    auto depth = pass_target_.GetRenderTarget().GetDepthAttachment();
+    if (!depth.has_value()) {
+      VALIDATION_LOG << "Depth attachment unexpectedly missing from the "
+                        "EntityPass render target.";
+      return {};
+    }
+    depth->load_action = LoadAction::kClear;
+    depth->store_action = StoreAction::kDontCare;
+    pass_target_.target_.SetDepthAttachment(depth.value());
+  }
+
   auto stencil = pass_target_.GetRenderTarget().GetStencilAttachment();
   if (!stencil.has_value()) {
     VALIDATION_LOG << "Stencil attachment unexpectedly missing from the "