diff --git a/impeller/entity/contents/checkerboard_contents.cc b/impeller/entity/contents/checkerboard_contents.cc index 80a11e4d0f683..e8d0de77952c5 100644 --- a/impeller/entity/contents/checkerboard_contents.cc +++ b/impeller/entity/contents/checkerboard_contents.cc @@ -25,8 +25,7 @@ bool CheckerboardContents::Render(const ContentContext& renderer, auto options = OptionsFromPass(pass); options.blend_mode = BlendMode::kSourceOver; - options.stencil_compare = CompareFunction::kAlways; // Ignore all clips. - options.stencil_operation = StencilOperation::kKeep; + options.stencil_mode = ContentContextOptions::StencilMode::kIgnore; options.primitive_type = PrimitiveType::kTriangleStrip; VertexBufferBuilder vtx_builder; diff --git a/impeller/entity/contents/clip_contents.cc b/impeller/entity/contents/clip_contents.cc index ea5a61b6eb73d..3d6ea808793b1 100644 --- a/impeller/entity/contents/clip_contents.cc +++ b/impeller/entity/contents/clip_contents.cc @@ -89,8 +89,8 @@ bool ClipContents::Render(const ContentContext& renderer, { pass.SetCommandLabel("Difference Clip (Increment)"); - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; auto points = Rect::MakeSize(pass.GetRenderTargetSize()).GetPoints(); auto vertices = @@ -113,14 +113,14 @@ bool ClipContents::Render(const ContentContext& renderer, pass.SetCommandLabel("Difference Clip (Punch)"); pass.SetStencilReference(entity.GetClipDepth() + 1); - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kDecrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipDecrement; } } else { pass.SetCommandLabel("Intersect Clip"); - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } auto geometry_result = geometry_->GetPositionBuffer(renderer, entity, pass); @@ -179,8 +179,7 @@ bool ClipRestoreContents::Render(const ContentContext& renderer, pass.SetCommandLabel("Restore Clip"); auto options = OptionsFromPass(pass); options.blend_mode = BlendMode::kDestination; - options.stencil_compare = CompareFunction::kLess; - options.stencil_operation = StencilOperation::kSetToReferenceValue; + options.stencil_mode = ContentContextOptions::StencilMode::kLegacyClipRestore; options.primitive_type = PrimitiveType::kTriangleStrip; pass.SetPipeline(renderer.GetClipPipeline(options)); pass.SetStencilReference(entity.GetClipDepth()); diff --git a/impeller/entity/contents/conical_gradient_contents.cc b/impeller/entity/contents/conical_gradient_contents.cc index 55fc5134de743..9bd5e1ee61091 100644 --- a/impeller/entity/contents/conical_gradient_contents.cc +++ b/impeller/entity/contents/conical_gradient_contents.cc @@ -95,8 +95,8 @@ bool ConicalGradientContents::RenderSSBO(const ContentContext& renderer, GetGeometry()->GetPositionBuffer(renderer, entity, pass); auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; @@ -165,8 +165,8 @@ bool ConicalGradientContents::RenderTexture(const ContentContext& renderer, auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; pass.SetPipeline(renderer.GetConicalGradientFillPipeline(options)); diff --git a/impeller/entity/contents/content_context.cc b/impeller/entity/contents/content_context.cc index 035d1e3f84f3b..bde5a604b62ce 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -153,10 +153,61 @@ void ContentContextOptions::ApplyToPipelineDescriptor( "has_depth_stencil_attachments=" << has_depth_stencil_attachments; if (maybe_stencil.has_value()) { - StencilAttachmentDescriptor stencil = maybe_stencil.value(); - stencil.stencil_compare = stencil_compare; - stencil.depth_stencil_pass = stencil_operation; - desc.SetStencilAttachmentDescriptors(stencil); + StencilAttachmentDescriptor front_stencil = maybe_stencil.value(); + StencilAttachmentDescriptor back_stencil = front_stencil; + + switch (stencil_mode) { + case StencilMode::kIgnore: + front_stencil.stencil_compare = CompareFunction::kAlways; + 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: + 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: + 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: + front_stencil.stencil_compare = CompareFunction::kNotEqual; + front_stencil.depth_stencil_pass = StencilOperation::kKeep; + desc.SetStencilAttachmentDescriptors(front_stencil); + break; + case StencilMode::kLegacyClipRestore: + front_stencil.stencil_compare = CompareFunction::kLess; + front_stencil.depth_stencil_pass = + StencilOperation::kSetToReferenceValue; + desc.SetStencilAttachmentDescriptors(front_stencil); + break; + case StencilMode::kLegacyClipIncrement: + front_stencil.stencil_compare = CompareFunction::kEqual; + front_stencil.depth_stencil_pass = StencilOperation::kIncrementClamp; + desc.SetStencilAttachmentDescriptors(front_stencil); + break; + case StencilMode::kLegacyClipDecrement: + front_stencil.stencil_compare = CompareFunction::kEqual; + front_stencil.depth_stencil_pass = StencilOperation::kDecrementClamp; + desc.SetStencilAttachmentDescriptors(front_stencil); + break; + case StencilMode::kLegacyClipCompare: + front_stencil.stencil_compare = CompareFunction::kEqual; + front_stencil.depth_stencil_pass = StencilOperation::kKeep; + desc.SetStencilAttachmentDescriptors(front_stencil); + break; + } } if (maybe_depth.has_value()) { DepthAttachmentDescriptor depth = maybe_depth.value(); diff --git a/impeller/entity/contents/content_context.h b/impeller/entity/contents/content_context.h index acf77ac26e045..64ad969559a75 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -286,11 +286,41 @@ struct PendingCommandBuffers { /// Flutter application may easily require building hundreds of PSOs in total, /// 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, + /// 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. + kCoverCompare, + + // Operations to control the legacy clip implementation, which forms a + // heightmap on the stencil buffer. + + /// Slice the clip heightmap to a new maximum height. + kLegacyClipRestore, + /// Increment the stencil heightmap. + kLegacyClipIncrement, + /// Decrement the stencil heightmap (used for difference clipping only). + kLegacyClipDecrement, + /// Used for applying clips to all non-clip draw calls. + kLegacyClipCompare, + }; + SampleCount sample_count = SampleCount::kCount1; BlendMode blend_mode = BlendMode::kSourceOver; CompareFunction depth_compare = CompareFunction::kAlways; - CompareFunction stencil_compare = CompareFunction::kEqual; - StencilOperation stencil_operation = StencilOperation::kKeep; + StencilMode stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipCompare; PrimitiveType primitive_type = PrimitiveType::kTriangle; PixelFormat color_attachment_pixel_format = PixelFormat::kUnknown; bool has_depth_stencil_attachments = true; @@ -304,8 +334,7 @@ struct ContentContextOptions { static_assert(sizeof(o.blend_mode) == 1); static_assert(sizeof(o.sample_count) == 1); static_assert(sizeof(o.depth_compare) == 1); - static_assert(sizeof(o.stencil_compare) == 1); - static_assert(sizeof(o.stencil_operation) == 1); + static_assert(sizeof(o.stencil_mode) == 1); static_assert(sizeof(o.primitive_type) == 1); static_assert(sizeof(o.color_attachment_pixel_format) == 1); @@ -316,11 +345,10 @@ struct ContentContextOptions { // enums static_cast(o.color_attachment_pixel_format) << 8 | static_cast(o.primitive_type) << 16 | - static_cast(o.stencil_operation) << 24 | - static_cast(o.stencil_compare) << 32 | - static_cast(o.depth_compare) << 40 | - static_cast(o.blend_mode) << 48 | - static_cast(o.sample_count) << 56; + static_cast(o.stencil_mode) << 24 | + static_cast(o.depth_compare) << 32 | + static_cast(o.blend_mode) << 40 | + static_cast(o.sample_count) << 48; } }; @@ -331,8 +359,7 @@ struct ContentContextOptions { lhs.blend_mode == rhs.blend_mode && lhs.depth_write_enabled == rhs.depth_write_enabled && lhs.depth_compare == rhs.depth_compare && - lhs.stencil_compare == rhs.stencil_compare && - lhs.stencil_operation == rhs.stencil_operation && + lhs.stencil_mode == rhs.stencil_mode && lhs.primitive_type == rhs.primitive_type && lhs.color_attachment_pixel_format == rhs.color_attachment_pixel_format && diff --git a/impeller/entity/contents/linear_gradient_contents.cc b/impeller/entity/contents/linear_gradient_contents.cc index 3570c658f7e8b..cb319b327f43a 100644 --- a/impeller/entity/contents/linear_gradient_contents.cc +++ b/impeller/entity/contents/linear_gradient_contents.cc @@ -96,8 +96,8 @@ bool LinearGradientContents::RenderTexture(const ContentContext& renderer, auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; @@ -159,8 +159,8 @@ bool LinearGradientContents::RenderSSBO(const ContentContext& renderer, GetGeometry()->GetPositionBuffer(renderer, entity, pass); auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; diff --git a/impeller/entity/contents/radial_gradient_contents.cc b/impeller/entity/contents/radial_gradient_contents.cc index f174a6679fe09..8bed872c08a65 100644 --- a/impeller/entity/contents/radial_gradient_contents.cc +++ b/impeller/entity/contents/radial_gradient_contents.cc @@ -94,8 +94,8 @@ bool RadialGradientContents::RenderSSBO(const ContentContext& renderer, GetGeometry()->GetPositionBuffer(renderer, entity, pass); auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; @@ -154,8 +154,8 @@ bool RadialGradientContents::RenderTexture(const ContentContext& renderer, auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; diff --git a/impeller/entity/contents/runtime_effect_contents.cc b/impeller/entity/contents/runtime_effect_contents.cc index 2b358932a1d44..75eedb80939fb 100644 --- a/impeller/entity/contents/runtime_effect_contents.cc +++ b/impeller/entity/contents/runtime_effect_contents.cc @@ -89,8 +89,8 @@ bool RuntimeEffectContents::Render(const ContentContext& renderer, GetGeometry()->GetPositionBuffer(renderer, entity, pass); auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; diff --git a/impeller/entity/contents/solid_color_contents.cc b/impeller/entity/contents/solid_color_contents.cc index d506c0f3197f7..707e771e79f86 100644 --- a/impeller/entity/contents/solid_color_contents.cc +++ b/impeller/entity/contents/solid_color_contents.cc @@ -57,8 +57,8 @@ bool SolidColorContents::Render(const ContentContext& renderer, auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; diff --git a/impeller/entity/contents/sweep_gradient_contents.cc b/impeller/entity/contents/sweep_gradient_contents.cc index 111324488061a..29fbe935eaa6e 100644 --- a/impeller/entity/contents/sweep_gradient_contents.cc +++ b/impeller/entity/contents/sweep_gradient_contents.cc @@ -102,8 +102,8 @@ bool SweepGradientContents::RenderSSBO(const ContentContext& renderer, auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; @@ -163,8 +163,8 @@ bool SweepGradientContents::RenderTexture(const ContentContext& renderer, auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; diff --git a/impeller/entity/contents/texture_contents.cc b/impeller/entity/contents/texture_contents.cc index e600eb230c673..f70640f6aedc7 100644 --- a/impeller/entity/contents/texture_contents.cc +++ b/impeller/entity/contents/texture_contents.cc @@ -158,7 +158,7 @@ bool TextureContents::Render(const ContentContext& renderer, auto pipeline_options = OptionsFromPassAndEntity(pass, entity); if (!stencil_enabled_) { - pipeline_options.stencil_compare = CompareFunction::kAlways; + pipeline_options.stencil_mode = ContentContextOptions::StencilMode::kIgnore; } pipeline_options.primitive_type = PrimitiveType::kTriangleStrip; diff --git a/impeller/entity/contents/tiled_texture_contents.cc b/impeller/entity/contents/tiled_texture_contents.cc index 823c3d0b6132d..732e27ec25d20 100644 --- a/impeller/entity/contents/tiled_texture_contents.cc +++ b/impeller/entity/contents/tiled_texture_contents.cc @@ -153,8 +153,8 @@ bool TiledTextureContents::Render(const ContentContext& renderer, auto options = OptionsFromPassAndEntity(pass, entity); if (geometry_result.prevent_overdraw) { - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; } options.primitive_type = geometry_result.type; diff --git a/impeller/renderer/compute_subgroup_unittests.cc b/impeller/renderer/compute_subgroup_unittests.cc index 144b63544470f..dd657b1a62474 100644 --- a/impeller/renderer/compute_subgroup_unittests.cc +++ b/impeller/renderer/compute_subgroup_unittests.cc @@ -143,8 +143,9 @@ TEST_P(ComputeSubgroupTest, PathPlayground) { pass.GetRenderTarget().GetStencilAttachment().has_value(); options.blend_mode = BlendMode::kSourceIn; options.primitive_type = PrimitiveType::kTriangleStrip; - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; pass.SetPipeline(renderer.GetSolidFillPipeline(options)); @@ -340,8 +341,9 @@ TEST_P(ComputeSubgroupTest, LargePath) { pass.GetRenderTarget().GetStencilAttachment().has_value(); options.blend_mode = BlendMode::kSourceIn; options.primitive_type = PrimitiveType::kTriangleStrip; - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; pass.SetPipeline(renderer.GetSolidFillPipeline(options)); @@ -418,8 +420,9 @@ TEST_P(ComputeSubgroupTest, QuadAndCubicInOnePath) { pass.GetRenderTarget().GetStencilAttachment().has_value(); options.blend_mode = BlendMode::kSourceIn; options.primitive_type = PrimitiveType::kTriangleStrip; - options.stencil_compare = CompareFunction::kEqual; - options.stencil_operation = StencilOperation::kIncrementClamp; + + options.stencil_mode = + ContentContextOptions::StencilMode::kLegacyClipIncrement; pass.SetPipeline(renderer.GetSolidFillPipeline(options));