From 2e09c418a7851cecc51c2cafa7f5e97cda147c56 Mon Sep 17 00:00:00 2001 From: Brandon DeRosier Date: Wed, 21 Feb 2024 19:30:18 -0800 Subject: [PATCH] [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. --- impeller/aiks/canvas.cc | 7 +- impeller/entity/contents/clip_contents.cc | 111 ++++++++++- impeller/entity/contents/clip_contents.h | 11 ++ .../entity/contents/color_source_contents.h | 88 ++++++++- impeller/entity/contents/content_context.cc | 22 ++- impeller/entity/contents/content_context.h | 45 +++-- impeller/entity/contents/contents.cc | 4 + impeller/entity/entity.cc | 2 +- impeller/entity/entity_pass.cc | 3 + impeller/entity/entity_unittests.cc | 34 ++++ .../entity/geometry/fill_path_geometry.cc | 183 ++++++++++-------- impeller/entity/inline_pass_context.cc | 12 ++ 12 files changed, 404 insertions(+), 118 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index d65d5274a21a4..1c8c963c3e31a 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -219,8 +219,10 @@ bool Canvas::Restore() { } transform_stack_.pop_back(); - if (num_clips > 0) { - RestoreClip(); + if constexpr (!ContentContext::kEnableStencilThenCover) { + if (num_clips > 0) { + RestoreClip(); + } } return true; @@ -597,7 +599,6 @@ void Canvas::RestoreClip() { entity.SetContents(std::make_shared()); 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 22b81e5d72770..b85beac674a9a 100644 --- a/impeller/entity/contents/clip_contents.cc +++ b/impeller/entity/contents/clip_contents.cc @@ -73,9 +73,97 @@ bool ClipContents::CanInheritOpacity(const Entity& entity) const { 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 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{} + .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 @@ bool ClipContents::Render(const ContentContext& renderer, 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 @@ bool ClipContents::Render(const ContentContext& renderer, 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 @@ bool ClipContents::Render(const ContentContext& renderer, 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 b519cc255e112..8d7f162217cff 100644 --- a/impeller/entity/contents/clip_contents.h +++ b/impeller/entity/contents/clip_contents.h @@ -49,6 +49,17 @@ class ClipContents final : public Contents { 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_; 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 d89e522cde094..4951494b69030 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 @@ class ColorSourceContents : public Contents { 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 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{} + .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 @@ class ColorSourceContents : public Contents { 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 @@ class ColorSourceContents : public Contents { 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 05397d3346bed..270e8173508c2 100644 --- a/impeller/entity/contents/content_context.cc +++ b/impeller/entity/contents/content_context.cc @@ -164,28 +164,32 @@ void ContentContextOptions::ApplyToPipelineDescriptor( 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 4b813e9a8d18e..67e840716557d 100644 --- a/impeller/entity/contents/content_context.h +++ b/impeller/entity/contents/content_context.h @@ -287,21 +287,34 @@ struct PendingCommandBuffers { /// 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 @@ class ContentContext { 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 GetSceneContext() const; #endif // IMPELLER_ENABLE_3D diff --git a/impeller/entity/contents/contents.cc b/impeller/entity/contents/contents.cc index 681c160a58174..b71ceca97db2e 100644 --- a/impeller/entity/contents/contents.cc +++ b/impeller/entity/contents/contents.cc @@ -27,6 +27,10 @@ ContentContextOptions OptionsFromPass(const RenderPass& pass) { 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 e1f26f6fc8325..472f4b534bee8 100644 --- a/impeller/entity/entity.cc +++ b/impeller/entity/entity.cc @@ -110,7 +110,7 @@ uint32_t Entity::GetNewClipDepth() const { 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 608545b0e8509..76a5d313e0dae 100644 --- a/impeller/entity/entity_pass.cc +++ b/impeller/entity/entity_pass.cc @@ -4,6 +4,7 @@ #include "impeller/entity/entity_pass.h" +#include #include #include #include @@ -765,6 +766,7 @@ bool EntityPass::RenderElement(Entity& element_entity, 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::max()); if (!msaa_backdrop_entity.Render(renderer, *result.pass)) { VALIDATION_LOG << "Failed to render MSAA backdrop filter entity."; return false; @@ -923,6 +925,7 @@ bool EntityPass::OnRender( backdrop_entity.SetTransform( Matrix::MakeTranslation(Vector3(-local_pass_position))); backdrop_entity.SetClipDepth(clip_depth_floor); + backdrop_entity.SetNewClipDepth(std::numeric_limits::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 e5a6adca14b7f..07b065d0a10ea 100644 --- a/impeller/entity/entity_unittests.cc +++ b/impeller/entity/entity_unittests.cc @@ -2758,6 +2758,40 @@ TEST_P(EntityTest, FramebufferFetchVulkanBindingOffsetIsTheSame) { } #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 5cd721a583942..959d858f6d73c 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 @@ FillPathGeometry::FillPathGeometry(const Path& path, std::optional 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 @@ GeometryResult FillPathGeometry::GetPositionBuffer( 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 @@ GeometryResult FillPathGeometry::GetPositionUVBuffer( 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 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 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 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 d9258acd7938c..7fcaf515ad3e8 100644 --- a/impeller/entity/inline_pass_context.cc +++ b/impeller/entity/inline_pass_context.cc @@ -146,6 +146,18 @@ InlinePassContext::RenderPassResult InlinePassContext::GetRenderPass( 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 "