diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index de7573ef4ac39..3b4907b5336bf 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -171,7 +171,10 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame, } } -sk_sp LayerTree::Flatten(const SkRect& bounds) { +sk_sp LayerTree::Flatten( + const SkRect& bounds, + std::shared_ptr texture_registry, + GrDirectContext* gr_context) { TRACE_EVENT0("flutter", "LayerTree::Flatten"); DisplayListCanvasRecorder builder(bounds); @@ -179,13 +182,14 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { 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 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { .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 @@ sk_sp LayerTree::Flatten(const SkRect& bounds) { // 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 c7daa5f809e9f..167500400b758 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -8,6 +8,7 @@ #include #include +#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 @@ class LayerTree { void Paint(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache = false) const; - sk_sp Flatten(const SkRect& bounds); + sk_sp Flatten( + const SkRect& bounds, + std::shared_ptr 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 528fc027c043a..384d1b500ccb3 100644 --- a/lib/ui/compositing.dart +++ b/lib/ui/compositing.dart @@ -38,6 +38,7 @@ class Scene extends NativeFieldWrapperClass1 { 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 734a67ef2481c..5a8601b90effe 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 @@ Scene::Scene(std::shared_ptr rootLayer, ->get_window(0) ->viewport_metrics(); - layer_tree_ = std::make_unique( + layer_tree_ = std::make_shared( SkISize::Make(viewport_metrics.physical_width, viewport_metrics.physical_height), static_cast(viewport_metrics.device_pixel_ratio)); @@ -69,12 +70,7 @@ Dart_Handle Scene::toImageSync(uint32_t width, 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 @@ Dart_Handle Scene::toImage(uint32_t width, 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::RasterizeLayerTreeToImage(std::move(layer_tree_), width, + height, raw_image_callback); +} - return Picture::RasterizeToImage(picture, width, height, raw_image_callback); +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::unique_ptr Scene::takeLayerTree() { +std::shared_ptr Scene::takeLayerTree() { return std::move(layer_tree_); } diff --git a/lib/ui/compositing/scene.h b/lib/ui/compositing/scene.h index 1cf95aad4ec43..aca797836fcb1 100644 --- a/lib/ui/compositing/scene.h +++ b/lib/ui/compositing/scene.h @@ -26,7 +26,7 @@ class Scene : public RefCountedDartWrappable { bool checkerboardRasterCacheImages, bool checkerboardOffscreenLayers); - std::unique_ptr takeLayerTree(); + std::shared_ptr takeLayerTree(); Dart_Handle toImageSync(uint32_t width, uint32_t height, @@ -34,17 +34,26 @@ class Scene : public RefCountedDartWrappable { 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 rootLayer, - uint32_t rasterizerTracingThreshold, - bool checkerboardRasterCacheImages, - bool checkerboardOffscreenLayers); - - std::unique_ptr layer_tree_; + Scene(std::shared_ptr rootLayer, + uint32_t rasterizerTracingThreshold, + bool checkerboardRasterCacheImages, + bool checkerboardOffscreenLayers); + + 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 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 beeb0ccf80404..14391c2128a74 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 @@ sk_sp DlDeferredImageGPU::Make( raster_task_runner)); } +sk_sp DlDeferredImageGPU::MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + return sk_sp(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 image_wrapper, fml::RefPtr raster_task_runner) @@ -92,6 +105,20 @@ DlDeferredImageGPU::ImageWrapper::Make( return wrapper; } +std::shared_ptr +DlDeferredImageGPU::ImageWrapper::MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue) { + auto wrapper = std::shared_ptr( + 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 display_list, @@ -131,9 +158,11 @@ bool DlDeferredImageGPU::ImageWrapper::isTextureBacked() const { return texture_.isValid(); } -void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { +void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList( + std::shared_ptr 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 @@ void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() { 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 429dcd873a101..5f04eb25d0765 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 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); + static sk_sp MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + // |DlImage| ~DlDeferredImageGPU() override; @@ -73,6 +81,13 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr unref_queue); + static std::shared_ptr MakeFromLayerTree( + const SkImageInfo& image_info, + std::shared_ptr layer_tree, + fml::WeakPtr snapshot_delegate, + fml::RefPtr raster_task_runner, + fml::RefPtr unref_queue); + const SkImageInfo image_info() const { return image_info_; } const GrBackendTexture& texture() const { return texture_; } bool isTextureBacked() const; @@ -103,7 +118,11 @@ class DlDeferredImageGPU final : public DlImage { fml::RefPtr raster_task_runner, fml::RefPtr 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 layer_tree = nullptr); // |ContextListener| void OnGrContextCreated() override; diff --git a/lib/ui/painting/picture.cc b/lib/ui/painting/picture.cc index 4d5411d1830f6..c79c5c08a3688 100644 --- a/lib/ui/painting/picture.cc +++ b/lib/ui/painting/picture.cc @@ -95,11 +95,21 @@ Dart_Handle Picture::RasterizeToImage(sk_sp display_list, 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 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 draw_callback, + std::shared_ptr layer_tree, uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { @@ -158,10 +168,25 @@ Dart_Handle Picture::RasterizeToImage( // 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 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 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 1cb390a182138..77fda55884c3d 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 @@ class Picture : public RefCountedDartWrappable { uint32_t height, Dart_Handle raw_image_callback); + static Dart_Handle RasterizeLayerTreeToImage( + std::shared_ptr 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 draw_callback, + std::shared_ptr 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 4158d28701cbb..3b59ffed9fb23 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 @@ class SnapshotDelegate { /// virtual std::shared_ptr GetTextureRegistry() = 0; + virtual GrDirectContext* GetGrContext() = 0; + virtual std::unique_ptr MakeGpuImage( sk_sp display_list, const SkImageInfo& image_info) = 0; diff --git a/runtime/runtime_delegate.h b/runtime/runtime_delegate.h index 540e47dd09ba4..ad680677338e0 100644 --- a/runtime/runtime_delegate.h +++ b/runtime/runtime_delegate.h @@ -24,7 +24,7 @@ class RuntimeDelegate { virtual void ScheduleFrame(bool regenerate_layer_tree = true) = 0; - virtual void Render(std::unique_ptr layer_tree) = 0; + virtual void Render(std::shared_ptr layer_tree) = 0; virtual void UpdateSemantics(SemanticsNodeUpdates update, CustomAccessibilityActionUpdates actions) = 0; diff --git a/shell/common/animator.cc b/shell/common/animator.cc index 31bd0cdfb5eb5..d8614dc22f69c 100644 --- a/shell/common/animator.cc +++ b/shell/common/animator.cc @@ -144,7 +144,7 @@ void Animator::BeginFrame( } } -void Animator::Render(std::unique_ptr layer_tree) { +void Animator::Render(std::shared_ptr 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 d822935307ac8..6550452ba481e 100644 --- a/shell/common/animator.h +++ b/shell/common/animator.h @@ -54,7 +54,7 @@ class Animator final { void RequestFrame(bool regenerate_layer_tree = true); - void Render(std::unique_ptr layer_tree); + void Render(std::shared_ptr layer_tree); const std::weak_ptr GetVsyncWaiter() const; diff --git a/shell/common/animator_unittests.cc b/shell/common/animator_unittests.cc index 628d7eb9afbc0..91c2bad1b033f 100644 --- a/shell/common/animator_unittests.cc +++ b/shell/common/animator_unittests.cc @@ -157,7 +157,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyIdleBeforeRender) { [&] { ASSERT_FALSE(delegate.notify_idle_called_); auto layer_tree = - std::make_unique(SkISize::Make(600, 800), 1.0); + std::make_shared(SkISize::Make(600, 800), 1.0); animator->Render(std::move(layer_tree)); task_runners.GetPlatformTaskRunner()->PostTask(flush_vsync_task); }, @@ -240,7 +240,7 @@ TEST_F(ShellTest, AnimatorDoesNotNotifyDelegateIfPipelineIsNotEmpty) { PostTaskSync(task_runners.GetUITaskRunner(), [&] { auto layer_tree = - std::make_unique(SkISize::Make(600, 800), 1.0); + std::make_shared(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 9a0e5d03e4883..c2cbc9f512b98 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -439,7 +439,7 @@ void Engine::ScheduleFrame(bool regenerate_layer_tree) { animator_->RequestFrame(regenerate_layer_tree); } -void Engine::Render(std::unique_ptr layer_tree) { +void Engine::Render(std::shared_ptr layer_tree) { if (!layer_tree) { return; } diff --git a/shell/common/engine.h b/shell/common/engine.h index 491ec4f0e5fe3..04b968f106c41 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -879,7 +879,7 @@ class Engine final : public RuntimeDelegate, PointerDataDispatcher::Delegate { std::string DefaultRouteName() override; // |RuntimeDelegate| - void Render(std::unique_ptr layer_tree) override; + void Render(std::shared_ptr layer_tree) override; // |RuntimeDelegate| void UpdateSemantics(SemanticsNodeUpdates update, diff --git a/shell/common/engine_unittests.cc b/shell/common/engine_unittests.cc index 62674947f9e87..6dfc93c555c36 100644 --- a/shell/common/engine_unittests.cc +++ b/shell/common/engine_unittests.cc @@ -48,7 +48,7 @@ class MockRuntimeDelegate : public RuntimeDelegate { public: MOCK_METHOD0(DefaultRouteName, std::string()); MOCK_METHOD1(ScheduleFrame, void(bool)); - MOCK_METHOD1(Render, void(std::unique_ptr)); + MOCK_METHOD1(Render, void(std::shared_ptr)); MOCK_METHOD2(UpdateSemantics, void(SemanticsNodeUpdates, CustomAccessibilityActionUpdates)); MOCK_METHOD1(HandlePlatformMessage, void(std::unique_ptr)); diff --git a/shell/common/pipeline.h b/shell/common/pipeline.h index 35f90f39f2c6a..f9546d0816125 100644 --- a/shell/common/pipeline.h +++ b/shell/common/pipeline.h @@ -222,11 +222,11 @@ class Pipeline { }; struct LayerTreeItem { - LayerTreeItem(std::unique_ptr layer_tree, + LayerTreeItem(std::shared_ptr layer_tree, std::unique_ptr frame_timings_recorder) : layer_tree(std::move(layer_tree)), frame_timings_recorder(std::move(frame_timings_recorder)) {} - std::unique_ptr layer_tree; + std::shared_ptr layer_tree; std::unique_ptr frame_timings_recorder; }; diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index d3ecb11fee8ec..f9d10fd3e2240 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -145,6 +145,10 @@ std::shared_ptr Rasterizer::GetTextureRegistry() { 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 Rasterizer::Draw(std::shared_ptr pipeline, RasterStatus raster_status = RasterStatus::kFailed; LayerTreePipeline::Consumer consumer = [&](std::unique_ptr item) { - std::unique_ptr layer_tree = std::move(item->layer_tree); + std::shared_ptr layer_tree = std::move(item->layer_tree); std::unique_ptr frame_timings_recorder = std::move(item->frame_timings_recorder); if (discard_callback(*layer_tree.get())) { @@ -488,7 +492,7 @@ fml::Milliseconds Rasterizer::GetFrameBudget() const { RasterStatus Rasterizer::DoDraw( std::unique_ptr frame_timings_recorder, - std::unique_ptr layer_tree) { + std::shared_ptr 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 2f90ed5b1fe66..7052b664e1791 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 @@ class Rasterizer final : public SnapshotDelegate, std::unique_ptr frame_timings_recorder); // |SnapshotDelegate| + GrDirectContext* GetGrContext() override; + std::shared_ptr GetTextureRegistry() override; using LayerTreeDiscardCallback = std::function; @@ -496,7 +499,7 @@ class Rasterizer final : public SnapshotDelegate, RasterStatus DoDraw( std::unique_ptr frame_timings_recorder, - std::unique_ptr layer_tree); + std::shared_ptr layer_tree); RasterStatus DrawToSurface(FrameTimingsRecorder& frame_timings_recorder, flutter::LayerTree& layer_tree); @@ -515,11 +518,11 @@ class Rasterizer final : public SnapshotDelegate, std::unique_ptr snapshot_surface_producer_; std::unique_ptr compositor_context_; // This is the last successfully rasterized layer tree. - std::unique_ptr last_layer_tree_; + std::shared_ptr 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 resubmitted_layer_tree_; + std::shared_ptr resubmitted_layer_tree_; std::unique_ptr 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 45232840bf2b1..af14fcc1675cf 100644 --- a/shell/common/rasterizer_unittests.cc +++ b/shell/common/rasterizer_unittests.cc @@ -176,7 +176,7 @@ TEST(RasterizerTest, fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -238,7 +238,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -306,7 +306,7 @@ TEST( rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -376,7 +376,7 @@ TEST(RasterizerTest, rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -423,7 +423,7 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNoSurfaceIsSet) { fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -476,7 +476,7 @@ TEST(RasterizerTest, externalViewEmbedderDoesntEndFrameWhenNotUsedThisFrame) { fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -573,7 +573,7 @@ TEST(RasterizerTest, fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -627,7 +627,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -681,7 +681,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -734,7 +734,7 @@ TEST( fml::AutoResetWaitableEvent latch; thread_host.raster_thread->GetTaskRunner()->PostTask([&] { auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder()); @@ -811,7 +811,7 @@ TEST(RasterizerTest, auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = - std::make_unique(/*frame_size=*/SkISize(), + std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i])); @@ -972,7 +972,7 @@ TEST(RasterizerTest, presentationTimeSetWhenVsyncTargetInFuture) { auto pipeline = std::make_shared(/*depth=*/10); for (int i = 0; i < 2; i++) { auto layer_tree = - std::make_unique(/*frame_size=*/SkISize(), + std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(timestamps[i])); @@ -1045,7 +1045,7 @@ TEST(RasterizerTest, presentationTimeNotSetWhenVsyncTargetInPast) { thread_host.raster_thread->GetTaskRunner()->PostTask([&] { rasterizer->Setup(std::move(surface)); auto pipeline = std::make_shared(/*depth=*/10); - auto layer_tree = std::make_unique(/*frame_size=*/SkISize(), + auto layer_tree = std::make_shared(/*frame_size=*/SkISize(), /*device_pixel_ratio=*/2.0f); auto layer_tree_item = std::make_unique( std::move(layer_tree), CreateFinishedBuildRecorder(first_timestamp)); diff --git a/shell/common/shell_test.cc b/shell/common/shell_test.cc index 27f6b0f65f527..eca345058787f 100644 --- a/shell/common/shell_test.cc +++ b/shell/common/shell_test.cc @@ -197,7 +197,7 @@ void ShellTest::PumpOneFrame(Shell* shell, fml::WeakPtr runtime_delegate = shell->weak_engine_; shell->GetTaskRunners().GetUITaskRunner()->PostTask( [&latch, runtime_delegate, &builder, viewport_metrics]() { - auto layer_tree = std::make_unique( + auto layer_tree = std::make_shared( SkISize::Make(viewport_metrics.physical_width, viewport_metrics.physical_height), static_cast(viewport_metrics.device_pixel_ratio)); diff --git a/testing/dart/compositing_test.dart b/testing/dart/compositing_test.dart index 10c70978d22b5..01320919a52dd 100644 --- a/testing/dart/compositing_test.dart +++ b/testing/dart/compositing_test.dart @@ -36,6 +36,28 @@ void main() { 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(() {