From bef5ac613234ca366c3d73e74cd0adc90a7ec074 Mon Sep 17 00:00:00 2001 From: gaaclarke <30870216+gaaclarke@users.noreply.github.com> Date: Tue, 26 May 2020 21:02:40 -0700 Subject: [PATCH] Made the Rasterizer avoid GPU calls when backgrounded (#18563) --- shell/common/animator_unittests.cc | 4 +- shell/common/rasterizer.cc | 96 ++++++++++++------- shell/common/rasterizer.h | 21 +++- shell/common/shell_benchmarks.cc | 4 +- shell/common/shell_test.cc | 3 +- shell/common/shell_unittests.cc | 3 +- .../platform/android/android_shell_holder.cc | 3 +- .../ios/framework/Source/FlutterEngine.mm | 3 +- shell/platform/embedder/embedder.cc | 4 +- shell/platform/fuchsia/flutter/engine.cc | 6 +- shell/testing/tester_main.cc | 3 +- 11 files changed, 100 insertions(+), 50 deletions(-) diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc index 34acb1d45dd..0f5e4325813 100644 --- a/shell/common/animator_unittests.cc +++ b/shell/common/animator_unittests.cc @@ -58,7 +58,9 @@ TEST_F(ShellTest, VSyncTargetTime) { ShellTestPlatformView::BackendType::kDefaultBackend, nullptr); }, [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); + return std::make_unique( + shell, shell.GetTaskRunners(), + shell.GetIsGpuDisabledSyncSwitch()); }); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 522fdf851d1..30d50dba03e 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -28,26 +28,34 @@ static constexpr std::chrono::milliseconds kSkiaCleanupExpiration(15000); static Rasterizer::DummyDelegate dummy_delegate_; Rasterizer::Rasterizer( TaskRunners task_runners, - std::unique_ptr compositor_context) + std::unique_ptr compositor_context, + std::shared_ptr is_gpu_disabled_sync_switch) : Rasterizer(dummy_delegate_, std::move(task_runners), - std::move(compositor_context)) {} - -Rasterizer::Rasterizer(Delegate& delegate, TaskRunners task_runners) - : Rasterizer(delegate, - std::move(task_runners), - std::make_unique( - delegate.GetFrameBudget())) {} + std::move(compositor_context), + is_gpu_disabled_sync_switch) {} Rasterizer::Rasterizer( Delegate& delegate, TaskRunners task_runners, - std::unique_ptr compositor_context) + std::shared_ptr is_gpu_disabled_sync_switch) + : Rasterizer(delegate, + std::move(task_runners), + std::make_unique( + delegate.GetFrameBudget()), + is_gpu_disabled_sync_switch) {} + +Rasterizer::Rasterizer( + Delegate& delegate, + TaskRunners task_runners, + std::unique_ptr compositor_context, + std::shared_ptr is_gpu_disabled_sync_switch) : delegate_(delegate), task_runners_(std::move(task_runners)), compositor_context_(std::move(compositor_context)), user_override_resource_cache_bytes_(false), - weak_factory_(this) { + weak_factory_(this), + is_gpu_disabled_sync_switch_(is_gpu_disabled_sync_switch) { FML_DCHECK(compositor_context_); } @@ -168,31 +176,10 @@ void Rasterizer::Draw(fml::RefPtr> pipeline) { } } -sk_sp Rasterizer::DoMakeRasterSnapshot( - SkISize size, - std::function draw_callback) { - TRACE_EVENT0("flutter", __FUNCTION__); - - sk_sp surface; - SkImageInfo image_info = SkImageInfo::MakeN32Premul( - size.width(), size.height(), SkColorSpace::MakeSRGB()); - if (surface_ == nullptr || surface_->GetContext() == nullptr) { - // Raster surface is fine if there is no on screen surface. This might - // happen in case of software rendering. - surface = SkSurface::MakeRaster(image_info); - } else { - if (!surface_->MakeRenderContextCurrent()) { - return nullptr; - } - - // When there is an on screen surface, we need a render target SkSurface - // because we want to access texture backed images. - surface = SkSurface::MakeRenderTarget(surface_->GetContext(), // context - SkBudgeted::kNo, // budgeted - image_info // image info - ); - } - +namespace { +sk_sp DrawSnapshot( + sk_sp surface, + const std::function& draw_callback) { if (surface == nullptr || surface->getCanvas() == nullptr) { return nullptr; } @@ -219,6 +206,45 @@ sk_sp Rasterizer::DoMakeRasterSnapshot( return nullptr; } +} // namespace + +sk_sp Rasterizer::DoMakeRasterSnapshot( + SkISize size, + std::function draw_callback) { + TRACE_EVENT0("flutter", __FUNCTION__); + sk_sp result; + SkImageInfo image_info = SkImageInfo::MakeN32Premul( + size.width(), size.height(), SkColorSpace::MakeSRGB()); + if (surface_ == nullptr || surface_->GetContext() == nullptr) { + // Raster surface is fine if there is no on screen surface. This might + // happen in case of software rendering. + sk_sp surface = SkSurface::MakeRaster(image_info); + result = DrawSnapshot(surface, draw_callback); + } else { + is_gpu_disabled_sync_switch_->Execute( + fml::SyncSwitch::Handlers() + .SetIfTrue([&] { + sk_sp surface = SkSurface::MakeRaster(image_info); + result = DrawSnapshot(surface, draw_callback); + }) + .SetIfFalse([&] { + if (!surface_->MakeRenderContextCurrent()) { + return; + } + + // When there is an on screen surface, we need a render target + // SkSurface because we want to access texture backed images. + sk_sp surface = SkSurface::MakeRenderTarget( + surface_->GetContext(), // context + SkBudgeted::kNo, // budgeted + image_info // image info + ); + result = DrawSnapshot(surface, draw_callback); + })); + } + + return result; +} sk_sp Rasterizer::MakeRasterSnapshot(sk_sp picture, SkISize picture_size) { diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index a254d84994b..39111b0d59e 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -15,6 +15,7 @@ #include "flutter/fml/closure.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/fml/raster_thread_merger.h" +#include "flutter/fml/synchronization/sync_switch.h" #include "flutter/fml/synchronization/waitable_event.h" #include "flutter/fml/time/time_delta.h" #include "flutter/fml/time/time_point.h" @@ -101,9 +102,13 @@ class Rasterizer final : public SnapshotDelegate { /// @param[in] task_runners The task runners used by the shell. /// @param[in] compositor_context The compositor context used to hold all /// the GPU state used by the rasterizer. + /// @param[in] is_gpu_disabled_sync_switch + /// A `SyncSwitch` for handling disabling of the GPU (typically happens + /// when an app is backgrounded) /// Rasterizer(TaskRunners task_runners, - std::unique_ptr compositor_context); + std::unique_ptr compositor_context, + std::shared_ptr is_gpu_disabled_sync_switch); //---------------------------------------------------------------------------- /// @brief Creates a new instance of a rasterizer. Rasterizers may only @@ -116,8 +121,13 @@ class Rasterizer final : public SnapshotDelegate { /// /// @param[in] delegate The rasterizer delegate. /// @param[in] task_runners The task runners used by the shell. + /// @param[in] is_gpu_disabled_sync_switch + /// A `SyncSwitch` for handling disabling of the GPU (typically happens + /// when an app is backgrounded) /// - Rasterizer(Delegate& delegate, TaskRunners task_runners); + Rasterizer(Delegate& delegate, + TaskRunners task_runners, + std::shared_ptr is_gpu_disabled_sync_switch); //---------------------------------------------------------------------------- /// @brief Creates a new instance of a rasterizer. Rasterizers may only @@ -132,10 +142,14 @@ class Rasterizer final : public SnapshotDelegate { /// @param[in] task_runners The task runners used by the shell. /// @param[in] compositor_context The compositor context used to hold all /// the GPU state used by the rasterizer. + /// @param[in] is_gpu_disabled_sync_switch + /// A `SyncSwitch` for handling disabling of the GPU (typically happens + /// when an app is backgrounded) /// Rasterizer(Delegate& delegate, TaskRunners task_runners, - std::unique_ptr compositor_context); + std::unique_ptr compositor_context, + std::shared_ptr is_gpu_disabled_sync_switch); //---------------------------------------------------------------------------- /// @brief Destroys the rasterizer. This must happen on the GPU task @@ -432,6 +446,7 @@ class Rasterizer final : public SnapshotDelegate { std::optional max_cache_bytes_; fml::TaskRunnerAffineWeakPtrFactory weak_factory_; fml::RefPtr raster_thread_merger_; + std::shared_ptr is_gpu_disabled_sync_switch_; // |SnapshotDelegate| sk_sp MakeRasterSnapshot(sk_sp picture, diff --git a/shell/common/shell_benchmarks.cc b/shell/common/shell_benchmarks.cc index c5b2751204a..9d3a1a36f9c 100644 --- a/shell/common/shell_benchmarks.cc +++ b/shell/common/shell_benchmarks.cc @@ -58,7 +58,9 @@ static void StartupAndShutdownShell(benchmark::State& state, return std::make_unique(shell, shell.GetTaskRunners()); }, [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); + return std::make_unique( + shell, shell.GetTaskRunners(), + shell.GetIsGpuDisabledSyncSwitch()); }); } diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index 8ef045cf0a0..8bd7d8b14b2 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -298,7 +298,8 @@ std::unique_ptr ShellTest::CreateShell( shell_test_external_view_embedder); }, [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); + return std::make_unique(shell, shell.GetTaskRunners(), + shell.GetIsGpuDisabledSyncSwitch()); }); } void ShellTest::DestroyShell(std::unique_ptr shell) { diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc index 589d593cd0f..5318458d16b 100644 --- a/shell/common/shell_unittests.cc +++ b/shell/common/shell_unittests.cc @@ -143,7 +143,8 @@ TEST_F(ShellTest, ShellTestPlatformView::BackendType::kDefaultBackend, nullptr); }, [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); + return std::make_unique(shell, shell.GetTaskRunners(), + shell.GetIsGpuDisabledSyncSwitch()); }); ASSERT_TRUE(ValidateShell(shell.get())); ASSERT_TRUE(DartVMRef::IsInstanceRunning()); diff --git a/shell/platform/android/android_shell_holder.cc b/shell/platform/android/android_shell_holder.cc index fe4d85ab7b2..bde98f83630 100644 --- a/shell/platform/android/android_shell_holder.cc +++ b/shell/platform/android/android_shell_holder.cc @@ -79,7 +79,8 @@ AndroidShellHolder::AndroidShellHolder( }; Shell::CreateCallback on_create_rasterizer = [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); + return std::make_unique(shell, shell.GetTaskRunners(), + shell.GetIsGpuDisabledSyncSwitch()); }; // The current thread will be used as the platform thread. Ensure that the diff --git a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm index 59eae779c61..0b671b0088d 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm @@ -475,7 +475,8 @@ static constexpr int kNumProfilerSamplesPerSec = 5; flutter::Shell::CreateCallback on_create_rasterizer = [](flutter::Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); + return std::make_unique(shell, shell.GetTaskRunners(), + shell.GetIsGpuDisabledSyncSwitch()); }; if (flutter::IsIosEmbeddedViewsPreviewEnabled()) { diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index bfbcb0033be..9091b33bbca 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -935,8 +935,8 @@ FlutterEngineResult FlutterEngineInitialize(size_t version, flutter::Shell::CreateCallback on_create_rasterizer = [](flutter::Shell& shell) { - return std::make_unique(shell, - shell.GetTaskRunners()); + return std::make_unique( + shell, shell.GetTaskRunners(), shell.GetIsGpuDisabledSyncSwitch()); }; // TODO(chinmaygarde): This is the wrong spot for this. It belongs in the diff --git a/shell/platform/fuchsia/flutter/engine.cc b/shell/platform/fuchsia/flutter/engine.cc index 0f6fa1e053e..fc2c2fe80a9 100644 --- a/shell/platform/fuchsia/flutter/engine.cc +++ b/shell/platform/fuchsia/flutter/engine.cc @@ -202,9 +202,9 @@ Engine::Engine(Delegate& delegate, } return std::make_unique( - shell.GetTaskRunners(), // task runners - std::move(compositor_context) // compositor context - ); + /*task_runners=*/shell.GetTaskRunners(), + /*compositor_context=*/std::move(compositor_context), + /*is_gpu_disabled_sync_switch=*/shell.GetIsGpuDisabledSyncSwitch()); }); UpdateNativeThreadLabelNames(thread_label_, task_runners); diff --git a/shell/testing/tester_main.cc b/shell/testing/tester_main.cc index cab64817ae2..73b6ce77257 100644 --- a/shell/testing/tester_main.cc +++ b/shell/testing/tester_main.cc @@ -139,7 +139,8 @@ int RunTester(const flutter::Settings& settings, }; Shell::CreateCallback on_create_rasterizer = [](Shell& shell) { - return std::make_unique(shell, shell.GetTaskRunners()); + return std::make_unique(shell, shell.GetTaskRunners(), + shell.GetIsGpuDisabledSyncSwitch()); }; auto shell = Shell::Create(task_runners, //