Made the Rasterizer avoid GPU calls when backgrounded (#18563)

diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc
index 34acb1d..0f5e432 100644
--- a/shell/common/animator_unittests.cc
+++ b/shell/common/animator_unittests.cc
@@ -58,7 +58,9 @@
               ShellTestPlatformView::BackendType::kDefaultBackend, nullptr);
         },
         [](Shell& shell) {
-          return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
+          return std::make_unique<Rasterizer>(
+              shell, shell.GetTaskRunners(),
+              shell.GetIsGpuDisabledSyncSwitch());
         });
     ASSERT_TRUE(DartVMRef::IsInstanceRunning());
 
diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc
index 522fdf8..30d50db 100644
--- a/shell/common/rasterizer.cc
+++ b/shell/common/rasterizer.cc
@@ -28,26 +28,34 @@
 static Rasterizer::DummyDelegate dummy_delegate_;
 Rasterizer::Rasterizer(
     TaskRunners task_runners,
-    std::unique_ptr<flutter::CompositorContext> compositor_context)
+    std::unique_ptr<flutter::CompositorContext> compositor_context,
+    std::shared_ptr<fml::SyncSwitch> 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<flutter::CompositorContext>(
-                     delegate.GetFrameBudget())) {}
+                 std::move(compositor_context),
+                 is_gpu_disabled_sync_switch) {}
 
 Rasterizer::Rasterizer(
     Delegate& delegate,
     TaskRunners task_runners,
-    std::unique_ptr<flutter::CompositorContext> compositor_context)
+    std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch)
+    : Rasterizer(delegate,
+                 std::move(task_runners),
+                 std::make_unique<flutter::CompositorContext>(
+                     delegate.GetFrameBudget()),
+                 is_gpu_disabled_sync_switch) {}
+
+Rasterizer::Rasterizer(
+    Delegate& delegate,
+    TaskRunners task_runners,
+    std::unique_ptr<flutter::CompositorContext> compositor_context,
+    std::shared_ptr<fml::SyncSwitch> 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 @@
   }
 }
 
-sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
-    SkISize size,
-    std::function<void(SkCanvas*)> draw_callback) {
-  TRACE_EVENT0("flutter", __FUNCTION__);
-
-  sk_sp<SkSurface> 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<SkImage> DrawSnapshot(
+    sk_sp<SkSurface> surface,
+    const std::function<void(SkCanvas*)>& draw_callback) {
   if (surface == nullptr || surface->getCanvas() == nullptr) {
     return nullptr;
   }
@@ -219,6 +206,45 @@
 
   return nullptr;
 }
+}  // namespace
+
+sk_sp<SkImage> Rasterizer::DoMakeRasterSnapshot(
+    SkISize size,
+    std::function<void(SkCanvas*)> draw_callback) {
+  TRACE_EVENT0("flutter", __FUNCTION__);
+  sk_sp<SkImage> 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<SkSurface> surface = SkSurface::MakeRaster(image_info);
+    result = DrawSnapshot(surface, draw_callback);
+  } else {
+    is_gpu_disabled_sync_switch_->Execute(
+        fml::SyncSwitch::Handlers()
+            .SetIfTrue([&] {
+              sk_sp<SkSurface> 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<SkSurface> surface = SkSurface::MakeRenderTarget(
+                  surface_->GetContext(),  // context
+                  SkBudgeted::kNo,         // budgeted
+                  image_info               // image info
+              );
+              result = DrawSnapshot(surface, draw_callback);
+            }));
+  }
+
+  return result;
+}
 
 sk_sp<SkImage> Rasterizer::MakeRasterSnapshot(sk_sp<SkPicture> picture,
                                               SkISize picture_size) {
diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h
index a254d84..39111b0 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 @@
   /// @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<flutter::CompositorContext> compositor_context);
+             std::unique_ptr<flutter::CompositorContext> compositor_context,
+             std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch);
 
   //----------------------------------------------------------------------------
   /// @brief      Creates a new instance of a rasterizer. Rasterizers may only
@@ -116,8 +121,13 @@
   ///
   /// @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<fml::SyncSwitch> is_gpu_disabled_sync_switch);
 
   //----------------------------------------------------------------------------
   /// @brief      Creates a new instance of a rasterizer. Rasterizers may only
@@ -132,10 +142,14 @@
   /// @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<flutter::CompositorContext> compositor_context);
+             std::unique_ptr<flutter::CompositorContext> compositor_context,
+             std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch);
 
   //----------------------------------------------------------------------------
   /// @brief      Destroys the rasterizer. This must happen on the GPU task
@@ -432,6 +446,7 @@
   std::optional<size_t> max_cache_bytes_;
   fml::TaskRunnerAffineWeakPtrFactory<Rasterizer> weak_factory_;
   fml::RefPtr<fml::RasterThreadMerger> raster_thread_merger_;
+  std::shared_ptr<fml::SyncSwitch> is_gpu_disabled_sync_switch_;
 
   // |SnapshotDelegate|
   sk_sp<SkImage> MakeRasterSnapshot(sk_sp<SkPicture> picture,
diff --git a/shell/common/shell_benchmarks.cc b/shell/common/shell_benchmarks.cc
index c5b2751..9d3a1a3 100644
--- a/shell/common/shell_benchmarks.cc
+++ b/shell/common/shell_benchmarks.cc
@@ -58,7 +58,9 @@
           return std::make_unique<PlatformView>(shell, shell.GetTaskRunners());
         },
         [](Shell& shell) {
-          return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
+          return std::make_unique<Rasterizer>(
+              shell, shell.GetTaskRunners(),
+              shell.GetIsGpuDisabledSyncSwitch());
         });
   }
 
diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc
index 8ef045c..8bd7d8b 100644
--- a/shell/common/shell_test.cc
+++ b/shell/common/shell_test.cc
@@ -298,7 +298,8 @@
             shell_test_external_view_embedder);
       },
       [](Shell& shell) {
-        return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
+        return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners(),
+                                            shell.GetIsGpuDisabledSyncSwitch());
       });
 }
 void ShellTest::DestroyShell(std::unique_ptr<Shell> shell) {
diff --git a/shell/common/shell_unittests.cc b/shell/common/shell_unittests.cc
index 589d593..5318458 100644
--- a/shell/common/shell_unittests.cc
+++ b/shell/common/shell_unittests.cc
@@ -143,7 +143,8 @@
             ShellTestPlatformView::BackendType::kDefaultBackend, nullptr);
       },
       [](Shell& shell) {
-        return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
+        return std::make_unique<Rasterizer>(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 fe4d85a..bde98f8 100644
--- a/shell/platform/android/android_shell_holder.cc
+++ b/shell/platform/android/android_shell_holder.cc
@@ -79,7 +79,8 @@
       };
 
   Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
-    return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
+    return std::make_unique<Rasterizer>(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 59eae77..0b671b0 100644
--- a/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
+++ b/shell/platform/darwin/ios/framework/Source/FlutterEngine.mm
@@ -475,7 +475,8 @@
 
   flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
       [](flutter::Shell& shell) {
-        return std::make_unique<flutter::Rasterizer>(shell, shell.GetTaskRunners());
+        return std::make_unique<flutter::Rasterizer>(shell, shell.GetTaskRunners(),
+                                                     shell.GetIsGpuDisabledSyncSwitch());
       };
 
   if (flutter::IsIosEmbeddedViewsPreviewEnabled()) {
diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc
index bfbcb00..9091b33 100644
--- a/shell/platform/embedder/embedder.cc
+++ b/shell/platform/embedder/embedder.cc
@@ -935,8 +935,8 @@
 
   flutter::Shell::CreateCallback<flutter::Rasterizer> on_create_rasterizer =
       [](flutter::Shell& shell) {
-        return std::make_unique<flutter::Rasterizer>(shell,
-                                                     shell.GetTaskRunners());
+        return std::make_unique<flutter::Rasterizer>(
+            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 0f6fa1e..fc2c2fe 100644
--- a/shell/platform/fuchsia/flutter/engine.cc
+++ b/shell/platform/fuchsia/flutter/engine.cc
@@ -202,9 +202,9 @@
         }
 
         return std::make_unique<flutter::Rasterizer>(
-            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 cab6481..73b6ce7 100644
--- a/shell/testing/tester_main.cc
+++ b/shell/testing/tester_main.cc
@@ -139,7 +139,8 @@
       };
 
   Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
-    return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners());
+    return std::make_unique<Rasterizer>(shell, shell.GetTaskRunners(),
+                                        shell.GetIsGpuDisabledSyncSwitch());
   };
 
   auto shell = Shell::Create(task_runners,             //