From ad4202f1e0a93ecbb57d5c77a982d48232f61e64 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 9 Jul 2024 12:55:08 -0700 Subject: [PATCH 01/37] [Impeller] enable experimental canvas. --- common/config.gni | 2 +- impeller/aiks/experimental_canvas.cc | 24 ++++++++---------------- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/common/config.gni b/common/config.gni index c587735b5063e..577c83940f84f 100644 --- a/common/config.gni +++ b/common/config.gni @@ -37,7 +37,7 @@ declare_args() { slimpeller = false # Opt into new DL dispatcher that skips AIKS layer - experimental_canvas = false + experimental_canvas = true } # feature_defines_list --------------------------------------------------------- diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 1c0bfb0cac4e1..a414372e89052 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -56,7 +56,6 @@ static const constexpr RenderTarget::AttachmentConfig kDefaultStencilConfig = static std::unique_ptr CreateRenderTarget( ContentContext& renderer, ISize size, - int mip_count, const Color& clear_color) { const std::shared_ptr& context = renderer.GetContext(); @@ -65,18 +64,12 @@ static std::unique_ptr CreateRenderTarget( /// What's important is the `StorageMode` of the textures, which cannot be /// changed for the lifetime of the textures. - if (context->GetBackendType() == Context::BackendType::kOpenGLES) { - // TODO(https://github.com/flutter/flutter/issues/141732): Implement mip map - // generation on opengles. - mip_count = 1; - } - RenderTarget target; if (context->GetCapabilities()->SupportsOffscreenMSAA()) { target = renderer.GetRenderTargetCache()->CreateOffscreenMSAA( /*context=*/*context, /*size=*/size, - /*mip_count=*/mip_count, + /*mip_count=*/1, /*label=*/"EntityPass", /*color_attachment_config=*/ RenderTarget::AttachmentConfigMSAA{ @@ -90,7 +83,7 @@ static std::unique_ptr CreateRenderTarget( target = renderer.GetRenderTargetCache()->CreateOffscreen( *context, // context size, // size - /*mip_count=*/mip_count, + /*mip_count=*/1, "EntityPass", // label RenderTarget::AttachmentConfig{ .storage_mode = StorageMode::kDevicePrivate, @@ -172,12 +165,10 @@ void ExperimentalCanvas::SetupRenderPass() { // a second save layer with the same dimensions as the onscreen. When // rendering is completed, we must blit this saveLayer to the onscreen. if (requires_readback_) { - auto entity_pass_target = CreateRenderTarget( - renderer_, // - color0.texture->GetSize(), // - // Note: this is incorrect, we also need to know what kind of filter. - /*mip_count=*/4, // - /*clear_color=*/Color::BlackTransparent()); + auto entity_pass_target = + CreateRenderTarget(renderer_, // + color0.texture->GetSize(), // + /*clear_color=*/Color::BlackTransparent()); render_passes_.push_back( LazyRenderingConfig(renderer_, std::move(entity_pass_target))); } else { @@ -379,7 +370,8 @@ void ExperimentalCanvas::SaveLayer( renderer_, // CreateRenderTarget(renderer_, // ISize(subpass_coverage.GetSize()), // - 1u, Color::BlackTransparent()))); + Color::BlackTransparent() // + ))); save_layer_state_.push_back(SaveLayerState{paint_copy, subpass_coverage}); CanvasStackEntry entry; From c148f01bdc82dfd56319a754505e8eec2c98702d Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 9 Jul 2024 13:16:49 -0700 Subject: [PATCH 02/37] remove redefinition --- impeller/golden_tests/golden_playground_test_mac.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/impeller/golden_tests/golden_playground_test_mac.cc b/impeller/golden_tests/golden_playground_test_mac.cc index d5cb282c4bf98..7a2b674dbc049 100644 --- a/impeller/golden_tests/golden_playground_test_mac.cc +++ b/impeller/golden_tests/golden_playground_test_mac.cc @@ -24,8 +24,6 @@ #define GLFW_INCLUDE_NONE #include "third_party/glfw/include/GLFW/glfw3.h" -#define EXPERIMENTAL_CANVAS false - namespace impeller { namespace { From 5e3ebb187b98f26de1480ee631f3071c7e41eda7 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 9 Jul 2024 13:53:40 -0700 Subject: [PATCH 03/37] temp test adaption. --- shell/gpu/gpu_surface_metal_impeller_unittests.mm | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/shell/gpu/gpu_surface_metal_impeller_unittests.mm b/shell/gpu/gpu_surface_metal_impeller_unittests.mm index 13ccbba3f6906..4164a242bef1d 100644 --- a/shell/gpu/gpu_surface_metal_impeller_unittests.mm +++ b/shell/gpu/gpu_surface_metal_impeller_unittests.mm @@ -109,19 +109,31 @@ GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override auto& host_buffer = surface->GetAiksContext()->GetContentContext().GetTransientsBuffer(); +#if EXPERIMENTAL_CANVAS + EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); +#else EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); +#endif // EXPERIMENTAL_CANVAS auto frame = surface->AcquireFrame(SkISize::Make(100, 100)); frame->set_submit_info({.frame_boundary = false}); ASSERT_TRUE(frame->Submit()); +#if EXPERIMENTAL_CANVAS + EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); +#else EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); +#endif // EXPERIMENTAL_CANVAS frame = surface->AcquireFrame(SkISize::Make(100, 100)); frame->set_submit_info({.frame_boundary = true}); ASSERT_TRUE(frame->Submit()); +#if EXPERIMENTAL_CANVAS + EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 2u); +#else EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); +#endif // EXPERIMENTAL_CANVAS } } // namespace testing From 492f4613d246b7c3181f8ac0bebc2559c08b1e7c Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 9 Jul 2024 14:15:27 -0700 Subject: [PATCH 04/37] fix host buffer reset for exp canvas. --- shell/gpu/gpu_surface_metal_impeller.mm | 5 ++++- shell/gpu/gpu_surface_metal_impeller_unittests.mm | 11 ----------- shell/gpu/gpu_surface_vulkan_impeller.cc | 7 +++++-- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index bc9bfd78d2ffb..8647d2897fc62 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -162,6 +162,7 @@ impeller::IRect cull_rect = surface->coverage(); SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.GetWidth(), cull_rect.GetHeight()); + const bool reset_host_buffer = surface_frame.submit_info().frame_boundary; #if EXPERIMENTAL_CANVAS impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), @@ -179,13 +180,15 @@ impeller_dispatcher.FinishRecording(); aiks_context->GetContentContext().GetTransientsBuffer().Reset(); aiks_context->GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames(); + if (reset_host_buffer) { + aiks_context->GetContentContext().GetTransientsBuffer().Reset(); + } return true; })); #else impeller::DlDispatcher impeller_dispatcher(cull_rect); display_list->Dispatch(impeller_dispatcher, sk_cull_rect); auto picture = impeller_dispatcher.EndRecordingAsPicture(); - const bool reset_host_buffer = surface_frame.submit_info().frame_boundary; return renderer->Render( std::move(surface), diff --git a/shell/gpu/gpu_surface_metal_impeller_unittests.mm b/shell/gpu/gpu_surface_metal_impeller_unittests.mm index 4164a242bef1d..ff33d438450e3 100644 --- a/shell/gpu/gpu_surface_metal_impeller_unittests.mm +++ b/shell/gpu/gpu_surface_metal_impeller_unittests.mm @@ -109,31 +109,20 @@ GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override auto& host_buffer = surface->GetAiksContext()->GetContentContext().GetTransientsBuffer(); -#if EXPERIMENTAL_CANVAS EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); -#else EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); -#endif // EXPERIMENTAL_CANVAS auto frame = surface->AcquireFrame(SkISize::Make(100, 100)); frame->set_submit_info({.frame_boundary = false}); ASSERT_TRUE(frame->Submit()); -#if EXPERIMENTAL_CANVAS - EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); -#else EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); -#endif // EXPERIMENTAL_CANVAS frame = surface->AcquireFrame(SkISize::Make(100, 100)); frame->set_submit_info({.frame_boundary = true}); ASSERT_TRUE(frame->Submit()); -#if EXPERIMENTAL_CANVAS - EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 2u); -#else EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); -#endif // EXPERIMENTAL_CANVAS } } // namespace testing diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index d32cef7e6ea4c..ebd2751a1f11c 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -87,6 +87,8 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( std::move(surface), fml::MakeCopyable([&](impeller::RenderTarget& render_target) -> bool { + const bool reset_host_buffer = + surface_frame.submit_info().frame_boundary; #if EXPERIMENTAL_CANVAS impeller::TextFrameDispatcher collector( aiks_context->GetContentContext(), impeller::Matrix()); @@ -107,6 +109,9 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( aiks_context->GetContentContext() .GetLazyGlyphAtlas() ->ResetTextFrames(); + if (reset_host_buffer) { + aiks_context->GetContentContext().GetTransientsBuffer().Reset(); + } return true; #else impeller::Rect dl_cull_rect = impeller::Rect::MakeSize(cull_rect); @@ -115,8 +120,6 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( impeller_dispatcher, SkIRect::MakeWH(cull_rect.width, cull_rect.height)); auto picture = impeller_dispatcher.EndRecordingAsPicture(); - const bool reset_host_buffer = - surface_frame.submit_info().frame_boundary; return aiks_context->Render(picture, render_target, reset_host_buffer); #endif From ff2fa94400d7f2c18649c933984a247749ca2bca Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 9 Jul 2024 14:26:36 -0700 Subject: [PATCH 05/37] add capture for reset_host_buffer --- shell/gpu/gpu_surface_metal_impeller.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index 8647d2897fc62..c5b854f339766 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -171,7 +171,7 @@ return renderer->Render( std::move(surface), fml::MakeCopyable([aiks_context, &display_list, &cull_rect, - &sk_cull_rect](impeller::RenderTarget& render_target) -> bool { + &sk_cull_rect, reset_host_buffer](impeller::RenderTarget& render_target) -> bool { impeller::ExperimentalDlDispatcher impeller_dispatcher( aiks_context->GetContentContext(), render_target, display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(), From a2ef961aeba90c431822d9f35790a260984cef7a Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 9 Jul 2024 15:50:12 -0700 Subject: [PATCH 06/37] capture. --- shell/gpu/gpu_surface_metal_impeller.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index c5b854f339766..45d60b55d15ba 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -170,8 +170,8 @@ display_list->Dispatch(collector, sk_cull_rect); return renderer->Render( std::move(surface), - fml::MakeCopyable([aiks_context, &display_list, &cull_rect, - &sk_cull_rect, reset_host_buffer](impeller::RenderTarget& render_target) -> bool { + fml::MakeCopyable([aiks_context, &display_list, &cull_rect, &sk_cull_rect, + &reset_host_buffer](impeller::RenderTarget& render_target) -> bool { impeller::ExperimentalDlDispatcher impeller_dispatcher( aiks_context->GetContentContext(), render_target, display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(), @@ -193,7 +193,7 @@ return renderer->Render( std::move(surface), fml::MakeCopyable([aiks_context, picture = std::move(picture), - reset_host_buffer](impeller::RenderTarget& render_target) -> bool { + &reset_host_buffer](impeller::RenderTarget& render_target) -> bool { return aiks_context->Render(picture, render_target, reset_host_buffer); })); #endif From 2432a3ff47db3e7f2d9ac2e8eb71ad9e7a5d7a50 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 9 Jul 2024 16:51:00 -0700 Subject: [PATCH 07/37] remove extra assert. --- shell/gpu/gpu_surface_metal_impeller_unittests.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/shell/gpu/gpu_surface_metal_impeller_unittests.mm b/shell/gpu/gpu_surface_metal_impeller_unittests.mm index ff33d438450e3..13ccbba3f6906 100644 --- a/shell/gpu/gpu_surface_metal_impeller_unittests.mm +++ b/shell/gpu/gpu_surface_metal_impeller_unittests.mm @@ -109,7 +109,6 @@ GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override auto& host_buffer = surface->GetAiksContext()->GetContentContext().GetTransientsBuffer(); - EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); auto frame = surface->AcquireFrame(SkISize::Make(100, 100)); From f0a0114d4771c6cf2dc72bac690e66fbd4002e9c Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 9 Jul 2024 18:38:46 -0700 Subject: [PATCH 08/37] temp disable for testing. --- .../gpu_surface_metal_impeller_unittests.mm | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/shell/gpu/gpu_surface_metal_impeller_unittests.mm b/shell/gpu/gpu_surface_metal_impeller_unittests.mm index 13ccbba3f6906..f7599fea2b6e9 100644 --- a/shell/gpu/gpu_surface_metal_impeller_unittests.mm +++ b/shell/gpu/gpu_surface_metal_impeller_unittests.mm @@ -97,32 +97,33 @@ GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override ASSERT_TRUE(frame->Submit()); } -TEST(GPUSurfaceMetalImpeller, ResetHostBufferBasedOnFrameBoundary) { - auto delegate = std::make_shared(); - delegate->SetDevice(); +// TESTING! +// TEST(GPUSurfaceMetalImpeller, ResetHostBufferBasedOnFrameBoundary) { +// auto delegate = std::make_shared(); +// delegate->SetDevice(); - auto context = CreateImpellerContext(); - std::unique_ptr surface = - std::make_unique(delegate.get(), CreateImpellerContext()); +// auto context = CreateImpellerContext(); +// std::unique_ptr surface = +// std::make_unique(delegate.get(), CreateImpellerContext()); - ASSERT_TRUE(surface->IsValid()); +// ASSERT_TRUE(surface->IsValid()); - auto& host_buffer = surface->GetAiksContext()->GetContentContext().GetTransientsBuffer(); +// auto& host_buffer = surface->GetAiksContext()->GetContentContext().GetTransientsBuffer(); - EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); +// EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); - auto frame = surface->AcquireFrame(SkISize::Make(100, 100)); - frame->set_submit_info({.frame_boundary = false}); +// auto frame = surface->AcquireFrame(SkISize::Make(100, 100)); +// frame->set_submit_info({.frame_boundary = false}); - ASSERT_TRUE(frame->Submit()); - EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); +// ASSERT_TRUE(frame->Submit()); +// EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); - frame = surface->AcquireFrame(SkISize::Make(100, 100)); - frame->set_submit_info({.frame_boundary = true}); +// frame = surface->AcquireFrame(SkISize::Make(100, 100)); +// frame->set_submit_info({.frame_boundary = true}); - ASSERT_TRUE(frame->Submit()); - EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); -} +// ASSERT_TRUE(frame->Submit()); +// EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); +// } } // namespace testing } // namespace flutter From 188ecd16e2256bcda453e567f8756cfd982cd335 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 10 Jul 2024 14:56:57 -0700 Subject: [PATCH 09/37] cull rect correctly --- impeller/aiks/experimental_canvas.cc | 50 +++++++++++++++++----------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index a414372e89052..67317ea3bf948 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -203,6 +203,19 @@ void ExperimentalCanvas::SaveLayer( ContentBoundsPromise bounds_promise, uint32_t total_content_depth, bool can_distribute_opacity) { + if (!clip_coverage_stack_.HasCoverage()) { + // The current clip is empty. This means the pass texture won't be + // visible, so skip it. + Save(total_content_depth); + return; + } + + auto clip_coverage_back = clip_coverage_stack_.CurrentClipCoverage(); + if (!clip_coverage_back.has_value()) { + Save(total_content_depth); + return; + } + // Can we always guarantee that we get a bounds? Does a lack of bounds // indicate something? if (!bounds.has_value()) { @@ -218,28 +231,25 @@ void ExperimentalCanvas::SaveLayer( // The maximum coverage of the subpass. Subpasses textures should never // extend outside the parent pass texture or the current clip coverage. - Rect coverage_limit = Rect::MakeOriginSize( - GetGlobalPassPosition(), - Size(render_passes_.back().inline_pass_context->GetTexture()->GetSize())); + std::optional maybe_coverage_limit = + Rect::MakeOriginSize(GetGlobalPassPosition(), + Size(render_passes_.back() + .inline_pass_context->GetTexture() + ->GetSize())) + .Intersection(clip_coverage_back.value()); + + if (!maybe_coverage_limit.has_value()) { + Save(total_content_depth); + return; + } + maybe_coverage_limit = maybe_coverage_limit->Intersection( + Rect::MakeSize(render_target_.GetRenderTargetSize())); - // BDF No-op. need to do some precomputation to ensure this is fully skipped. - if (backdrop_filter) { - if (!clip_coverage_stack_.HasCoverage()) { - Save(total_content_depth); - return; - } - auto maybe_clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); - if (!maybe_clip_coverage.has_value()) { - Save(total_content_depth); - return; - } - auto clip_coverage = maybe_clip_coverage.value(); - if (clip_coverage.IsEmpty() || - !coverage_limit.IntersectsWithRect(clip_coverage)) { - Save(total_content_depth); - return; - } + if (!maybe_coverage_limit.has_value() || maybe_coverage_limit->IsEmpty()) { + Save(total_content_depth); + return; } + auto coverage_limit = maybe_coverage_limit.value(); if (can_distribute_opacity && !backdrop_filter && Paint::CanApplyOpacityPeephole(paint)) { From 0c2926e13f0d86dd5aca5614fa1e123518289e9c Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 23 Jul 2024 11:18:44 -0700 Subject: [PATCH 10/37] ++ --- shell/common/snapshot_controller_impeller.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shell/common/snapshot_controller_impeller.cc b/shell/common/snapshot_controller_impeller.cc index 3f926b5025bcd..9233fce8e93c1 100644 --- a/shell/common/snapshot_controller_impeller.cc +++ b/shell/common/snapshot_controller_impeller.cc @@ -48,7 +48,6 @@ sk_sp DoMakeRasterSnapshot( #if EXPERIMENTAL_CANVAS // Do not use the render target cache as the lifecycle of this texture // will outlive a particular frame. - impeller::ISize impeller_size = impeller::ISize(size.width(), size.height()); impeller::RenderTargetAllocator render_target_allocator = impeller::RenderTargetAllocator( context->GetContext()->GetResourceAllocator()); @@ -56,7 +55,7 @@ sk_sp DoMakeRasterSnapshot( if (context->GetContext()->GetCapabilities()->SupportsOffscreenMSAA()) { target = render_target_allocator.CreateOffscreenMSAA( *context->GetContext(), // context - impeller_size, // size + render_target_size, // size /*mip_count=*/1, "Picture Snapshot MSAA", // label impeller::RenderTarget:: @@ -65,7 +64,7 @@ sk_sp DoMakeRasterSnapshot( } else { target = render_target_allocator.CreateOffscreen( *context->GetContext(), // context - impeller_size, // size + render_target_size, // size /*mip_count=*/1, "Picture Snapshot", // label impeller::RenderTarget:: From f42ec97097ec63bbd37047da7580ab19dac90639 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 23 Jul 2024 12:32:27 -0700 Subject: [PATCH 11/37] ++ --- shell/common/snapshot_controller_impeller.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/common/snapshot_controller_impeller.cc b/shell/common/snapshot_controller_impeller.cc index 9233fce8e93c1..68bc9ac46a3c8 100644 --- a/shell/common/snapshot_controller_impeller.cc +++ b/shell/common/snapshot_controller_impeller.cc @@ -79,7 +79,7 @@ sk_sp DoMakeRasterSnapshot( context->GetContentContext(), target, display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(), - impeller::IRect::MakeSize(impeller_size)); + impeller::IRect::MakeSize(render_target_size)); display_list->Dispatch(impeller_dispatcher, SkIRect::MakeSize(size)); impeller_dispatcher.FinishRecording(); From 239402c6f1f1a045409a9a06059359370018d93e Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 23 Jul 2024 13:47:24 -0700 Subject: [PATCH 12/37] add back trace event. --- impeller/aiks/experimental_canvas.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 67317ea3bf948..84309b57c18ec 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -4,6 +4,7 @@ #include "impeller/aiks/experimental_canvas.h" #include "fml/logging.h" +#include "fml/trace_event.h" #include "impeller/aiks/canvas.h" #include "impeller/aiks/paint_pass_delegate.h" #include "impeller/base/validation.h" @@ -203,6 +204,8 @@ void ExperimentalCanvas::SaveLayer( ContentBoundsPromise bounds_promise, uint32_t total_content_depth, bool can_distribute_opacity) { + TRACE_EVENT0("flutter", "Canvas::saveLayer"); + if (!clip_coverage_stack_.HasCoverage()) { // The current clip is empty. This means the pass texture won't be // visible, so skip it. From 3a355557d23fc600f41c0189aec807360e5d4f8b Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Thu, 25 Jul 2024 09:43:43 -0700 Subject: [PATCH 13/37] Update gpu_surface_metal_impeller_unittests.mm --- .../gpu_surface_metal_impeller_unittests.mm | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/shell/gpu/gpu_surface_metal_impeller_unittests.mm b/shell/gpu/gpu_surface_metal_impeller_unittests.mm index 885d7b13ce329..94bde0eb25fc5 100644 --- a/shell/gpu/gpu_surface_metal_impeller_unittests.mm +++ b/shell/gpu/gpu_surface_metal_impeller_unittests.mm @@ -125,35 +125,35 @@ GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override // EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); // } -#ifdef IMPELLER_DEBUG -TEST(GPUSurfaceMetalImpeller, CreatesImpellerCaptureScope) { - auto delegate = std::make_shared(); - delegate->SetDevice(); +// #ifdef IMPELLER_DEBUG +// TEST(GPUSurfaceMetalImpeller, CreatesImpellerCaptureScope) { +// auto delegate = std::make_shared(); +// delegate->SetDevice(); - auto context = CreateImpellerContext(); +// auto context = CreateImpellerContext(); - EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive()); +// EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive()); - std::unique_ptr surface = - std::make_unique(delegate.get(), context); - auto frame_1 = surface->AcquireFrame(SkISize::Make(100, 100)); - frame_1->set_submit_info({.frame_boundary = false}); +// std::unique_ptr surface = +// std::make_unique(delegate.get(), context); +// auto frame_1 = surface->AcquireFrame(SkISize::Make(100, 100)); +// frame_1->set_submit_info({.frame_boundary = false}); - EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); +// EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); - std::unique_ptr surface_2 = - std::make_unique(delegate.get(), context); - auto frame_2 = surface->AcquireFrame(SkISize::Make(100, 100)); - frame_2->set_submit_info({.frame_boundary = true}); +// std::unique_ptr surface_2 = +// std::make_unique(delegate.get(), context); +// auto frame_2 = surface->AcquireFrame(SkISize::Make(100, 100)); +// frame_2->set_submit_info({.frame_boundary = true}); - EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); +// EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); - ASSERT_TRUE(frame_1->Submit()); - EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); - ASSERT_TRUE(frame_2->Submit()); - EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive()); -} -#endif // IMPELLER_DEBUG +// ASSERT_TRUE(frame_1->Submit()); +// EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); +// ASSERT_TRUE(frame_2->Submit()); +// EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive()); +// } +// #endif // IMPELLER_DEBUG } // namespace testing } // namespace flutter From 45c00cfc65311b6dcf7c0d2f914570da25d82f1f Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 25 Jul 2024 15:41:33 -0700 Subject: [PATCH 14/37] ++ --- impeller/aiks/experimental_canvas.cc | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index e1c1dc18a695b..3697e07b60355 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -705,8 +705,29 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, if (renderer_.GetDeviceCapabilities().SupportsFramebufferFetch()) { ApplyFramebufferBlend(entity); } else { - VALIDATION_LOG << "Emulated advanced blends are currently unsupported."; - return; + // End the active pass and flush the buffer before rendering "advanced" + // blends. Advanced blends work by binding the current render target + // texture as an input ("destination"), blending with a second texture + // input ("source"), writing the result to an intermediate texture, and + // finally copying the data from the intermediate texture back to the + // render target texture. And so all of the commands that have written + // to the render target texture so far need to execute before it's bound + // for blending (otherwise the blend pass will end up executing before + // all the previous commands in the active pass). + auto input_texture = FlipBackdrop(render_passes_, GetGlobalPassPosition(), + clip_coverage_stack_, renderer_); + if (!input_texture) { + return; + } + + FilterInput::Vector inputs = { + FilterInput::Make(input_texture, entity.GetTransform().Invert()), + FilterInput::Make(entity.GetContents())}; + auto contents = + ColorFilterContents::MakeBlend(entity.GetBlendMode(), inputs); + contents->SetCoverageHint(entity.GetCoverage()); + entity.SetContents(std::move(contents)); + entity.SetBlendMode(BlendMode::kSource); } } From 94b4340ff540416218a308562b90bb6e2121eb87 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 25 Jul 2024 17:08:27 -0700 Subject: [PATCH 15/37] fix entity pass flip --- impeller/aiks/experimental_canvas.cc | 23 ++++++++++++----------- impeller/aiks/experimental_canvas.h | 6 ++++++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 3697e07b60355..ecf99a3e02136 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -83,13 +83,13 @@ static std::shared_ptr FlipBackdrop( // unbalanced save layers. Ideally, this method would return false and the // renderer could handle that by terminating dispatch. render_passes.push_back(LazyRenderingConfig( - renderer, std::move(rendering_config.entity_pass_target))); + renderer, std::move(rendering_config.entity_pass_target), + std::move(rendering_config.inline_pass_context))); return nullptr; } std::shared_ptr input_texture = - rendering_config.entity_pass_target->Flip( - *renderer.GetContext()->GetResourceAllocator()); + rendering_config.inline_pass_context->GetTexture(); if (!input_texture) { VALIDATION_LOG << "Failed to fetch the color texture in order to " @@ -97,12 +97,14 @@ static std::shared_ptr FlipBackdrop( // Note: see above. render_passes.push_back(LazyRenderingConfig( - renderer, std::move(rendering_config.entity_pass_target))); + renderer, std::move(rendering_config.entity_pass_target), + std::move(rendering_config.inline_pass_context))); return nullptr; } render_passes.push_back(LazyRenderingConfig( - renderer, std::move(rendering_config.entity_pass_target))); + renderer, std::move(rendering_config.entity_pass_target), + std::move(rendering_config.inline_pass_context))); // Eagerly restore the BDF contents. // If the pass context returns a backdrop texture, we need to draw it to the @@ -674,14 +676,13 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, // conditionally update the backdrop color to its solid color value blended // with the current backdrop. if (render_passes_.back().IsApplyingClearColor()) { - std::optional maybe_color = - entity.AsBackgroundColor(render_passes_.back() - .entity_pass_target->GetRenderTarget() - .GetRenderTargetSize()); + std::optional maybe_color = entity.AsBackgroundColor( + render_passes_.back().inline_pass_context->GetTexture()->GetSize()); if (maybe_color.has_value()) { Color color = maybe_color.value(); - RenderTarget& render_target = - render_passes_.back().entity_pass_target->GetRenderTarget(); + RenderTarget& render_target = render_passes_.back() + .inline_pass_context->GetPassTarget() + .GetRenderTarget(); ColorAttachment attachment = render_target.GetColorAttachments().find(0u)->second; attachment.clear_color = attachment.clear_color.Unpremultiply() diff --git a/impeller/aiks/experimental_canvas.h b/impeller/aiks/experimental_canvas.h index d1868441b7545..debb4baf088fc 100644 --- a/impeller/aiks/experimental_canvas.h +++ b/impeller/aiks/experimental_canvas.h @@ -31,6 +31,12 @@ struct LazyRenderingConfig { inline_pass_context = std::make_unique(renderer, *entity_pass_target, 0); } + + LazyRenderingConfig(ContentContext& renderer, + std::unique_ptr entity_pass_target, + std::unique_ptr inline_pass_context) + : entity_pass_target(std::move(entity_pass_target)), + inline_pass_context(std::move(inline_pass_context)) {} }; /// This Canvas attempts to translate from display lists to draw calls directly. From ed8ad3f3561bd0e3e7a747241648f395e377b9ad Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 30 Jul 2024 17:12:20 -0700 Subject: [PATCH 16/37] ++ --- impeller/aiks/experimental_canvas.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index ecf99a3e02136..de65dfe68043e 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -322,15 +322,15 @@ void ExperimentalCanvas::SaveLayer( return; } - // Can we always guarantee that we get a bounds? Does a lack of bounds - // indicate something? - if (!bounds.has_value()) { - bounds = Rect::MakeSize(render_target_.GetRenderTargetSize()); - } + // // Can we always guarantee that we get a bounds? Does a lack of bounds + // // indicate something? + // if (!bounds.has_value()) { + // bounds = Rect::MakeSize(render_target_.GetRenderTargetSize()); + // } // SaveLayer is a no-op, depending on the bounds promise. Should/Can DL elide // this? - if (bounds->IsEmpty()) { + if (bounds.has_value() && bounds->IsEmpty()) { Save(total_content_depth); return; } @@ -408,7 +408,8 @@ void ExperimentalCanvas::SaveLayer( // Backdrop Filter must expand bounds to at least the clip stack, otherwise // the coverage of the parent render pass. Rect subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); - if (backdrop_filter_contents) { + if (backdrop_filter_contents || + Entity::IsBlendModeDestructive(paint.blend_mode)) { FML_CHECK(clip_coverage_stack_.HasCoverage()); // We should never hit this case as we check the intersection above. // NOLINTBEGIN(bugprone-unchecked-optional-access) From 5b9c14b65bbfa4893911c43374670306b1309709 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 30 Jul 2024 19:14:42 -0700 Subject: [PATCH 17/37] ++ --- shell/gpu/gpu_surface_metal_impeller.mm | 4 ++-- shell/gpu/gpu_surface_vulkan_impeller.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index 9d7f1015e371b..30569cdcd11fd 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -161,7 +161,7 @@ SkIRect sk_cull_rect = SkIRect::MakeWH(cull_rect.GetWidth(), cull_rect.GetHeight()); const bool reset_host_buffer = surface_frame.submit_info().frame_boundary; - const impeller::RenderTarget& render_target = surface->GetTargetRenderPassDescriptor(); + impeller::RenderTarget render_target = surface->GetTargetRenderPassDescriptor(); surface->SetFrameBoundary(surface_frame.submit_info().frame_boundary); surface_frame.set_user_data(std::move(surface)); @@ -284,7 +284,7 @@ impeller::TextFrameDispatcher collector(aiks_context->GetContentContext(), impeller::Matrix()); display_list->Dispatch(collector, sk_cull_rect); - const impeller::RenderTarget& render_target = surface->GetTargetRenderPassDescriptor(); + impeller::RenderTarget render_target = surface->GetTargetRenderPassDescriptor(); impeller::ExperimentalDlDispatcher impeller_dispatcher( aiks_context->GetContentContext(), render_target, display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(), diff --git a/shell/gpu/gpu_surface_vulkan_impeller.cc b/shell/gpu/gpu_surface_vulkan_impeller.cc index 12f5810e0363a..02a9a4dfd5908 100644 --- a/shell/gpu/gpu_surface_vulkan_impeller.cc +++ b/shell/gpu/gpu_surface_vulkan_impeller.cc @@ -62,7 +62,7 @@ std::unique_ptr GPUSurfaceVulkanImpeller::AcquireFrame( auto cull_rect = surface->GetTargetRenderPassDescriptor().GetRenderTargetSize(); - const impeller::RenderTarget& render_target = + impeller::RenderTarget render_target = surface->GetTargetRenderPassDescriptor(); SurfaceFrame::EncodeCallback encode_callback = [aiks_context = From c5ad6785edd8497640b9b695d2c5ce80ee55c5b2 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 30 Jul 2024 20:24:51 -0700 Subject: [PATCH 18/37] check bounds. --- impeller/aiks/experimental_canvas.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index de65dfe68043e..26eb1d6474e43 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -407,9 +407,9 @@ void ExperimentalCanvas::SaveLayer( // Backdrop Filter must expand bounds to at least the clip stack, otherwise // the coverage of the parent render pass. - Rect subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); + Rect subpass_coverage; if (backdrop_filter_contents || - Entity::IsBlendModeDestructive(paint.blend_mode)) { + Entity::IsBlendModeDestructive(paint.blend_mode) || !bounds.has_value()) { FML_CHECK(clip_coverage_stack_.HasCoverage()); // We should never hit this case as we check the intersection above. // NOLINTBEGIN(bugprone-unchecked-optional-access) @@ -418,6 +418,8 @@ void ExperimentalCanvas::SaveLayer( .Intersection(clip_coverage_stack_.CurrentClipCoverage().value()) .value(); // NOLINTEND(bugprone-unchecked-optional-access) + } else { + subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); } render_passes_.push_back(LazyRenderingConfig( From bbdec467d8d2aa218cc7122a9508a0251fbf8f79 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 30 Jul 2024 22:18:32 -0700 Subject: [PATCH 19/37] ++ --- impeller/aiks/experimental_canvas.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 26eb1d6474e43..4d55e94b9efe3 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -688,9 +688,8 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, .GetRenderTarget(); ColorAttachment attachment = render_target.GetColorAttachments().find(0u)->second; - attachment.clear_color = attachment.clear_color.Unpremultiply() - .Blend(color, entity.GetBlendMode()) - .Premultiply(); + attachment.clear_color = + attachment.clear_color.Blend(color, entity.GetBlendMode()); render_target.SetColorAttachment(attachment, 0u); } } From 35204a343ebd38c78ee500df612dcbbf40975b03 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 31 Jul 2024 11:00:04 -0700 Subject: [PATCH 20/37] more adjustments. --- impeller/aiks/aiks_playground.cc | 21 +++++++++++++++++---- impeller/aiks/experimental_canvas.cc | 7 +++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/impeller/aiks/aiks_playground.cc b/impeller/aiks/aiks_playground.cc index 82f76bf3372a4..882e0d66a99c2 100644 --- a/impeller/aiks/aiks_playground.cc +++ b/impeller/aiks/aiks_playground.cc @@ -75,10 +75,7 @@ bool AiksPlayground::ImGuiBegin(const char* name, bool AiksPlayground::OpenPlaygroundHere( const sk_sp& list) { - DlDispatcher dispatcher; - list->Dispatch(dispatcher); - Picture picture = dispatcher.EndRecordingAsPicture(); - return OpenPlaygroundHere(std::move(picture)); + return OpenPlaygroundHere([list]() { return list; }); } bool AiksPlayground::OpenPlaygroundHere( @@ -91,12 +88,28 @@ bool AiksPlayground::OpenPlaygroundHere( return Playground::OpenPlaygroundHere( [&renderer, &callback](RenderTarget& render_target) -> bool { +#if EXPERIMENTAL_CANVAS + auto display_list = callback(); + TextFrameDispatcher collector(renderer.GetContentContext(), Matrix()); + display_list->Dispatch(collector); + + ExperimentalDlDispatcher impeller_dispatcher( + renderer.GetContentContext(), render_target, + display_list->root_has_backdrop_filter(), + display_list->max_root_blend_mode(), IRect::MakeMaximum()); + display_list->Dispatch(impeller_dispatcher); + impeller_dispatcher.FinishRecording(); + renderer.GetContentContext().GetTransientsBuffer().Reset(); + renderer.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames(); + return true; +#else auto display_list = callback(); DlDispatcher dispatcher; display_list->Dispatch(dispatcher); Picture picture = dispatcher.EndRecordingAsPicture(); return renderer.Render(picture, render_target, true); +#endif // EXPERIMENTAL_CANVAS }); } diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 4d55e94b9efe3..084a983d78615 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -688,8 +688,11 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, .GetRenderTarget(); ColorAttachment attachment = render_target.GetColorAttachments().find(0u)->second; - attachment.clear_color = - attachment.clear_color.Blend(color, entity.GetBlendMode()); + // Attachment.clear color needs to be premultiplied at all times, but the + // Color::Blend function requires unpremultiplied colors. + attachment.clear_color = attachment.clear_color.Unpremultiply() + .Blend(color, entity.GetBlendMode()) + .Premultiply(); render_target.SetColorAttachment(attachment, 0u); } } From 50497ced8a07f1517185104af232d2ec79aa6d5f Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 9 Aug 2024 20:30:25 -0700 Subject: [PATCH 21/37] ++ --- impeller/display_list/dl_dispatcher.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 72c96acf8d6f0..06e91b69b3576 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -600,7 +600,7 @@ void DlDispatcherBase::saveLayer(const SkRect& bounds, ? ContentBoundsPromise::kMayClipContents : ContentBoundsPromise::kContainsContents; std::optional impeller_bounds; - if (!options.content_is_unbounded()) { + if (!options.content_is_unbounded() || options.bounds_from_caller()) { impeller_bounds = skia_conversions::ToRect(bounds); } From 464b21e221d7a3682623c9ca4c5bc3f14ef37e1a Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Fri, 9 Aug 2024 23:48:06 -0700 Subject: [PATCH 22/37] ++ --- impeller/display_list/dl_dispatcher.cc | 4 +++- impeller/golden_tests/golden_playground_test_mac.cc | 8 ++++---- impeller/renderer/backend/metal/surface_mtl.h | 4 ++-- impeller/renderer/backend/metal/surface_mtl.mm | 6 ++++-- shell/gpu/gpu_surface_metal_impeller.mm | 1 - 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 06e91b69b3576..787beab7020f2 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -1301,7 +1301,9 @@ void TextFrameDispatcher::drawTextFrame( properties.stroke_width = paint_.stroke_width; } if (text_frame->HasColor()) { - properties.color = paint_.color; + // Alpha is always applied when rendering, remove it here so + // we do not double-apply the alpha. + properties.color = paint_.color.WithAlpha(1.0); } auto scale = (matrix_ * Matrix::MakeTranslation(Point(x, y))).GetMaxBasisLengthXY(); diff --git a/impeller/golden_tests/golden_playground_test_mac.cc b/impeller/golden_tests/golden_playground_test_mac.cc index 9ed2de77db427..8893b4e7842b4 100644 --- a/impeller/golden_tests/golden_playground_test_mac.cc +++ b/impeller/golden_tests/golden_playground_test_mac.cc @@ -89,18 +89,18 @@ std::shared_ptr DisplayListToTexture( ); } + SkIRect sk_cull_rect = SkIRect::MakeWH(size.width, size.height); impeller::TextFrameDispatcher collector(context.GetContentContext(), impeller::Matrix()); - display_list->Dispatch( - collector, SkIRect::MakeSize(SkISize::Make(size.width, size.height))); + display_list->Dispatch(collector, sk_cull_rect); impeller::ExperimentalDlDispatcher impeller_dispatcher( context.GetContentContext(), target, display_list->root_has_backdrop_filter(), display_list->max_root_blend_mode(), impeller::IRect::MakeSize(size)); - display_list->Dispatch(impeller_dispatcher, SkIRect::MakeSize(SkISize::Make( - size.width, size.height))); + display_list->Dispatch(impeller_dispatcher, sk_cull_rect); impeller_dispatcher.FinishRecording(); + context.GetContentContext().GetTransientsBuffer().Reset(); context.GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames(); return target.GetRenderTargetTexture(); diff --git a/impeller/renderer/backend/metal/surface_mtl.h b/impeller/renderer/backend/metal/surface_mtl.h index bff5072f8fb8b..a9c9c8ec6c0d5 100644 --- a/impeller/renderer/backend/metal/surface_mtl.h +++ b/impeller/renderer/backend/metal/surface_mtl.h @@ -66,7 +66,7 @@ class SurfaceMTL final : public Surface { } /// @brief Perform the final blit and trigger end of frame workloads. - bool PreparePresent(); + bool PreparePresent() const; // |Surface| bool Present() const override; @@ -85,7 +85,7 @@ class SurfaceMTL final : public Surface { std::optional clip_rect_; bool frame_boundary_ = false; bool present_with_transaction_ = false; - bool prepared_ = false; + mutable bool prepared_ = false; static bool ShouldPerformPartialRepaint(std::optional damage_rect); diff --git a/impeller/renderer/backend/metal/surface_mtl.mm b/impeller/renderer/backend/metal/surface_mtl.mm index caa6804c8a42a..6299f4524f4f8 100644 --- a/impeller/renderer/backend/metal/surface_mtl.mm +++ b/impeller/renderer/backend/metal/surface_mtl.mm @@ -222,7 +222,7 @@ - (void)flutterPrepareForPresent:(nonnull id)commandBuffer; return IRect::MakeSize(resolve_texture_->GetSize()); } -bool SurfaceMTL::PreparePresent() { +bool SurfaceMTL::PreparePresent() const { auto context = context_.lock(); if (!context) { return false; @@ -265,7 +265,9 @@ - (void)flutterPrepareForPresent:(nonnull id)commandBuffer; // |Surface| bool SurfaceMTL::Present() const { - FML_CHECK(prepared_); + if (!prepared_) { + PreparePresent(); + } auto context = context_.lock(); if (!context) { return false; diff --git a/shell/gpu/gpu_surface_metal_impeller.mm b/shell/gpu/gpu_surface_metal_impeller.mm index 1b0f28ec748f0..6c6e4f9e9c17e 100644 --- a/shell/gpu/gpu_surface_metal_impeller.mm +++ b/shell/gpu/gpu_surface_metal_impeller.mm @@ -182,7 +182,6 @@ cull_rect); display_list->Dispatch(impeller_dispatcher, sk_cull_rect); impeller_dispatcher.FinishRecording(); - aiks_context->GetContentContext().GetTransientsBuffer().Reset(); aiks_context->GetContentContext().GetLazyGlyphAtlas()->ResetTextFrames(); if (reset_host_buffer) { aiks_context->GetContentContext().GetTransientsBuffer().Reset(); From 8324a61fddbf8e8aa98b583cc9473262e5a79a32 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 10 Aug 2024 09:49:26 -0700 Subject: [PATCH 23/37] ++ --- impeller/aiks/experimental_canvas.cc | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 084a983d78615..dabba34cd1e8d 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -322,14 +322,6 @@ void ExperimentalCanvas::SaveLayer( return; } - // // Can we always guarantee that we get a bounds? Does a lack of bounds - // // indicate something? - // if (!bounds.has_value()) { - // bounds = Rect::MakeSize(render_target_.GetRenderTargetSize()); - // } - - // SaveLayer is a no-op, depending on the bounds promise. Should/Can DL elide - // this? if (bounds.has_value() && bounds->IsEmpty()) { Save(total_content_depth); return; @@ -358,7 +350,8 @@ void ExperimentalCanvas::SaveLayer( auto coverage_limit = maybe_coverage_limit.value(); if (can_distribute_opacity && !backdrop_filter && - Paint::CanApplyOpacityPeephole(paint)) { + Paint::CanApplyOpacityPeephole(paint) && + bounds_promise != ContentBoundsPromise::kMayClipContents) { Save(total_content_depth); transform_stack_.back().distributed_opacity *= paint.color.alpha; return; From cbb19a4458add46aae544746037a7e16a4c79550 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 10 Aug 2024 10:14:28 -0700 Subject: [PATCH 24/37] bounds adjustment. --- impeller/aiks/experimental_canvas.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index dabba34cd1e8d..4efe09aabcf20 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -309,6 +309,11 @@ void ExperimentalCanvas::SaveLayer( bool can_distribute_opacity) { TRACE_EVENT0("flutter", "Canvas::saveLayer"); + // TODO(jonahwilliams): understand why we sometimes get empty bounds instead of nullopt bounds. + if (bounds.has_value() && bounds->IsEmpty()) { + bounds = std::nullopt; + } + if (!clip_coverage_stack_.HasCoverage()) { // The current clip is empty. This means the pass texture won't be // visible, so skip it. @@ -322,11 +327,6 @@ void ExperimentalCanvas::SaveLayer( return; } - if (bounds.has_value() && bounds->IsEmpty()) { - Save(total_content_depth); - return; - } - // The maximum coverage of the subpass. Subpasses textures should never // extend outside the parent pass texture or the current clip coverage. std::optional maybe_coverage_limit = From dc131c0ffad6921b45cd3649f8ac774a46716e30 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 10 Aug 2024 10:16:39 -0700 Subject: [PATCH 25/37] ++ --- impeller/aiks/experimental_canvas.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 4efe09aabcf20..b571d247b96fd 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -309,7 +309,8 @@ void ExperimentalCanvas::SaveLayer( bool can_distribute_opacity) { TRACE_EVENT0("flutter", "Canvas::saveLayer"); - // TODO(jonahwilliams): understand why we sometimes get empty bounds instead of nullopt bounds. + // TODO(jonahwilliams): understand why we sometimes get empty bounds instead + // of nullopt bounds. if (bounds.has_value() && bounds->IsEmpty()) { bounds = std::nullopt; } From 5414db387d3297f617e16bccfaa44ff096b22efa Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 10 Aug 2024 11:50:33 -0700 Subject: [PATCH 26/37] fix advanced blend coverage hint. --- impeller/aiks/experimental_canvas.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index b571d247b96fd..ab33859d4a4f7 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -720,12 +720,19 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, return; } + // The coverage hint tells the rendered Contents which portion of the + // rendered output will actually be used, and so we set this to the + // current clip coverage (which is the max clip bounds). The contents may + // optionally use this hint to avoid unnecessary rendering work. + auto element_coverage_hint = entity.GetContents()->GetCoverageHint(); + entity.GetContents()->SetCoverageHint(Rect::Intersection( + element_coverage_hint, clip_coverage_stack_.CurrentClipCoverage())); + FilterInput::Vector inputs = { FilterInput::Make(input_texture, entity.GetTransform().Invert()), FilterInput::Make(entity.GetContents())}; auto contents = ColorFilterContents::MakeBlend(entity.GetBlendMode(), inputs); - contents->SetCoverageHint(entity.GetCoverage()); entity.SetContents(std::move(contents)); entity.SetBlendMode(BlendMode::kSource); } From ca34138fb41b3b61823234c35f09ab507051bd26 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 10 Aug 2024 13:58:44 -0700 Subject: [PATCH 27/37] Add missing return. --- impeller/aiks/experimental_canvas.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index ab33859d4a4f7..81f4ec06bcf3c 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -688,6 +688,7 @@ void ExperimentalCanvas::AddRenderEntityToCurrentPass(Entity entity, .Blend(color, entity.GetBlendMode()) .Premultiply(); render_target.SetColorAttachment(attachment, 0u); + return; } } From 2c6f55e34ed1c5e7ec69cefda287ea8431aebc21 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 10 Aug 2024 14:24:34 -0700 Subject: [PATCH 28/37] force final rp construction. --- impeller/aiks/experimental_canvas.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 81f4ec06bcf3c..fef77a4890b31 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -865,6 +865,7 @@ bool ExperimentalCanvas::BlitToOnscreen() { void ExperimentalCanvas::EndReplay() { FML_DCHECK(render_passes_.size() == 1u); + render_passes_.back().inline_pass_context->GetRenderPass(0); render_passes_.back().inline_pass_context->EndPass(); // If requires_readback_ was true, then we rendered to an offscreen texture From 1236b733c4042225183e7207e5ff7b6952f3bfe5 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Sat, 10 Aug 2024 16:14:16 -0700 Subject: [PATCH 29/37] ++ --- impeller/aiks/experimental_canvas.cc | 3 ++- impeller/display_list/aiks_dl_unittests.cc | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index fef77a4890b31..f0ab00974f439 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -495,7 +495,8 @@ bool ExperimentalCanvas::Restore() { PaintPassDelegate(save_layer_state.paint) .CreateContentsForSubpassTarget( lazy_render_pass.inline_pass_context->GetTexture(), - transform_stack_.back().transform); + Matrix::MakeTranslation(Vector3{-GetGlobalPassPosition()}) * + transform_stack_.back().transform); lazy_render_pass.inline_pass_context->EndPass(); diff --git a/impeller/display_list/aiks_dl_unittests.cc b/impeller/display_list/aiks_dl_unittests.cc index e8cf7326bcd90..f565b8b6a7214 100644 --- a/impeller/display_list/aiks_dl_unittests.cc +++ b/impeller/display_list/aiks_dl_unittests.cc @@ -771,7 +771,7 @@ TEST_P(AiksTest, MatrixSaveLayerFilter) { DlPaint paint; paint.setColor(DlColor::kBlack()); builder.DrawPaint(paint); - builder.SaveLayer({}, nullptr); + builder.SaveLayer(nullptr, nullptr); { paint.setColor(DlColor::kGreen().withAlpha(255 * 0.5)); paint.setBlendMode(DlBlendMode::kPlus); From 630bb36d590649c1e535b8208b374887d20392fb Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 13 Aug 2024 09:57:28 -0700 Subject: [PATCH 30/37] ++ --- impeller/aiks/experimental_canvas.cc | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index f0ab00974f439..add8062768010 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -322,11 +322,12 @@ void ExperimentalCanvas::SaveLayer( return; } - auto clip_coverage_back = clip_coverage_stack_.CurrentClipCoverage(); - if (!clip_coverage_back.has_value()) { + auto maybe_current_clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); + if (!maybe_current_clip_coverage.has_value()) { Save(total_content_depth); return; } + auto current_clip_coverage = maybe_current_clip_coverage.value(); // The maximum coverage of the subpass. Subpasses textures should never // extend outside the parent pass texture or the current clip coverage. @@ -335,7 +336,7 @@ void ExperimentalCanvas::SaveLayer( Size(render_passes_.back() .inline_pass_context->GetTexture() ->GetSize())) - .Intersection(clip_coverage_back.value()); + .Intersection(current_clip_coverage); if (!maybe_coverage_limit.has_value()) { Save(total_content_depth); @@ -362,11 +363,8 @@ void ExperimentalCanvas::SaveLayer( std::shared_ptr backdrop_filter_contents; Point local_position = {0, 0}; if (backdrop_filter) { - auto current_clip_coverage = clip_coverage_stack_.CurrentClipCoverage(); - if (current_clip_coverage.has_value()) { - local_position = - current_clip_coverage->GetOrigin() - GetGlobalPassPosition(); - } + local_position = + current_clip_coverage.GetOrigin() - GetGlobalPassPosition(); EntityPass::BackdropFilterProc backdrop_filter_proc = [backdrop_filter = backdrop_filter->Clone()]( const FilterInput::Ref& input, const Matrix& effect_transform, @@ -405,13 +403,12 @@ void ExperimentalCanvas::SaveLayer( if (backdrop_filter_contents || Entity::IsBlendModeDestructive(paint.blend_mode) || !bounds.has_value()) { FML_CHECK(clip_coverage_stack_.HasCoverage()); - // We should never hit this case as we check the intersection above. - // NOLINTBEGIN(bugprone-unchecked-optional-access) subpass_coverage = - coverage_limit - .Intersection(clip_coverage_stack_.CurrentClipCoverage().value()) - .value(); - // NOLINTEND(bugprone-unchecked-optional-access) + coverage_limit.Intersection(current_clip_coverage).value(); + // Clip tight bounds, even if clip is flooded. + if (bounds.has_value()) { + subpass_coverage = coverage_limit.Intersection(bounds.value()).value(); + } } else { subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); } From 86600bffe064341b2810048e23210af75ebfcff7 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Tue, 13 Aug 2024 17:39:47 -0700 Subject: [PATCH 31/37] ++ --- impeller/display_list/aiks_dl_unittests.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/impeller/display_list/aiks_dl_unittests.cc b/impeller/display_list/aiks_dl_unittests.cc index f565b8b6a7214..4aa538b26ffdb 100644 --- a/impeller/display_list/aiks_dl_unittests.cc +++ b/impeller/display_list/aiks_dl_unittests.cc @@ -748,6 +748,12 @@ TEST_P(AiksTest, MatrixBackdropFilter) { DlPaint paint; paint.setColor(DlColor::kGreen().withAlpha(0.5 * 255)); paint.setBlendMode(DlBlendMode::kPlus); + + DlPaint rect_paint; + rect_paint.setColor(DlColor::kRed()); + rect_paint.setStrokeWidth(4); + rect_paint.setDrawStyle(DlDrawStyle::kStroke); + builder.DrawRect(SkRect::MakeLTRB(0, 0, 300, 300), rect_paint); builder.DrawCircle(SkPoint::Make(200, 200), 100, paint); // Should render a second circle, centered on the bottom-right-most edge of // the circle. From d11a4acc47f85b3fd4daf738e42902befba888b4 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 13:12:54 -0700 Subject: [PATCH 32/37] fix stroked text. --- impeller/aiks/experimental_canvas.cc | 16 ++++++++++------ impeller/display_list/dl_dispatcher.cc | 4 ++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index add8062768010..5a30c154d6d11 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -309,10 +309,14 @@ void ExperimentalCanvas::SaveLayer( bool can_distribute_opacity) { TRACE_EVENT0("flutter", "Canvas::saveLayer"); - // TODO(jonahwilliams): understand why we sometimes get empty bounds instead - // of nullopt bounds. + // Empty bounds on a save layer that contains a BDF should be treated as + // unbounded. if (bounds.has_value() && bounds->IsEmpty()) { - bounds = std::nullopt; + if (backdrop_filter != nullptr) { + bounds = std::nullopt; + } else { + Save(total_content_depth); + } } if (!clip_coverage_stack_.HasCoverage()) { @@ -403,11 +407,11 @@ void ExperimentalCanvas::SaveLayer( if (backdrop_filter_contents || Entity::IsBlendModeDestructive(paint.blend_mode) || !bounds.has_value()) { FML_CHECK(clip_coverage_stack_.HasCoverage()); - subpass_coverage = - coverage_limit.Intersection(current_clip_coverage).value(); + subpass_coverage = coverage_limit; // Clip tight bounds, even if clip is flooded. if (bounds.has_value()) { - subpass_coverage = coverage_limit.Intersection(bounds.value()).value(); + subpass_coverage = + coverage_limit.Intersection(bounds.value()).value_or(bounds.value()); } } else { subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 787beab7020f2..1ab37505a4640 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -1102,6 +1102,7 @@ void DlDispatcherBase::drawTextBlob(const sk_sp blob, UNIMPLEMENTED; } +// |flutter::DlOpReceiver| void DlDispatcherBase::drawTextFrame( const std::shared_ptr& text_frame, SkScalar x, @@ -1319,8 +1320,11 @@ void TextFrameDispatcher::drawDisplayList( SkScalar opacity) { [[maybe_unused]] size_t stack_depth = stack_.size(); save(); + Paint old_paint = paint_; + paint_ = Paint{}; display_list->Dispatch(*this); restore(); + paint_ = old_paint; FML_DCHECK(stack_depth == stack_.size()); } From c3a64cf80a2c645fd1a8ddb4bb91c2725939a0fc Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 18:32:33 -0700 Subject: [PATCH 33/37] adjust more things. --- impeller/aiks/experimental_canvas.cc | 9 ++------- impeller/display_list/dl_dispatcher.cc | 8 ++++++++ impeller/entity/entity.cc | 1 + 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 5a30c154d6d11..c7973c4260c02 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -309,14 +309,9 @@ void ExperimentalCanvas::SaveLayer( bool can_distribute_opacity) { TRACE_EVENT0("flutter", "Canvas::saveLayer"); - // Empty bounds on a save layer that contains a BDF should be treated as - // unbounded. if (bounds.has_value() && bounds->IsEmpty()) { - if (backdrop_filter != nullptr) { - bounds = std::nullopt; - } else { - Save(total_content_depth); - } + Save(total_content_depth); + return; } if (!clip_coverage_stack_.HasCoverage()) { diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 1ab37505a4640..60df1aad52ee3 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -604,6 +604,14 @@ void DlDispatcherBase::saveLayer(const SkRect& bounds, impeller_bounds = skia_conversions::ToRect(bounds); } + // Empty bounds on a save layer that contains a BDF or destructive blend + // should be treated as unbounded. All other empty bounds can be skipped. + if (impeller_bounds.has_value() && impeller_bounds->IsEmpty() && + (backdrop != nullptr || + Entity::IsBlendModeDestructive(paint.blend_mode))) { + impeller_bounds = std::nullopt; + } + GetCanvas().SaveLayer(paint, impeller_bounds, ToImageFilter(backdrop), promise, total_content_depth, options.can_distribute_opacity()); diff --git a/impeller/entity/entity.cc b/impeller/entity/entity.cc index cb336892d3a61..29d4c7445894e 100644 --- a/impeller/entity/entity.cc +++ b/impeller/entity/entity.cc @@ -164,6 +164,7 @@ bool Entity::IsBlendModeDestructive(BlendMode blend_mode) { case BlendMode::kDestinationATop: case BlendMode::kXor: case BlendMode::kModulate: + case BlendMode::kDestinationOver: return true; default: return false; From 02b7834cf81bcf36230656244857c606be96963d Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 18:34:01 -0700 Subject: [PATCH 34/37] ++ --- impeller/entity/entity.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/impeller/entity/entity.cc b/impeller/entity/entity.cc index 29d4c7445894e..cb336892d3a61 100644 --- a/impeller/entity/entity.cc +++ b/impeller/entity/entity.cc @@ -164,7 +164,6 @@ bool Entity::IsBlendModeDestructive(BlendMode blend_mode) { case BlendMode::kDestinationATop: case BlendMode::kXor: case BlendMode::kModulate: - case BlendMode::kDestinationOver: return true; default: return false; From 3899c5824bdc4841ae19b293728b8b98fbfbf215 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Wed, 14 Aug 2024 20:07:16 -0700 Subject: [PATCH 35/37] ++ --- impeller/aiks/canvas.cc | 3 ++- impeller/aiks/canvas.h | 3 ++- impeller/aiks/experimental_canvas.cc | 5 +++-- impeller/aiks/experimental_canvas.h | 3 ++- impeller/display_list/dl_dispatcher.cc | 3 ++- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/impeller/aiks/canvas.cc b/impeller/aiks/canvas.cc index 2b709fdc83159..37be4bfd7aa23 100644 --- a/impeller/aiks/canvas.cc +++ b/impeller/aiks/canvas.cc @@ -807,7 +807,8 @@ void Canvas::SaveLayer(const Paint& paint, const std::shared_ptr& backdrop_filter, ContentBoundsPromise bounds_promise, uint32_t total_content_depth, - bool can_distribute_opacity) { + bool can_distribute_opacity, + bool bounds_from_caller) { if (can_distribute_opacity && !backdrop_filter && Paint::CanApplyOpacityPeephole(paint) && bounds_promise != ContentBoundsPromise::kMayClipContents) { diff --git a/impeller/aiks/canvas.h b/impeller/aiks/canvas.h index e5bdc379b0622..834b3d118e1e2 100644 --- a/impeller/aiks/canvas.h +++ b/impeller/aiks/canvas.h @@ -77,7 +77,8 @@ class Canvas { const std::shared_ptr& backdrop_filter = nullptr, ContentBoundsPromise bounds_promise = ContentBoundsPromise::kUnknown, uint32_t total_content_depth = kMaxDepth, - bool can_distribute_opacity = false); + bool can_distribute_opacity = false, + bool bounds_from_caller = false); virtual bool Restore(); diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index c7973c4260c02..839b2d5e35877 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -306,7 +306,8 @@ void ExperimentalCanvas::SaveLayer( const std::shared_ptr& backdrop_filter, ContentBoundsPromise bounds_promise, uint32_t total_content_depth, - bool can_distribute_opacity) { + bool can_distribute_opacity, + bool bounds_from_caller) { TRACE_EVENT0("flutter", "Canvas::saveLayer"); if (bounds.has_value() && bounds->IsEmpty()) { @@ -404,7 +405,7 @@ void ExperimentalCanvas::SaveLayer( FML_CHECK(clip_coverage_stack_.HasCoverage()); subpass_coverage = coverage_limit; // Clip tight bounds, even if clip is flooded. - if (bounds.has_value()) { + if (bounds.has_value() && bounds_from_caller) { subpass_coverage = coverage_limit.Intersection(bounds.value()).value_or(bounds.value()); } diff --git a/impeller/aiks/experimental_canvas.h b/impeller/aiks/experimental_canvas.h index debb4baf088fc..8ec5e18b7c1e2 100644 --- a/impeller/aiks/experimental_canvas.h +++ b/impeller/aiks/experimental_canvas.h @@ -71,7 +71,8 @@ class ExperimentalCanvas : public Canvas { const std::shared_ptr& backdrop_filter, ContentBoundsPromise bounds_promise, uint32_t total_content_depth, - bool can_distribute_opacity) override; + bool can_distribute_opacity, + bool bounds_from_caller) override; bool Restore() override; diff --git a/impeller/display_list/dl_dispatcher.cc b/impeller/display_list/dl_dispatcher.cc index 60df1aad52ee3..eda382ba07de8 100644 --- a/impeller/display_list/dl_dispatcher.cc +++ b/impeller/display_list/dl_dispatcher.cc @@ -614,7 +614,8 @@ void DlDispatcherBase::saveLayer(const SkRect& bounds, GetCanvas().SaveLayer(paint, impeller_bounds, ToImageFilter(backdrop), promise, total_content_depth, - options.can_distribute_opacity()); + options.can_distribute_opacity(), + options.bounds_from_caller()); } // |flutter::DlOpReceiver| From 3e21b07169ceb80a420e9275d37a5834934f31cd Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 15 Aug 2024 08:32:34 -0700 Subject: [PATCH 36/37] remove incorrect clip --- impeller/aiks/experimental_canvas.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/impeller/aiks/experimental_canvas.cc b/impeller/aiks/experimental_canvas.cc index 839b2d5e35877..b9cd19a12afcd 100644 --- a/impeller/aiks/experimental_canvas.cc +++ b/impeller/aiks/experimental_canvas.cc @@ -402,13 +402,12 @@ void ExperimentalCanvas::SaveLayer( Rect subpass_coverage; if (backdrop_filter_contents || Entity::IsBlendModeDestructive(paint.blend_mode) || !bounds.has_value()) { - FML_CHECK(clip_coverage_stack_.HasCoverage()); subpass_coverage = coverage_limit; - // Clip tight bounds, even if clip is flooded. - if (bounds.has_value() && bounds_from_caller) { - subpass_coverage = - coverage_limit.Intersection(bounds.value()).value_or(bounds.value()); - } + // TODO(jonahwilliams): if we have tight bounds we should be able to reduce + // this size here. if (bounds.has_value() && bounds_from_caller) { + // subpass_coverage = + // coverage_limit.Intersection(bounds.value()).value_or(bounds.value()); + // } } else { subpass_coverage = bounds->TransformBounds(GetCurrentTransform()); } From c2b89385d867b36595aa40a4a5f0ec0739cebf00 Mon Sep 17 00:00:00 2001 From: jonahwilliams Date: Thu, 15 Aug 2024 08:39:51 -0700 Subject: [PATCH 37/37] remove test opt outs. --- impeller/aiks/aiks_unittests.cc | 119 +++++++++--------- .../gpu_surface_metal_impeller_unittests.mm | 81 ++++++------ 2 files changed, 99 insertions(+), 101 deletions(-) diff --git a/impeller/aiks/aiks_unittests.cc b/impeller/aiks/aiks_unittests.cc index 828904bee71eb..2919c78604e4a 100644 --- a/impeller/aiks/aiks_unittests.cc +++ b/impeller/aiks/aiks_unittests.cc @@ -242,66 +242,65 @@ TEST_P(AiksTest, DrawRectAbsorbsClears) { ASSERT_EQ(render_pass->GetCommands().size(), 0llu); } -// TEST_P(AiksTest, DrawRectAbsorbsClearsNegativeRRect) { -// Canvas canvas; -// canvas.DrawRRect(Rect::MakeXYWH(0, 0, 300, 300), {5.0, 5.0}, -// {.color = Color::Red(), .blend_mode = -// BlendMode::kSource}); -// canvas.DrawRRect(Rect::MakeXYWH(0, 0, 300, 300), {5.0, 5.0}, -// {.color = Color::CornflowerBlue().WithAlpha(0.75), -// .blend_mode = BlendMode::kSourceOver}); - -// std::shared_ptr spy = ContextSpy::Make(); -// Picture picture = canvas.EndRecordingAsPicture(); -// std::shared_ptr real_context = GetContext(); -// std::shared_ptr mock_context = spy->MakeContext(real_context); -// AiksContext renderer(mock_context, nullptr); -// std::shared_ptr image = picture.ToImage(renderer, {300, 300}); - -// ASSERT_EQ(spy->render_passes_.size(), 1llu); -// std::shared_ptr render_pass = spy->render_passes_[0]; -// ASSERT_EQ(render_pass->GetCommands().size(), 2llu); -// } - -// TEST_P(AiksTest, DrawRectAbsorbsClearsNegativeRotation) { -// Canvas canvas; -// canvas.Translate(Vector3(150.0, 150.0, 0.0)); -// canvas.Rotate(Degrees(45.0)); -// canvas.Translate(Vector3(-150.0, -150.0, 0.0)); -// canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), -// {.color = Color::Red(), .blend_mode = BlendMode::kSource}); - -// std::shared_ptr spy = ContextSpy::Make(); -// Picture picture = canvas.EndRecordingAsPicture(); -// std::shared_ptr real_context = GetContext(); -// std::shared_ptr mock_context = spy->MakeContext(real_context); -// AiksContext renderer(mock_context, nullptr); -// std::shared_ptr image = picture.ToImage(renderer, {300, 300}); - -// ASSERT_EQ(spy->render_passes_.size(), 1llu); -// std::shared_ptr render_pass = spy->render_passes_[0]; -// ASSERT_EQ(render_pass->GetCommands().size(), 1llu); -// } - -// TEST_P(AiksTest, DrawRectAbsorbsClearsNegative) { -// Canvas canvas; -// canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), -// {.color = Color::Red(), .blend_mode = BlendMode::kSource}); -// canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), -// {.color = Color::CornflowerBlue().WithAlpha(0.75), -// .blend_mode = BlendMode::kSourceOver}); - -// std::shared_ptr spy = ContextSpy::Make(); -// Picture picture = canvas.EndRecordingAsPicture(); -// std::shared_ptr real_context = GetContext(); -// std::shared_ptr mock_context = spy->MakeContext(real_context); -// AiksContext renderer(mock_context, nullptr); -// std::shared_ptr image = picture.ToImage(renderer, {301, 301}); - -// ASSERT_EQ(spy->render_passes_.size(), 1llu); -// std::shared_ptr render_pass = spy->render_passes_[0]; -// ASSERT_EQ(render_pass->GetCommands().size(), 2llu); -// } +TEST_P(AiksTest, DrawRectAbsorbsClearsNegativeRRect) { + Canvas canvas; + canvas.DrawRRect(Rect::MakeXYWH(0, 0, 300, 300), {5.0, 5.0}, + {.color = Color::Red(), .blend_mode = BlendMode::kSource}); + canvas.DrawRRect(Rect::MakeXYWH(0, 0, 300, 300), {5.0, 5.0}, + {.color = Color::CornflowerBlue().WithAlpha(0.75), + .blend_mode = BlendMode::kSourceOver}); + + std::shared_ptr spy = ContextSpy::Make(); + Picture picture = canvas.EndRecordingAsPicture(); + std::shared_ptr real_context = GetContext(); + std::shared_ptr mock_context = spy->MakeContext(real_context); + AiksContext renderer(mock_context, nullptr); + std::shared_ptr image = picture.ToImage(renderer, {300, 300}); + + ASSERT_EQ(spy->render_passes_.size(), 1llu); + std::shared_ptr render_pass = spy->render_passes_[0]; + ASSERT_EQ(render_pass->GetCommands().size(), 2llu); +} + +TEST_P(AiksTest, DrawRectAbsorbsClearsNegativeRotation) { + Canvas canvas; + canvas.Translate(Vector3(150.0, 150.0, 0.0)); + canvas.Rotate(Degrees(45.0)); + canvas.Translate(Vector3(-150.0, -150.0, 0.0)); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), + {.color = Color::Red(), .blend_mode = BlendMode::kSource}); + + std::shared_ptr spy = ContextSpy::Make(); + Picture picture = canvas.EndRecordingAsPicture(); + std::shared_ptr real_context = GetContext(); + std::shared_ptr mock_context = spy->MakeContext(real_context); + AiksContext renderer(mock_context, nullptr); + std::shared_ptr image = picture.ToImage(renderer, {300, 300}); + + ASSERT_EQ(spy->render_passes_.size(), 1llu); + std::shared_ptr render_pass = spy->render_passes_[0]; + ASSERT_EQ(render_pass->GetCommands().size(), 1llu); +} + +TEST_P(AiksTest, DrawRectAbsorbsClearsNegative) { + Canvas canvas; + canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), + {.color = Color::Red(), .blend_mode = BlendMode::kSource}); + canvas.DrawRect(Rect::MakeXYWH(0, 0, 300, 300), + {.color = Color::CornflowerBlue().WithAlpha(0.75), + .blend_mode = BlendMode::kSourceOver}); + + std::shared_ptr spy = ContextSpy::Make(); + Picture picture = canvas.EndRecordingAsPicture(); + std::shared_ptr real_context = GetContext(); + std::shared_ptr mock_context = spy->MakeContext(real_context); + AiksContext renderer(mock_context, nullptr); + std::shared_ptr image = picture.ToImage(renderer, {301, 301}); + + ASSERT_EQ(spy->render_passes_.size(), 1llu); + std::shared_ptr render_pass = spy->render_passes_[0]; + ASSERT_EQ(render_pass->GetCommands().size(), 2llu); +} TEST_P(AiksTest, ClipRectElidesNoOpClips) { Canvas canvas(Rect::MakeXYWH(0, 0, 100, 100)); diff --git a/shell/gpu/gpu_surface_metal_impeller_unittests.mm b/shell/gpu/gpu_surface_metal_impeller_unittests.mm index 94bde0eb25fc5..a5927ff035783 100644 --- a/shell/gpu/gpu_surface_metal_impeller_unittests.mm +++ b/shell/gpu/gpu_surface_metal_impeller_unittests.mm @@ -97,63 +97,62 @@ GPUCAMetalLayerHandle GetCAMetalLayer(const SkISize& frame_info) const override ASSERT_TRUE(frame->Submit()); } -// TESTING! -// TEST(GPUSurfaceMetalImpeller, ResetHostBufferBasedOnFrameBoundary) { -// auto delegate = std::make_shared(); -// delegate->SetDevice(); +TEST(GPUSurfaceMetalImpeller, ResetHostBufferBasedOnFrameBoundary) { + auto delegate = std::make_shared(); + delegate->SetDevice(); -// auto context = CreateImpellerContext(); -// std::unique_ptr surface = -// std::make_unique(delegate.get(), context); + auto context = CreateImpellerContext(); + std::unique_ptr surface = + std::make_unique(delegate.get(), context); -// ASSERT_TRUE(surface->IsValid()); + ASSERT_TRUE(surface->IsValid()); -// auto& host_buffer = surface->GetAiksContext()->GetContentContext().GetTransientsBuffer(); + auto& host_buffer = surface->GetAiksContext()->GetContentContext().GetTransientsBuffer(); -// EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); + EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); -// auto frame = surface->AcquireFrame(SkISize::Make(100, 100)); -// frame->set_submit_info({.frame_boundary = false}); + auto frame = surface->AcquireFrame(SkISize::Make(100, 100)); + frame->set_submit_info({.frame_boundary = false}); -// ASSERT_TRUE(frame->Submit()); -// EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); + ASSERT_TRUE(frame->Submit()); + EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 0u); -// frame = surface->AcquireFrame(SkISize::Make(100, 100)); -// frame->set_submit_info({.frame_boundary = true}); + frame = surface->AcquireFrame(SkISize::Make(100, 100)); + frame->set_submit_info({.frame_boundary = true}); -// ASSERT_TRUE(frame->Submit()); -// EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); -// } + ASSERT_TRUE(frame->Submit()); + EXPECT_EQ(host_buffer.GetStateForTest().current_frame, 1u); +} -// #ifdef IMPELLER_DEBUG -// TEST(GPUSurfaceMetalImpeller, CreatesImpellerCaptureScope) { -// auto delegate = std::make_shared(); -// delegate->SetDevice(); +#ifdef IMPELLER_DEBUG +TEST(GPUSurfaceMetalImpeller, CreatesImpellerCaptureScope) { + auto delegate = std::make_shared(); + delegate->SetDevice(); -// auto context = CreateImpellerContext(); + auto context = CreateImpellerContext(); -// EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive()); + EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive()); -// std::unique_ptr surface = -// std::make_unique(delegate.get(), context); -// auto frame_1 = surface->AcquireFrame(SkISize::Make(100, 100)); -// frame_1->set_submit_info({.frame_boundary = false}); + std::unique_ptr surface = + std::make_unique(delegate.get(), context); + auto frame_1 = surface->AcquireFrame(SkISize::Make(100, 100)); + frame_1->set_submit_info({.frame_boundary = false}); -// EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); + EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); -// std::unique_ptr surface_2 = -// std::make_unique(delegate.get(), context); -// auto frame_2 = surface->AcquireFrame(SkISize::Make(100, 100)); -// frame_2->set_submit_info({.frame_boundary = true}); + std::unique_ptr surface_2 = + std::make_unique(delegate.get(), context); + auto frame_2 = surface->AcquireFrame(SkISize::Make(100, 100)); + frame_2->set_submit_info({.frame_boundary = true}); -// EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); + EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); -// ASSERT_TRUE(frame_1->Submit()); -// EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); -// ASSERT_TRUE(frame_2->Submit()); -// EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive()); -// } -// #endif // IMPELLER_DEBUG + ASSERT_TRUE(frame_1->Submit()); + EXPECT_TRUE(context->GetCaptureManager()->CaptureScopeActive()); + ASSERT_TRUE(frame_2->Submit()); + EXPECT_FALSE(context->GetCaptureManager()->CaptureScopeActive()); +} +#endif // IMPELLER_DEBUG } // namespace testing } // namespace flutter