[Impeller] Support multi-frame codecs (#36792)

diff --git a/lib/ui/painting/image_decoder_impeller.cc b/lib/ui/painting/image_decoder_impeller.cc
index 31a5ab0..4130f37 100644
--- a/lib/ui/painting/image_decoder_impeller.cc
+++ b/lib/ui/painting/image_decoder_impeller.cc
@@ -137,7 +137,7 @@
   return scaled_bitmap;
 }
 
-static sk_sp<DlImage> UploadTexture(
+sk_sp<DlImage> ImageDecoderImpeller::UploadTexture(
     const std::shared_ptr<impeller::Context>& context,
     std::shared_ptr<SkBitmap> bitmap) {
   TRACE_EVENT0("impeller", __FUNCTION__);
diff --git a/lib/ui/painting/image_decoder_impeller.h b/lib/ui/painting/image_decoder_impeller.h
index 0d1afcf..fdaa0a6 100644
--- a/lib/ui/painting/image_decoder_impeller.h
+++ b/lib/ui/painting/image_decoder_impeller.h
@@ -37,6 +37,10 @@
       SkISize target_size,
       impeller::ISize max_texture_size);
 
+  static sk_sp<DlImage> UploadTexture(
+      const std::shared_ptr<impeller::Context>& context,
+      std::shared_ptr<SkBitmap> bitmap);
+
  private:
   using FutureContext = std::shared_future<std::shared_ptr<impeller::Context>>;
   FutureContext context_;
diff --git a/lib/ui/painting/multi_frame_codec.cc b/lib/ui/painting/multi_frame_codec.cc
index 986c2f5..a292025 100644
--- a/lib/ui/painting/multi_frame_codec.cc
+++ b/lib/ui/painting/multi_frame_codec.cc
@@ -8,6 +8,9 @@
 
 #include "flutter/fml/make_copyable.h"
 #include "flutter/lib/ui/painting/image.h"
+#if IMPELLER_SUPPORTS_RENDERING
+#include "lib/ui/painting/image_decoder_impeller.h"
+#endif  // IMPELLER_SUPPORTS_RENDERING
 #include "third_party/dart/runtime/include/dart_api.h"
 #include "third_party/skia/include/core/SkPixelRef.h"
 #include "third_party/tonic/logging/dart_invoke.h"
@@ -26,6 +29,7 @@
                                ImageGenerator::kInfinitePlayCount
                            ? -1
                            : generator_->GetPlayCount() - 1),
+      is_impeller_enabled_(UIDartState::Current()->IsImpellerEnabled()),
       nextFrameIndex_(0) {}
 
 static void InvokeNextFrameCallback(
@@ -77,9 +81,11 @@
   return true;
 }
 
-sk_sp<SkImage> MultiFrameCodec::State::GetNextFrameImage(
+sk_sp<DlImage> MultiFrameCodec::State::GetNextFrameImage(
     fml::WeakPtr<GrDirectContext> resourceContext,
-    const std::shared_ptr<const fml::SyncSwitch>& gpu_disable_sync_switch) {
+    const std::shared_ptr<const fml::SyncSwitch>& gpu_disable_sync_switch,
+    std::shared_ptr<impeller::Context> impeller_context_,
+    fml::RefPtr<flutter::SkiaUnrefQueue> unref_queue) {
   SkBitmap bitmap = SkBitmap();
   SkImageInfo info = generator_->GetInfo().makeColorType(kN32_SkColorType);
   if (info.alphaType() == kUnpremul_SkAlphaType) {
@@ -125,30 +131,45 @@
     lastRequiredFrame_ = std::make_unique<SkBitmap>(bitmap);
     lastRequiredFrameIndex_ = nextFrameIndex_;
   }
-  sk_sp<SkImage> result;
 
+#if IMPELLER_SUPPORTS_RENDERING
+  if (is_impeller_enabled_) {
+    sk_sp<DlImage> result;
+    // impeller, transfer to DlImageImpeller
+    gpu_disable_sync_switch->Execute(fml::SyncSwitch::Handlers().SetIfFalse(
+        [&result, &bitmap, &impeller_context_] {
+          result = ImageDecoderImpeller::UploadTexture(
+              impeller_context_, std::make_shared<SkBitmap>(bitmap));
+        }));
+
+    return result;
+  }
+#endif  // IMPELLER_SUPPORTS_RENDERING
+
+  sk_sp<SkImage> skImage;
   gpu_disable_sync_switch->Execute(
       fml::SyncSwitch::Handlers()
-          .SetIfTrue([&result, &bitmap] {
+          .SetIfTrue([&skImage, &bitmap] {
             // Defer decoding until time of draw later on the raster thread. Can
             // happen when GL operations are currently forbidden such as in the
             // background on iOS.
-            result = SkImage::MakeFromBitmap(bitmap);
+            skImage = SkImage::MakeFromBitmap(bitmap);
           })
-          .SetIfFalse([&result, &resourceContext, &bitmap] {
+          .SetIfFalse([&skImage, &resourceContext, &bitmap] {
             if (resourceContext) {
               SkPixmap pixmap(bitmap.info(), bitmap.pixelRef()->pixels(),
                               bitmap.pixelRef()->rowBytes());
-              result = SkImage::MakeCrossContextFromPixmap(
+              skImage = SkImage::MakeCrossContextFromPixmap(
                   resourceContext.get(), pixmap, true);
             } else {
               // Defer decoding until time of draw later on the raster thread.
               // Can happen when GL operations are currently forbidden such as
               // in the background on iOS.
-              result = SkImage::MakeFromBitmap(bitmap);
+              skImage = SkImage::MakeFromBitmap(bitmap);
             }
           }));
-  return result;
+
+  return DlImageGPU::Make({skImage, std::move(unref_queue)});
 }
 
 void MultiFrameCodec::State::GetNextFrameAndInvokeCallback(
@@ -157,14 +178,16 @@
     fml::WeakPtr<GrDirectContext> resourceContext,
     fml::RefPtr<flutter::SkiaUnrefQueue> unref_queue,
     const std::shared_ptr<const fml::SyncSwitch>& gpu_disable_sync_switch,
-    size_t trace_id) {
+    size_t trace_id,
+    std::shared_ptr<impeller::Context> impeller_context) {
   fml::RefPtr<CanvasImage> image = nullptr;
   int duration = 0;
-  sk_sp<SkImage> skImage =
-      GetNextFrameImage(std::move(resourceContext), gpu_disable_sync_switch);
-  if (skImage) {
+  sk_sp<DlImage> dlImage =
+      GetNextFrameImage(std::move(resourceContext), gpu_disable_sync_switch,
+                        impeller_context, unref_queue);
+  if (dlImage) {
     image = CanvasImage::Create();
-    image->set_image(DlImageGPU::Make({skImage, std::move(unref_queue)}));
+    image->set_image(dlImage);
     ImageGenerator::FrameInfo frameInfo =
         generator_->GetFrameInfo(nextFrameIndex_);
     duration = frameInfo.duration;
@@ -218,7 +241,8 @@
         state->GetNextFrameAndInvokeCallback(
             std::move(callback), ui_task_runner,
             io_manager->GetResourceContext(), io_manager->GetSkiaUnrefQueue(),
-            io_manager->GetIsGpuDisabledSyncSwitch(), trace_id);
+            io_manager->GetIsGpuDisabledSyncSwitch(), trace_id,
+            io_manager->GetImpellerContext());
       }));
 
   return Dart_Null();
diff --git a/lib/ui/painting/multi_frame_codec.h b/lib/ui/painting/multi_frame_codec.h
index 3ccf8c7..3cb42b0 100644
--- a/lib/ui/painting/multi_frame_codec.h
+++ b/lib/ui/painting/multi_frame_codec.h
@@ -44,6 +44,7 @@
     const std::shared_ptr<ImageGenerator> generator_;
     const int frameCount_;
     const int repetitionCount_;
+    bool is_impeller_enabled_ = false;
 
     // The non-const members and functions below here are only read or written
     // to on the IO thread. They are not safe to access or write on the UI
@@ -55,9 +56,11 @@
     // The index of the last decoded required frame.
     int lastRequiredFrameIndex_ = -1;
 
-    sk_sp<SkImage> GetNextFrameImage(
+    sk_sp<DlImage> GetNextFrameImage(
         fml::WeakPtr<GrDirectContext> resourceContext,
-        const std::shared_ptr<const fml::SyncSwitch>& gpu_disable_sync_switch);
+        const std::shared_ptr<const fml::SyncSwitch>& gpu_disable_sync_switch,
+        std::shared_ptr<impeller::Context> impeller_context_,
+        fml::RefPtr<flutter::SkiaUnrefQueue> unref_queue);
 
     void GetNextFrameAndInvokeCallback(
         std::unique_ptr<DartPersistentValue> callback,
@@ -65,7 +68,8 @@
         fml::WeakPtr<GrDirectContext> resourceContext,
         fml::RefPtr<flutter::SkiaUnrefQueue> unref_queue,
         const std::shared_ptr<const fml::SyncSwitch>& gpu_disable_sync_switch,
-        size_t trace_id);
+        size_t trace_id,
+        std::shared_ptr<impeller::Context> impeller_context_);
   };
 
   // Shared across the UI and IO task runners.