From fdfdd6dccb762222b9cd5485a6253c70f7f4603e Mon Sep 17 00:00:00 2001 From: eggfly Date: Sun, 5 Dec 2021 22:59:01 +0800 Subject: [PATCH] Fix embedder_->EndFrame() not called in case of DrawLastLayerTree() (flutter/engine#29979) --- engine/src/flutter/shell/common/rasterizer.cc | 21 ++++-- engine/src/flutter/shell/common/rasterizer.h | 1 + .../shell/common/rasterizer_unittests.cc | 74 +++++++++++++++++++ .../flutter/shell/platform/android/BUILD.gn | 10 --- 4 files changed, 91 insertions(+), 15 deletions(-) diff --git a/engine/src/flutter/shell/common/rasterizer.cc b/engine/src/flutter/shell/common/rasterizer.cc index f937f5fe591..e52a814fb8a 100644 --- a/engine/src/flutter/shell/common/rasterizer.cc +++ b/engine/src/flutter/shell/common/rasterizer.cc @@ -147,7 +147,15 @@ void Rasterizer::DrawLastLayerTree( if (!last_layer_tree_ || !surface_) { return; } - DrawToSurface(*frame_timings_recorder, *last_layer_tree_); + RasterStatus raster_status = + DrawToSurface(*frame_timings_recorder, *last_layer_tree_); + + // EndFrame should perform cleanups for the external_view_embedder. + if (external_view_embedder_) { + bool should_resubmit_frame = ShouldResubmitFrame(raster_status); + external_view_embedder_->EndFrame(should_resubmit_frame, + raster_thread_merger_); + } } RasterStatus Rasterizer::Draw( @@ -184,8 +192,7 @@ RasterStatus Rasterizer::Draw( // if the raster status is to resubmit the frame, we push the frame to the // front of the queue and also change the consume status to more available. - auto should_resubmit_frame = raster_status == RasterStatus::kResubmit || - raster_status == RasterStatus::kSkipAndRetry; + bool should_resubmit_frame = ShouldResubmitFrame(raster_status); if (should_resubmit_frame) { auto front_continuation = pipeline->ProduceIfEmpty(); bool result = @@ -226,6 +233,11 @@ RasterStatus Rasterizer::Draw( return raster_status; } +bool Rasterizer::ShouldResubmitFrame(const RasterStatus& raster_status) { + return raster_status == RasterStatus::kResubmit || + raster_status == RasterStatus::kSkipAndRetry; +} + namespace { sk_sp DrawSnapshot( sk_sp surface, @@ -387,8 +399,7 @@ RasterStatus Rasterizer::DoDraw( DrawToSurface(*frame_timings_recorder, *layer_tree); if (raster_status == RasterStatus::kSuccess) { last_layer_tree_ = std::move(layer_tree); - } else if (raster_status == RasterStatus::kResubmit || - raster_status == RasterStatus::kSkipAndRetry) { + } else if (ShouldResubmitFrame(raster_status)) { resubmitted_layer_tree_ = std::move(layer_tree); return raster_status; } else if (raster_status == RasterStatus::kDiscarded) { diff --git a/engine/src/flutter/shell/common/rasterizer.h b/engine/src/flutter/shell/common/rasterizer.h index 6fe2ffb5f9e..fb381cc0f9a 100644 --- a/engine/src/flutter/shell/common/rasterizer.h +++ b/engine/src/flutter/shell/common/rasterizer.h @@ -483,6 +483,7 @@ class Rasterizer final : public SnapshotDelegate { void FireNextFrameCallbackIfPresent(); static bool NoDiscard(const flutter::LayerTree& layer_tree) { return false; } + static bool ShouldResubmitFrame(const RasterStatus& raster_status); Delegate& delegate_; std::unique_ptr surface_; diff --git a/engine/src/flutter/shell/common/rasterizer_unittests.cc b/engine/src/flutter/shell/common/rasterizer_unittests.cc index 78f96ed36a9..7190b8cf448 100644 --- a/engine/src/flutter/shell/common/rasterizer_unittests.cc +++ b/engine/src/flutter/shell/common/rasterizer_unittests.cc @@ -300,6 +300,80 @@ TEST( rasterizer->Draw(CreateFinishedBuildRecorder(), pipeline, no_discard); } +TEST(RasterizerTest, + drawLastLayerTreeWithThreadsMergedExternalViewEmbedderAndEndFrameCalled) { + std::string test_name = + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + ThreadHost thread_host("io.flutter.test." + test_name + ".", + ThreadHost::Type::Platform | ThreadHost::Type::RASTER | + ThreadHost::Type::IO | ThreadHost::Type::UI); + fml::MessageLoop::EnsureInitializedForCurrentThread(); + TaskRunners task_runners("test", + fml::MessageLoop::GetCurrent().GetTaskRunner(), + fml::MessageLoop::GetCurrent().GetTaskRunner(), + thread_host.ui_thread->GetTaskRunner(), + thread_host.io_thread->GetTaskRunner()); + + MockDelegate delegate; + EXPECT_CALL(delegate, GetTaskRunners()) + .WillRepeatedly(ReturnRef(task_runners)); + EXPECT_CALL(delegate, OnFrameRasterized(_)); + + auto rasterizer = std::make_unique(delegate); + auto surface = std::make_unique(); + + std::shared_ptr external_view_embedder = + std::make_shared(); + rasterizer->SetExternalViewEmbedder(external_view_embedder); + + SurfaceFrame::FramebufferInfo framebuffer_info; + framebuffer_info.supports_readback = true; + + auto surface_frame1 = std::make_unique( + /*surface=*/nullptr, framebuffer_info, + /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }); + auto surface_frame2 = std::make_unique( + /*surface=*/nullptr, framebuffer_info, + /*submit_callback=*/[](const SurfaceFrame&, SkCanvas*) { return true; }); + EXPECT_CALL(*surface, AllowsDrawingWhenGpuDisabled()) + .WillRepeatedly(Return(true)); + // Prepare two frames for Draw() and DrawLastLayerTree(). + EXPECT_CALL(*surface, AcquireFrame(SkISize())) + .WillOnce(Return(ByMove(std::move(surface_frame1)))) + .WillOnce(Return(ByMove(std::move(surface_frame2)))); + EXPECT_CALL(*surface, MakeRenderContextCurrent()) + .WillOnce(Return(ByMove(std::make_unique(true)))); + EXPECT_CALL(*external_view_embedder, SupportsDynamicThreadMerging) + .WillRepeatedly(Return(true)); + + EXPECT_CALL(*external_view_embedder, + BeginFrame(/*frame_size=*/SkISize(), /*context=*/nullptr, + /*device_pixel_ratio=*/2.0, + /*raster_thread_merger=*/_)) + .Times(2); + EXPECT_CALL(*external_view_embedder, SubmitFrame).Times(2); + EXPECT_CALL(*external_view_embedder, EndFrame(/*should_resubmit_frame=*/false, + /*raster_thread_merger=*/_)) + .Times(2); + + rasterizer->Setup(std::move(surface)); + + auto pipeline = std::make_shared>(/*depth=*/10); + auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + /*device_pixel_ratio=*/2.0f); + bool result = pipeline->Produce().Complete(std::move(layer_tree)); + EXPECT_TRUE(result); + auto no_discard = [](LayerTree&) { return false; }; + + // The Draw() will respectively call BeginFrame(), SubmitFrame() and + // EndFrame() one time. + rasterizer->Draw(CreateFinishedBuildRecorder(), pipeline, no_discard); + + // The DrawLastLayerTree() will respectively call BeginFrame(), SubmitFrame() + // and EndFrame() one more time, totally 2 times. + rasterizer->DrawLastLayerTree(CreateFinishedBuildRecorder()); +} + TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) { std::string test_name = ::testing::UnitTest::GetInstance()->current_test_info()->name(); diff --git a/engine/src/flutter/shell/platform/android/BUILD.gn b/engine/src/flutter/shell/platform/android/BUILD.gn index 19c2e794687..fa1b3fb948a 100644 --- a/engine/src/flutter/shell/platform/android/BUILD.gn +++ b/engine/src/flutter/shell/platform/android/BUILD.gn @@ -535,16 +535,6 @@ zip_bundle("flutter_jar_zip") { ] deps = [ ":android_jar" ] - - if (current_cpu == "x86" || current_cpu == "x64") { - files += [ - { - source = "$root_build_dir/lib.stripped/libflutter.so" - destination = "libflutter.so" - }, - ] - deps += [ ":flutter_shell_native" ] - } } action("gen_android_javadoc") {