Include TextureLayer in contents of toImageSync (#35608)

diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc
index de7573e..3b4907b 100644
--- a/flow/layers/layer_tree.cc
+++ b/flow/layers/layer_tree.cc
@@ -171,7 +171,10 @@
   }
 }
 
-sk_sp<DisplayList> LayerTree::Flatten(const SkRect& bounds) {
+sk_sp<DisplayList> LayerTree::Flatten(
+    const SkRect& bounds,
+    std::shared_ptr<TextureRegistry> texture_registry,
+    GrDirectContext* gr_context) {
   TRACE_EVENT0("flutter", "LayerTree::Flatten");
 
   DisplayListCanvasRecorder builder(bounds);
@@ -179,13 +182,14 @@
   MutatorsStack unused_stack;
   const FixedRefreshRateStopwatch unused_stopwatch;
   SkMatrix root_surface_transformation;
+
   // No root surface transformation. So assume identity.
   root_surface_transformation.reset();
 
   PrerollContext preroll_context{
       // clang-format off
       .raster_cache                  = nullptr,
-      .gr_context                    = nullptr,
+      .gr_context                    = gr_context,
       .view_embedder                 = nullptr,
       .mutators_stack                = unused_stack,
       .dst_color_space               = nullptr,
@@ -193,7 +197,7 @@
       .surface_needs_readback        = false,
       .raster_time                   = unused_stopwatch,
       .ui_time                       = unused_stopwatch,
-      .texture_registry              = nullptr,
+      .texture_registry              = texture_registry,
       .checkerboard_offscreen_layers = false,
       .frame_device_pixel_ratio      = device_pixel_ratio_
       // clang-format on
@@ -209,12 +213,12 @@
       // clang-format off
       .internal_nodes_canvas         = &internal_nodes_canvas,
       .leaf_nodes_canvas             = &builder,
-      .gr_context                    = nullptr,
+      .gr_context                    = gr_context,
       .dst_color_space               = nullptr,
       .view_embedder                 = nullptr,
       .raster_time                   = unused_stopwatch,
       .ui_time                       = unused_stopwatch,
-      .texture_registry              = nullptr,
+      .texture_registry              = texture_registry,
       .raster_cache                  = nullptr,
       .checkerboard_offscreen_layers = false,
       .frame_device_pixel_ratio      = device_pixel_ratio_,
diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h
index c7daa5f..1675004 100644
--- a/flow/layers/layer_tree.h
+++ b/flow/layers/layer_tree.h
@@ -8,6 +8,7 @@
 #include <cstdint>
 #include <memory>
 
+#include "flutter/common/graphics/texture.h"
 #include "flutter/flow/compositor_context.h"
 #include "flutter/flow/layers/layer.h"
 #include "flutter/flow/raster_cache.h"
@@ -41,7 +42,10 @@
   void Paint(CompositorContext::ScopedFrame& frame,
              bool ignore_raster_cache = false) const;
 
-  sk_sp<DisplayList> Flatten(const SkRect& bounds);
+  sk_sp<DisplayList> Flatten(
+      const SkRect& bounds,
+      std::shared_ptr<TextureRegistry> texture_registry = nullptr,
+      GrDirectContext* gr_context = nullptr);
 
   Layer* root_layer() const { return root_layer_.get(); }
 
diff --git a/lib/ui/compositing.dart b/lib/ui/compositing.dart
index e38066a..843be96 100644
--- a/lib/ui/compositing.dart
+++ b/lib/ui/compositing.dart
@@ -38,6 +38,7 @@
   external String? _toImageSync(int width, int height, _Image outImage);
 
   /// Creates a raster image representation of the current state of the scene.
+  ///
   /// This is a slow operation that is performed on a background thread.
   ///
   /// Callers must dispose the [Image] when they are done with it. If the result
diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc
index 734a67e..5a8601b 100644
--- a/lib/ui/compositing/scene.cc
+++ b/lib/ui/compositing/scene.cc
@@ -5,6 +5,7 @@
 #include "flutter/lib/ui/compositing/scene.h"
 
 #include "flutter/fml/trace_event.h"
+#include "flutter/lib/ui/painting/display_list_deferred_image_gpu.h"
 #include "flutter/lib/ui/painting/image.h"
 #include "flutter/lib/ui/painting/picture.h"
 #include "flutter/lib/ui/ui_dart_state.h"
@@ -42,7 +43,7 @@
                               ->get_window(0)
                               ->viewport_metrics();
 
-  layer_tree_ = std::make_unique<LayerTree>(
+  layer_tree_ = std::make_shared<LayerTree>(
       SkISize::Make(viewport_metrics.physical_width,
                     viewport_metrics.physical_height),
       static_cast<float>(viewport_metrics.device_pixel_ratio));
@@ -69,12 +70,7 @@
     return tonic::ToDart("Scene did not contain a layer tree.");
   }
 
-  auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height));
-  if (!picture) {
-    return tonic::ToDart("Could not flatten scene into a layer tree.");
-  }
-
-  Picture::RasterizeToImageSync(picture, width, height, raw_image_handle);
+  Scene::RasterizeToImage(width, height, raw_image_handle);
   return Dart_Null();
 }
 
@@ -87,15 +83,32 @@
     return tonic::ToDart("Scene did not contain a layer tree.");
   }
 
-  auto picture = layer_tree_->Flatten(SkRect::MakeWH(width, height));
-  if (!picture) {
-    return tonic::ToDart("Could not flatten scene into a layer tree.");
-  }
-
-  return Picture::RasterizeToImage(picture, width, height, raw_image_callback);
+  return Picture::RasterizeLayerTreeToImage(std::move(layer_tree_), width,
+                                            height, raw_image_callback);
 }
 
-std::unique_ptr<flutter::LayerTree> Scene::takeLayerTree() {
+void Scene::RasterizeToImage(uint32_t width,
+                             uint32_t height,
+                             Dart_Handle raw_image_handle) {
+  auto* dart_state = UIDartState::Current();
+  if (!dart_state) {
+    return;
+  }
+  auto unref_queue = dart_state->GetSkiaUnrefQueue();
+  auto snapshot_delegate = dart_state->GetSnapshotDelegate();
+  auto raster_task_runner = dart_state->GetTaskRunners().GetRasterTaskRunner();
+
+  auto image = CanvasImage::Create();
+  const SkImageInfo image_info = SkImageInfo::Make(
+      width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+  auto dl_image = DlDeferredImageGPU::MakeFromLayerTree(
+      image_info, std::move(layer_tree_), std::move(snapshot_delegate),
+      std::move(raster_task_runner), std::move(unref_queue));
+  image->set_image(dl_image);
+  image->AssociateWithDartWrapper(raw_image_handle);
+}
+
+std::shared_ptr<flutter::LayerTree> Scene::takeLayerTree() {
   return std::move(layer_tree_);
 }
 
diff --git a/lib/ui/compositing/scene.h b/lib/ui/compositing/scene.h
index 1cf95aa..aca7978 100644
--- a/lib/ui/compositing/scene.h
+++ b/lib/ui/compositing/scene.h
@@ -26,7 +26,7 @@
                      bool checkerboardRasterCacheImages,
                      bool checkerboardOffscreenLayers);
 
-  std::unique_ptr<flutter::LayerTree> takeLayerTree();
+  std::shared_ptr<flutter::LayerTree> takeLayerTree();
 
   Dart_Handle toImageSync(uint32_t width,
                           uint32_t height,
@@ -34,17 +34,26 @@
 
   Dart_Handle toImage(uint32_t width,
                       uint32_t height,
-                      Dart_Handle image_callback);
+                      Dart_Handle raw_image_handle);
 
   void dispose();
 
  private:
-  explicit Scene(std::shared_ptr<flutter::Layer> rootLayer,
-                 uint32_t rasterizerTracingThreshold,
-                 bool checkerboardRasterCacheImages,
-                 bool checkerboardOffscreenLayers);
+  Scene(std::shared_ptr<flutter::Layer> rootLayer,
+        uint32_t rasterizerTracingThreshold,
+        bool checkerboardRasterCacheImages,
+        bool checkerboardOffscreenLayers);
 
-  std::unique_ptr<flutter::LayerTree> layer_tree_;
+  void RasterizeToImage(uint32_t width,
+                        uint32_t height,
+                        Dart_Handle raw_image_handle);
+
+  // This is a shared_ptr to support flattening the layer tree from the UI
+  // thread onto the raster thread - allowing access to the texture registry
+  // required to render TextureLayers.
+  //
+  // No longer valid after calling `takeLayerTree`.
+  std::shared_ptr<flutter::LayerTree> layer_tree_;
 };
 
 }  // namespace flutter
diff --git a/lib/ui/painting/display_list_deferred_image_gpu.cc b/lib/ui/painting/display_list_deferred_image_gpu.cc
index beeb0cc..14391c2 100644
--- a/lib/ui/painting/display_list_deferred_image_gpu.cc
+++ b/lib/ui/painting/display_list_deferred_image_gpu.cc
@@ -22,6 +22,19 @@
       raster_task_runner));
 }
 
+sk_sp<DlDeferredImageGPU> DlDeferredImageGPU::MakeFromLayerTree(
+    const SkImageInfo& image_info,
+    std::shared_ptr<LayerTree> layer_tree,
+    fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
+    fml::RefPtr<fml::TaskRunner> raster_task_runner,
+    fml::RefPtr<SkiaUnrefQueue> unref_queue) {
+  return sk_sp<DlDeferredImageGPU>(new DlDeferredImageGPU(
+      ImageWrapper::MakeFromLayerTree(
+          image_info, std::move(layer_tree), std::move(snapshot_delegate),
+          raster_task_runner, std::move(unref_queue)),
+      raster_task_runner));
+}
+
 DlDeferredImageGPU::DlDeferredImageGPU(
     std::shared_ptr<ImageWrapper> image_wrapper,
     fml::RefPtr<fml::TaskRunner> raster_task_runner)
@@ -92,6 +105,20 @@
   return wrapper;
 }
 
+std::shared_ptr<DlDeferredImageGPU::ImageWrapper>
+DlDeferredImageGPU::ImageWrapper::MakeFromLayerTree(
+    const SkImageInfo& image_info,
+    std::shared_ptr<LayerTree> layer_tree,
+    fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
+    fml::RefPtr<fml::TaskRunner> raster_task_runner,
+    fml::RefPtr<SkiaUnrefQueue> unref_queue) {
+  auto wrapper = std::shared_ptr<ImageWrapper>(
+      new ImageWrapper(image_info, nullptr, std::move(snapshot_delegate),
+                       std::move(raster_task_runner), std::move(unref_queue)));
+  wrapper->SnapshotDisplayList(std::move(layer_tree));
+  return wrapper;
+}
+
 DlDeferredImageGPU::ImageWrapper::ImageWrapper(
     const SkImageInfo& image_info,
     sk_sp<DisplayList> display_list,
@@ -131,9 +158,11 @@
   return texture_.isValid();
 }
 
-void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() {
+void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList(
+    std::shared_ptr<LayerTree> layer_tree) {
   fml::TaskRunner::RunNowOrPostTask(
-      raster_task_runner_, [weak_this = weak_from_this()]() {
+      raster_task_runner_,
+      [weak_this = weak_from_this(), layer_tree = std::move(layer_tree)]() {
         auto wrapper = weak_this.lock();
         if (!wrapper) {
           return;
@@ -142,6 +171,14 @@
         if (!snapshot_delegate) {
           return;
         }
+        if (layer_tree) {
+          auto display_list =
+              layer_tree->Flatten(SkRect::MakeWH(wrapper->image_info_.width(),
+                                                 wrapper->image_info_.height()),
+                                  snapshot_delegate->GetTextureRegistry(),
+                                  snapshot_delegate->GetGrContext());
+          wrapper->display_list_ = std::move(display_list);
+        }
         auto result = snapshot_delegate->MakeGpuImage(wrapper->display_list_,
                                                       wrapper->image_info_);
         if (result->texture.isValid()) {
diff --git a/lib/ui/painting/display_list_deferred_image_gpu.h b/lib/ui/painting/display_list_deferred_image_gpu.h
index 429dcd8..5f04eb2 100644
--- a/lib/ui/painting/display_list_deferred_image_gpu.h
+++ b/lib/ui/painting/display_list_deferred_image_gpu.h
@@ -11,6 +11,7 @@
 #include "flutter/common/graphics/texture.h"
 #include "flutter/display_list/display_list.h"
 #include "flutter/display_list/display_list_image.h"
+#include "flutter/flow/layers/layer_tree.h"
 #include "flutter/flow/skia_gpu_object.h"
 #include "flutter/fml/macros.h"
 #include "flutter/fml/memory/weak_ptr.h"
@@ -28,6 +29,13 @@
       fml::RefPtr<fml::TaskRunner> raster_task_runner,
       fml::RefPtr<SkiaUnrefQueue> unref_queue);
 
+  static sk_sp<DlDeferredImageGPU> MakeFromLayerTree(
+      const SkImageInfo& image_info,
+      std::shared_ptr<LayerTree> layer_tree,
+      fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
+      fml::RefPtr<fml::TaskRunner> raster_task_runner,
+      fml::RefPtr<SkiaUnrefQueue> unref_queue);
+
   // |DlImage|
   ~DlDeferredImageGPU() override;
 
@@ -73,6 +81,13 @@
         fml::RefPtr<fml::TaskRunner> raster_task_runner,
         fml::RefPtr<SkiaUnrefQueue> unref_queue);
 
+    static std::shared_ptr<ImageWrapper> MakeFromLayerTree(
+        const SkImageInfo& image_info,
+        std::shared_ptr<LayerTree> layer_tree,
+        fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
+        fml::RefPtr<fml::TaskRunner> raster_task_runner,
+        fml::RefPtr<SkiaUnrefQueue> unref_queue);
+
     const SkImageInfo image_info() const { return image_info_; }
     const GrBackendTexture& texture() const { return texture_; }
     bool isTextureBacked() const;
@@ -103,7 +118,11 @@
                  fml::RefPtr<fml::TaskRunner> raster_task_runner,
                  fml::RefPtr<SkiaUnrefQueue> unref_queue);
 
-    void SnapshotDisplayList();
+    // If a layer tree is provided, it will be flattened during the raster
+    // thread task spwaned by this method. After being flattened into a display
+    // list, the image wrapper will be updated to hold this display list and the
+    // layer tree can be dropped.
+    void SnapshotDisplayList(std::shared_ptr<LayerTree> layer_tree = nullptr);
 
     // |ContextListener|
     void OnGrContextCreated() override;
diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc
index 4d5411d..c79c5c0 100644
--- a/lib/ui/painting/picture.cc
+++ b/lib/ui/painting/picture.cc
@@ -95,11 +95,21 @@
                                       Dart_Handle raw_image_callback) {
   return RasterizeToImage(
       [display_list](SkCanvas* canvas) { display_list->RenderTo(canvas); },
-      width, height, raw_image_callback);
+      nullptr, width, height, raw_image_callback);
+}
+
+Dart_Handle Picture::RasterizeLayerTreeToImage(
+    std::shared_ptr<LayerTree> layer_tree,
+    uint32_t width,
+    uint32_t height,
+    Dart_Handle raw_image_callback) {
+  return RasterizeToImage(nullptr, std::move(layer_tree), width, height,
+                          raw_image_callback);
 }
 
 Dart_Handle Picture::RasterizeToImage(
     std::function<void(SkCanvas*)> draw_callback,
+    std::shared_ptr<LayerTree> layer_tree,
     uint32_t width,
     uint32_t height,
     Dart_Handle raw_image_callback) {
@@ -158,10 +168,25 @@
 
   // Kick things off on the raster rask runner.
   fml::TaskRunner::RunNowOrPostTask(
-      raster_task_runner, [ui_task_runner, snapshot_delegate, draw_callback,
-                           picture_bounds, ui_task] {
-        sk_sp<SkImage> raster_image = snapshot_delegate->MakeRasterSnapshot(
-            draw_callback, picture_bounds);
+      raster_task_runner,
+      [ui_task_runner, snapshot_delegate, draw_callback, picture_bounds,
+       ui_task, layer_tree = std::move(layer_tree)] {
+        sk_sp<SkImage> raster_image;
+        if (layer_tree) {
+          auto display_list = layer_tree->Flatten(
+              SkRect::MakeWH(picture_bounds.width(), picture_bounds.height()),
+              snapshot_delegate->GetTextureRegistry(),
+              snapshot_delegate->GetGrContext());
+
+          raster_image = snapshot_delegate->MakeRasterSnapshot(
+              [display_list](SkCanvas* canvas) {
+                display_list->RenderTo(canvas);
+              },
+              picture_bounds);
+        } else {
+          raster_image = snapshot_delegate->MakeRasterSnapshot(draw_callback,
+                                                               picture_bounds);
+        }
 
         fml::TaskRunner::RunNowOrPostTask(
             ui_task_runner,
diff --git a/lib/ui/painting/picture.h b/lib/ui/painting/picture.h
index 1cb390a..77fda55 100644
--- a/lib/ui/painting/picture.h
+++ b/lib/ui/painting/picture.h
@@ -6,6 +6,7 @@
 #define FLUTTER_LIB_UI_PAINTING_PICTURE_H_
 
 #include "flutter/display_list/display_list.h"
+#include "flutter/flow/layers/layer_tree.h"
 #include "flutter/flow/skia_gpu_object.h"
 #include "flutter/lib/ui/dart_wrapper.h"
 #include "flutter/lib/ui/painting/image.h"
@@ -51,8 +52,19 @@
                                       uint32_t height,
                                       Dart_Handle raw_image_callback);
 
+  static Dart_Handle RasterizeLayerTreeToImage(
+      std::shared_ptr<LayerTree> layer_tree,
+      uint32_t width,
+      uint32_t height,
+      Dart_Handle raw_image_callback);
+
+  // Callers may provide either a draw_callback (which should reference a
+  // display list) or a layer tree. If a layer tree is provided, it will be
+  // flattened on the raster thread. In this case the draw callback will be
+  // ignored.
   static Dart_Handle RasterizeToImage(
       std::function<void(SkCanvas*)> draw_callback,
+      std::shared_ptr<LayerTree> layer_tree,
       uint32_t width,
       uint32_t height,
       Dart_Handle raw_image_callback);
diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h
index 4158d28..3b59ffe 100644
--- a/lib/ui/snapshot_delegate.h
+++ b/lib/ui/snapshot_delegate.h
@@ -13,6 +13,7 @@
 #include "third_party/skia/include/core/SkPicture.h"
 #include "third_party/skia/include/core/SkPromiseImageTexture.h"
 #include "third_party/skia/include/gpu/GrContextThreadSafeProxy.h"
+#include "third_party/skia/include/gpu/GrDirectContext.h"
 
 namespace flutter {
 
@@ -52,6 +53,8 @@
   ///
   virtual std::shared_ptr<TextureRegistry> GetTextureRegistry() = 0;
 
+  virtual GrDirectContext* GetGrContext() = 0;
+
   virtual std::unique_ptr<GpuImageResult> MakeGpuImage(
       sk_sp<DisplayList> display_list,
       const SkImageInfo& image_info) = 0;
diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h
index 540e47d..ad68067 100644
--- a/runtime/runtime_delegate.h
+++ b/runtime/runtime_delegate.h
@@ -24,7 +24,7 @@
 
   virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0;
 
-  virtual void Render(std::unique_ptr<flutter::LayerTree> layer_tree) = 0;
+  virtual void Render(std::shared_ptr<flutter::LayerTree> layer_tree) = 0;
 
   virtual void UpdateSemantics(SemanticsNodeUpdates update,
                                CustomAccessibilityActionUpdates actions) = 0;
diff --git a/shell/common/animator.cc b/shell/common/animator.cc
index 31bd0cd..d8614dc 100644
--- a/shell/common/animator.cc
+++ b/shell/common/animator.cc
@@ -144,7 +144,7 @@
   }
 }
 
-void Animator::Render(std::unique_ptr<flutter::LayerTree> layer_tree) {
+void Animator::Render(std::shared_ptr<flutter::LayerTree> layer_tree) {
   has_rendered_ = true;
   last_layer_tree_size_ = layer_tree->frame_size();
 
diff --git a/shell/common/animator.h b/shell/common/animator.h
index d822935..6550452 100644
--- a/shell/common/animator.h
+++ b/shell/common/animator.h
@@ -54,7 +54,7 @@
 
   void RequestFrame(bool regenerate_layer_tree = true);
 
-  void Render(std::unique_ptr<flutter::LayerTree> layer_tree);
+  void Render(std::shared_ptr<flutter::LayerTree> layer_tree);
 
   const std::weak_ptr<VsyncWaiter> GetVsyncWaiter() const;
 
diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc
index 628d7eb..91c2bad 100644
--- a/shell/common/animator_unittests.cc
+++ b/shell/common/animator_unittests.cc
@@ -157,7 +157,7 @@
       [&] {
         ASSERT_FALSE(delegate.notify_idle_called_);
         auto layer_tree =
-            std::make_unique<LayerTree>(SkISize::Make(600, 800), 1.0);
+            std::make_shared<LayerTree>(SkISize::Make(600, 800), 1.0);
         animator->Render(std::move(layer_tree));
         task_runners.GetPlatformTaskRunner()->PostTask(flush_vsync_task);
       },
@@ -240,7 +240,7 @@
 
     PostTaskSync(task_runners.GetUITaskRunner(), [&] {
       auto layer_tree =
-          std::make_unique<LayerTree>(SkISize::Make(600, 800), 1.0);
+          std::make_shared<LayerTree>(SkISize::Make(600, 800), 1.0);
       animator->Render(std::move(layer_tree));
     });
   }
diff --git a/shell/common/engine.cc b/shell/common/engine.cc
index 9a0e5d0..c2cbc9f 100644
--- a/shell/common/engine.cc
+++ b/shell/common/engine.cc
@@ -439,7 +439,7 @@
   animator_->RequestFrame(regenerate_layer_tree);
 }
 
-void Engine::Render(std::unique_ptr<flutter::LayerTree> layer_tree) {
+void Engine::Render(std::shared_ptr<flutter::LayerTree> layer_tree) {
   if (!layer_tree) {
     return;
   }
diff --git a/shell/common/engine.h b/shell/common/engine.h
index 491ec4f..04b968f 100644
--- a/shell/common/engine.h
+++ b/shell/common/engine.h
@@ -879,7 +879,7 @@
   std::string DefaultRouteName() override;
 
   // |RuntimeDelegate|
-  void Render(std::unique_ptr<flutter::LayerTree> layer_tree) override;
+  void Render(std::shared_ptr<flutter::LayerTree> layer_tree) override;
 
   // |RuntimeDelegate|
   void UpdateSemantics(SemanticsNodeUpdates update,
diff --git a/shell/common/engine_unittests.cc b/shell/common/engine_unittests.cc
index 6267494..6dfc93c 100644
--- a/shell/common/engine_unittests.cc
+++ b/shell/common/engine_unittests.cc
@@ -48,7 +48,7 @@
  public:
   MOCK_METHOD0(DefaultRouteName, std::string());
   MOCK_METHOD1(ScheduleFrame, void(bool));
-  MOCK_METHOD1(Render, void(std::unique_ptr<flutter::LayerTree>));
+  MOCK_METHOD1(Render, void(std::shared_ptr<flutter::LayerTree>));
   MOCK_METHOD2(UpdateSemantics,
                void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates));
   MOCK_METHOD1(HandlePlatformMessage, void(std::unique_ptr<PlatformMessage>));
diff --git a/shell/common/pipeline.h b/shell/common/pipeline.h
index 35f90f3..f9546d0 100644
--- a/shell/common/pipeline.h
+++ b/shell/common/pipeline.h
@@ -222,11 +222,11 @@
 };
 
 struct LayerTreeItem {
-  LayerTreeItem(std::unique_ptr<LayerTree> layer_tree,
+  LayerTreeItem(std::shared_ptr<LayerTree> layer_tree,
                 std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder)
       : layer_tree(std::move(layer_tree)),
         frame_timings_recorder(std::move(frame_timings_recorder)) {}
-  std::unique_ptr<LayerTree> layer_tree;
+  std::shared_ptr<LayerTree> layer_tree;
   std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder;
 };
 
diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc
index d3ecb11..f9d10fd 100644
--- a/shell/common/rasterizer.cc
+++ b/shell/common/rasterizer.cc
@@ -145,6 +145,10 @@
   return compositor_context_->texture_registry();
 }
 
+GrDirectContext* Rasterizer::GetGrContext() {
+  return surface_ ? surface_->GetContext() : nullptr;
+}
+
 flutter::LayerTree* Rasterizer::GetLastLayerTree() {
   return last_layer_tree_.get();
 }
@@ -181,7 +185,7 @@
   RasterStatus raster_status = RasterStatus::kFailed;
   LayerTreePipeline::Consumer consumer =
       [&](std::unique_ptr<LayerTreeItem> item) {
-        std::unique_ptr<LayerTree> layer_tree = std::move(item->layer_tree);
+        std::shared_ptr<LayerTree> layer_tree = std::move(item->layer_tree);
         std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder =
             std::move(item->frame_timings_recorder);
         if (discard_callback(*layer_tree.get())) {
@@ -488,7 +492,7 @@
 
 RasterStatus Rasterizer::DoDraw(
     std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
-    std::unique_ptr<flutter::LayerTree> layer_tree) {
+    std::shared_ptr<flutter::LayerTree> layer_tree) {
   TRACE_EVENT_WITH_FRAME_NUMBER(frame_timings_recorder, "flutter",
                                 "Rasterizer::DoDraw");
   FML_DCHECK(delegate_.GetTaskRunners()
diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h
index 2f90ed5..7052b66 100644
--- a/shell/common/rasterizer.h
+++ b/shell/common/rasterizer.h
@@ -26,6 +26,7 @@
 #include "flutter/shell/common/pipeline.h"
 #include "flutter/shell/common/snapshot_surface_producer.h"
 #include "third_party/skia/include/core/SkImage.h"
+#include "third_party/skia/include/gpu/GrDirectContext.h"
 
 namespace flutter {
 
@@ -213,6 +214,8 @@
       std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder);
 
   // |SnapshotDelegate|
+  GrDirectContext* GetGrContext() override;
+
   std::shared_ptr<flutter::TextureRegistry> GetTextureRegistry() override;
 
   using LayerTreeDiscardCallback = std::function<bool(flutter::LayerTree&)>;
@@ -496,7 +499,7 @@
 
   RasterStatus DoDraw(
       std::unique_ptr<FrameTimingsRecorder> frame_timings_recorder,
-      std::unique_ptr<flutter::LayerTree> layer_tree);
+      std::shared_ptr<flutter::LayerTree> layer_tree);
 
   RasterStatus DrawToSurface(FrameTimingsRecorder& frame_timings_recorder,
                              flutter::LayerTree& layer_tree);
@@ -515,11 +518,11 @@
   std::unique_ptr<SnapshotSurfaceProducer> snapshot_surface_producer_;
   std::unique_ptr<flutter::CompositorContext> compositor_context_;
   // This is the last successfully rasterized layer tree.
-  std::unique_ptr<flutter::LayerTree> last_layer_tree_;
+  std::shared_ptr<flutter::LayerTree> last_layer_tree_;
   // Set when we need attempt to rasterize the layer tree again. This layer_tree
   // has not successfully rasterized. This can happen due to the change in the
   // thread configuration. This will be inserted to the front of the pipeline.
-  std::unique_ptr<flutter::LayerTree> resubmitted_layer_tree_;
+  std::shared_ptr<flutter::LayerTree> resubmitted_layer_tree_;
   std::unique_ptr<FrameTimingsRecorder> resubmitted_recorder_;
   fml::closure next_frame_callback_;
   bool user_override_resource_cache_bytes_;
diff --git a/shell/common/rasterizer_unittests.cc b/shell/common/rasterizer_unittests.cc
index 4523284..af14fcc 100644
--- a/shell/common/rasterizer_unittests.cc
+++ b/shell/common/rasterizer_unittests.cc
@@ -176,7 +176,7 @@
   fml::AutoResetWaitableEvent latch;
   thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-    auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+    auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                   /*device_pixel_ratio=*/2.0f);
     auto layer_tree_item = std::make_unique<LayerTreeItem>(
         std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -238,7 +238,7 @@
   fml::AutoResetWaitableEvent latch;
   thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-    auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+    auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                   /*device_pixel_ratio=*/2.0f);
     auto layer_tree_item = std::make_unique<LayerTreeItem>(
         std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -306,7 +306,7 @@
   rasterizer->Setup(std::move(surface));
 
   auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-  auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+  auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                 /*device_pixel_ratio=*/2.0f);
   auto layer_tree_item = std::make_unique<LayerTreeItem>(
       std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -376,7 +376,7 @@
   rasterizer->Setup(std::move(surface));
 
   auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-  auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+  auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                 /*device_pixel_ratio=*/2.0f);
   auto layer_tree_item = std::make_unique<LayerTreeItem>(
       std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -423,7 +423,7 @@
   fml::AutoResetWaitableEvent latch;
   thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-    auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+    auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                   /*device_pixel_ratio=*/2.0f);
     auto layer_tree_item = std::make_unique<LayerTreeItem>(
         std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -476,7 +476,7 @@
   fml::AutoResetWaitableEvent latch;
   thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-    auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+    auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                   /*device_pixel_ratio=*/2.0f);
     auto layer_tree_item = std::make_unique<LayerTreeItem>(
         std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -573,7 +573,7 @@
   fml::AutoResetWaitableEvent latch;
   thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-    auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+    auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                   /*device_pixel_ratio=*/2.0f);
     auto layer_tree_item = std::make_unique<LayerTreeItem>(
         std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -627,7 +627,7 @@
   fml::AutoResetWaitableEvent latch;
   thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-    auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+    auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                   /*device_pixel_ratio=*/2.0f);
     auto layer_tree_item = std::make_unique<LayerTreeItem>(
         std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -681,7 +681,7 @@
   fml::AutoResetWaitableEvent latch;
   thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-    auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+    auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                   /*device_pixel_ratio=*/2.0f);
     auto layer_tree_item = std::make_unique<LayerTreeItem>(
         std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -734,7 +734,7 @@
   fml::AutoResetWaitableEvent latch;
   thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-    auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+    auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                   /*device_pixel_ratio=*/2.0f);
     auto layer_tree_item = std::make_unique<LayerTreeItem>(
         std::move(layer_tree), CreateFinishedBuildRecorder());
@@ -811,7 +811,7 @@
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
     for (int i = 0; i < 2; i++) {
       auto layer_tree =
-          std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+          std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                       /*device_pixel_ratio=*/2.0f);
       auto layer_tree_item = std::make_unique<LayerTreeItem>(
           std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i]));
@@ -972,7 +972,7 @@
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
     for (int i = 0; i < 2; i++) {
       auto layer_tree =
-          std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+          std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                       /*device_pixel_ratio=*/2.0f);
       auto layer_tree_item = std::make_unique<LayerTreeItem>(
           std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i]));
@@ -1045,7 +1045,7 @@
   thread_host.raster_thread->GetTaskRunner()->PostTask([&] {
     rasterizer->Setup(std::move(surface));
     auto pipeline = std::make_shared<LayerTreePipeline>(/*depth=*/10);
-    auto layer_tree = std::make_unique<LayerTree>(/*frame_size=*/SkISize(),
+    auto layer_tree = std::make_shared<LayerTree>(/*frame_size=*/SkISize(),
                                                   /*device_pixel_ratio=*/2.0f);
     auto layer_tree_item = std::make_unique<LayerTreeItem>(
         std::move(layer_tree), CreateFinishedBuildRecorder(first_timestamp));
diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc
index 27f6b0f..eca3450 100644
--- a/shell/common/shell_test.cc
+++ b/shell/common/shell_test.cc
@@ -197,7 +197,7 @@
   fml::WeakPtr<RuntimeDelegate> runtime_delegate = shell->weak_engine_;
   shell->GetTaskRunners().GetUITaskRunner()->PostTask(
       [&latch, runtime_delegate, &builder, viewport_metrics]() {
-        auto layer_tree = std::make_unique<LayerTree>(
+        auto layer_tree = std::make_shared<LayerTree>(
             SkISize::Make(viewport_metrics.physical_width,
                           viewport_metrics.physical_height),
             static_cast<float>(viewport_metrics.device_pixel_ratio));
diff --git a/testing/dart/compositing_test.dart b/testing/dart/compositing_test.dart
index 99c95cf..cb65eb0 100644
--- a/testing/dart/compositing_test.dart
+++ b/testing/dart/compositing_test.dart
@@ -36,6 +36,28 @@
     expect(data.buffer.asUint8List()[3], 0xFF);
   });
 
+  test('Scene.toImageSync succeeds with texture layer', () async {
+    final SceneBuilder builder = SceneBuilder();
+    builder.pushOffset(10, 10);
+    builder.addTexture(0, width: 10, height: 10);
+
+    final Scene scene = builder.build();
+    final Image image = scene.toImageSync(10, 10);
+    scene.dispose();
+
+    expect(image.width, 10);
+    expect(image.height, 10);
+
+    final ByteData? data = await image.toByteData();
+
+    expect(data, isNotNull);
+    expect(data!.lengthInBytes, 10 * 10 * 4);
+    expect(data.buffer.asUint8List()[0], 0);
+    expect(data.buffer.asUint8List()[1], 0);
+    expect(data.buffer.asUint8List()[2], 0);
+    expect(data.buffer.asUint8List()[3], 0);
+  });
+
   test('addPicture with disposed picture does not crash', () {
     bool assertsEnabled = false;
     assert(() {