From 691f754d5cf3992987c23d7752f0ca8de10802b3 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 22 Oct 2018 17:05:59 -0700 Subject: [PATCH 1/3] Ensure that Scene::toImage renders texture backed images. TL;DR: Offscreen surface is created on the render thread and device to host transfer performed there before task completion on the UI thread. While attempting to snapshot layer trees, the engine was attempting to use the IO thread context. The reasoning was that this would be safe to do because any textures uploaded to the GPU as a result of async texture upload would have originated from this context and hence the handles would be valid in either context. As it turns out, while the handles are valid, Skia does not support this use-case because cross-context images transfer ownership of the image from one context to another. So, when we made the hop from the UI thread to the IO thread (for snapshotting), if either the UI or GPU threads released the last reference to the texture backed image, the image would be invalid. This led to such images being absent from the layer tree snapshot. Simply referencing the images as they are being used on the IO thread is not sufficient because accessing images on one context after their ownership has already been transferred to another is not safe behavior (from Skia's perspective, the handles are still valid in the sharegroup). To work around these issues, it was decided that an offscreen render target would be created on the render thread. The color attachment of this render target could then be transferred as a cross context image to the IO thread for the device to host tranfer. Again, this is currently not quite possible because the only way to create cross context images is from encoded data. Till Skia exposes the functionality to create cross-context images from textures in one context, we do a device to host transfer on the GPU thread. The side effect of this is that this is now part of the frame workload (image compression, which dominate the wall time, is still done of the IO thread). A minor side effect of this patch is that the GPU latch needs to be waited on before the UI thread tasks can be completed before shell initialization. --- lib/ui/BUILD.gn | 3 +- lib/ui/compositing/scene.cc | 139 +++++++++++------------------- lib/ui/snapshot_delegate.h | 21 +++++ lib/ui/ui_dart_state.cc | 6 ++ lib/ui/ui_dart_state.h | 5 ++ runtime/dart_isolate.cc | 22 +++-- runtime/dart_isolate.h | 3 + runtime/dart_isolate_unittests.cc | 2 + runtime/runtime_controller.cc | 6 ++ runtime/runtime_controller.h | 3 + shell/common/engine.cc | 2 + shell/common/engine.h | 2 + shell/common/rasterizer.cc | 51 +++++++++++ shell/common/rasterizer.h | 9 +- shell/common/shell.cc | 44 ++++++---- 15 files changed, 201 insertions(+), 117 deletions(-) create mode 100644 lib/ui/snapshot_delegate.h diff --git a/lib/ui/BUILD.gn b/lib/ui/BUILD.gn index 28791a35af619..06c46bc37f1c8 100644 --- a/lib/ui/BUILD.gn +++ b/lib/ui/BUILD.gn @@ -23,8 +23,8 @@ source_set("ui") { "painting/canvas.h", "painting/codec.cc", "painting/codec.h", - "painting/engine_layer.h", "painting/engine_layer.cc", + "painting/engine_layer.h", "painting/frame_info.cc", "painting/frame_info.h", "painting/gradient.cc", @@ -65,6 +65,7 @@ source_set("ui") { "semantics/semantics_update.h", "semantics/semantics_update_builder.cc", "semantics/semantics_update_builder.h", + "snapshot_delegate.h", "text/asset_manager_font_provider.cc", "text/asset_manager_font_provider.h", "text/font_collection.cc", diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 735ce44197921..6bb51f215fd41 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -53,46 +53,6 @@ void Scene::dispose() { ClearDartWrapper(); } -static sk_sp CreateSceneSnapshot(GrContext* context, - sk_sp picture, - const SkSize& size) { - TRACE_EVENT0("flutter", "CreateSceneSnapshot"); - auto image_info = - SkImageInfo::MakeN32Premul(SkISize::Make(size.width(), size.height())); - - sk_sp surface; - - if (context) { - surface = SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, image_info); - } - - if (!surface) { - surface = SkSurface::MakeRaster(image_info); - } - - if (!surface) { - return nullptr; - } - - auto canvas = surface->getCanvas(); - - if (!canvas) { - return nullptr; - } - - if (picture) { - canvas->drawPicture(picture.get()); - } - - auto snapshot = surface->makeImageSnapshot(); - - if (!snapshot) { - return nullptr; - } - - return snapshot->makeRasterImage(); -} - Dart_Handle Scene::toImage(uint32_t width, uint32_t height, Dart_Handle raw_image_callback) { @@ -110,67 +70,70 @@ Dart_Handle Scene::toImage(uint32_t width, } auto dart_state = UIDartState::Current(); - auto image_callback = std::make_unique( dart_state, raw_image_callback); + auto unref_queue = dart_state->GetSkiaUnrefQueue(); + auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); + auto gpu_task_runner = dart_state->GetTaskRunners().GetGPUTaskRunner(); + auto snapshot_delegate = dart_state->GetSnapshotDelegate(); // We can't create an image on this task runner because we don't have a // graphics context. Even if we did, it would be slow anyway. Also, this // thread owns the sole reference to the layer tree. So we flatten the layer // tree into a picture and use that as the thread transport mechanism. - auto bounds_size = SkSize::Make(width, height); - auto picture = m_layerTree->Flatten(SkRect::MakeSize(bounds_size)); + auto picture_bounds = SkISize::Make(width, height); + auto picture = m_layerTree->Flatten(SkRect::MakeWH(width, height)); + if (!picture) { // Already in Dart scope. return tonic::ToDart("Could not flatten scene into a layer tree."); } - auto resource_context = dart_state->GetResourceContext(); - auto ui_task_runner = dart_state->GetTaskRunners().GetUITaskRunner(); - auto unref_queue = dart_state->GetSkiaUnrefQueue(); - - // The picture has been prepared on the UI thread. - dart_state->GetTaskRunners().GetIOTaskRunner()->PostTask( - fml::MakeCopyable([picture = std::move(picture), // - bounds_size, // - resource_context = std::move(resource_context), // - ui_task_runner = std::move(ui_task_runner), // - image_callback = std::move(image_callback), // - unref_queue = std::move(unref_queue) // - ]() mutable { - // Snapshot the picture on the IO thread that contains an optional - // GrContext. - auto image = CreateSceneSnapshot(resource_context.get(), - std::move(picture), bounds_size); - - // Send the image back to the UI thread for submission back to the - // framework. - ui_task_runner->PostTask( - fml::MakeCopyable([image = std::move(image), // - image_callback = std::move(image_callback), // - unref_queue = std::move(unref_queue) // - ]() mutable { - auto dart_state = image_callback->dart_state().lock(); - if (!dart_state) { - // The root isolate could have died in the meantime. - return; - } - tonic::DartState::Scope scope(dart_state); - - if (!image) { - tonic::DartInvoke(image_callback->Get(), {Dart_Null()}); - return; - } - - auto dart_image = CanvasImage::Create(); - dart_image->set_image({std::move(image), std::move(unref_queue)}); - auto raw_dart_image = tonic::ToDart(std::move(dart_image)); - - // All done! - tonic::DartInvoke(image_callback->Get(), {raw_dart_image}); - })); - })); + auto ui_task = fml::MakeCopyable([ui_task_runner, + image_callback = std::move(image_callback), + unref_queue]( + sk_sp raster_image) mutable { + // Send the raster image back to the UI thread for submission to the + // framework. + ui_task_runner->PostTask(fml::MakeCopyable([raster_image, + image_callback = + std::move(image_callback), + unref_queue]() mutable { + auto dart_state = image_callback->dart_state().lock(); + if (!dart_state) { + // The root isolate could have died in the meantime. + return; + } + tonic::DartState::Scope scope(dart_state); + + if (!raster_image) { + tonic::DartInvoke(image_callback->Get(), {Dart_Null()}); + return; + } + + auto dart_image = CanvasImage::Create(); + dart_image->set_image({std::move(raster_image), std::move(unref_queue)}); + auto raw_dart_image = tonic::ToDart(std::move(dart_image)); + + // All done! + tonic::DartInvoke(image_callback->Get(), {raw_dart_image}); + })); + }); + + auto gpu_task = fml::MakeCopyable([gpu_task_runner, picture, picture_bounds, + snapshot_delegate, ui_task]() { + gpu_task_runner->PostTask([snapshot_delegate, picture, picture_bounds, + ui_task]() { + // Snapshot the picture on the GPU thread. This thread has access to the + // GPU contexts that may contain the sole references to a texture backed + // images in the picture. + ui_task(snapshot_delegate->MakeRasterSnapshot(picture, picture_bounds)); + }); + }); + + // Kick things off on the GPU. + gpu_task(); return Dart_Null(); } diff --git a/lib/ui/snapshot_delegate.h b/lib/ui/snapshot_delegate.h new file mode 100644 index 0000000000000..ceca0e7b35cd7 --- /dev/null +++ b/lib/ui/snapshot_delegate.h @@ -0,0 +1,21 @@ +// Copyright 2018 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_LIB_UI_SNAPSHOT_DELEGATE_H_ +#define FLUTTER_LIB_UI_SNAPSHOT_DELEGATE_H_ + +#include "third_party/skia/include/core/SkImage.h" +#include "third_party/skia/include/core/SkPicture.h" + +namespace blink { + +class SnapshotDelegate { + public: + virtual sk_sp MakeRasterSnapshot(sk_sp picture, + SkISize picture_size) = 0; +}; + +} // namespace blink + +#endif // FLUTTER_LIB_UI_SNAPSHOT_DELEGATE_H_ diff --git a/lib/ui/ui_dart_state.cc b/lib/ui/ui_dart_state.cc index 0d762f785262d..3903b4b23c736 100644 --- a/lib/ui/ui_dart_state.cc +++ b/lib/ui/ui_dart_state.cc @@ -16,6 +16,7 @@ namespace blink { UIDartState::UIDartState(TaskRunners task_runners, TaskObserverAdd add_callback, TaskObserverRemove remove_callback, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr skia_unref_queue, std::string advisory_script_uri, @@ -25,6 +26,7 @@ UIDartState::UIDartState(TaskRunners task_runners, : task_runners_(std::move(task_runners)), add_callback_(std::move(add_callback)), remove_callback_(std::move(remove_callback)), + snapshot_delegate_(std::move(snapshot_delegate)), resource_context_(std::move(resource_context)), advisory_script_uri_(std::move(advisory_script_uri)), advisory_script_entrypoint_(std::move(advisory_script_entrypoint)), @@ -99,6 +101,10 @@ void UIDartState::AddOrRemoveTaskObserver(bool add) { } } +fml::WeakPtr UIDartState::GetSnapshotDelegate() const { + return snapshot_delegate_; +} + fml::WeakPtr UIDartState::GetResourceContext() const { return resource_context_; } diff --git a/lib/ui/ui_dart_state.h b/lib/ui/ui_dart_state.h index dea3e9b650447..2fafb0537ae30 100644 --- a/lib/ui/ui_dart_state.h +++ b/lib/ui/ui_dart_state.h @@ -15,6 +15,7 @@ #include "flutter/fml/build_config.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/lib/ui/isolate_name_server/isolate_name_server.h" +#include "flutter/lib/ui/snapshot_delegate.h" #include "third_party/dart/runtime/include/dart_api.h" #include "third_party/skia/include/gpu/GrContext.h" #include "third_party/tonic/dart_microtask_queue.h" @@ -47,6 +48,8 @@ class UIDartState : public tonic::DartState { fml::RefPtr GetSkiaUnrefQueue() const; + fml::WeakPtr GetSnapshotDelegate() const; + fml::WeakPtr GetResourceContext() const; IsolateNameServer* GetIsolateNameServer(); @@ -68,6 +71,7 @@ class UIDartState : public tonic::DartState { UIDartState(TaskRunners task_runners, TaskObserverAdd add_callback, TaskObserverRemove remove_callback, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr skia_unref_queue, std::string advisory_script_uri, @@ -89,6 +93,7 @@ class UIDartState : public tonic::DartState { const TaskRunners task_runners_; const TaskObserverAdd add_callback_; const TaskObserverRemove remove_callback_; + fml::WeakPtr snapshot_delegate_; fml::WeakPtr resource_context_; const std::string advisory_script_uri_; const std::string advisory_script_entrypoint_; diff --git a/runtime/dart_isolate.cc b/runtime/dart_isolate.cc index ef62d141b3e77..784f650f6fdb0 100644 --- a/runtime/dart_isolate.cc +++ b/runtime/dart_isolate.cc @@ -38,6 +38,7 @@ std::weak_ptr DartIsolate::CreateRootIsolate( fml::RefPtr shared_snapshot, TaskRunners task_runners, std::unique_ptr window, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr unref_queue, std::string advisory_script_uri, @@ -54,14 +55,15 @@ std::weak_ptr DartIsolate::CreateRootIsolate( // isolate lifecycle is entirely managed by the VM). auto root_embedder_data = std::make_unique>( std::make_shared( - vm, // VM - std::move(isolate_snapshot), // isolate snapshot - std::move(shared_snapshot), // shared snapshot - task_runners, // task runners - std::move(resource_context), // resource context - std::move(unref_queue), // skia unref queue - advisory_script_uri, // advisory URI - advisory_script_entrypoint, // advisory entrypoint + vm, // VM + std::move(isolate_snapshot), // isolate snapshot + std::move(shared_snapshot), // shared snapshot + task_runners, // task runners + std::move(snapshot_delegate), // snapshot delegate + std::move(resource_context), // resource context + std::move(unref_queue), // skia unref queue + advisory_script_uri, // advisory URI + advisory_script_entrypoint, // advisory entrypoint nullptr // child isolate preparer will be set when this isolate is // prepared to run )); @@ -101,6 +103,7 @@ DartIsolate::DartIsolate(DartVM* vm, fml::RefPtr isolate_snapshot, fml::RefPtr shared_snapshot, TaskRunners task_runners, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr unref_queue, std::string advisory_script_uri, @@ -109,6 +112,7 @@ DartIsolate::DartIsolate(DartVM* vm, : UIDartState(std::move(task_runners), vm->GetSettings().task_observer_add, vm->GetSettings().task_observer_remove, + std::move(snapshot_delegate), std::move(resource_context), std::move(unref_queue), advisory_script_uri, @@ -520,6 +524,7 @@ Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate( vm->GetSharedSnapshot(), // shared snapshot null_task_runners, // task runners nullptr, // window + {}, // snapshot delegate {}, // resource context {}, // unref queue advisory_script_uri == nullptr ? "" @@ -630,6 +635,7 @@ DartIsolate::CreateDartVMAndEmbedderObjectPair( (*raw_embedder_isolate)->GetIsolateSnapshot(), // isolate_snapshot (*raw_embedder_isolate)->GetSharedSnapshot(), // shared_snapshot null_task_runners, // task_runners + fml::WeakPtr{}, // snapshot_delegate fml::WeakPtr{}, // resource_context nullptr, // unref_queue advisory_script_uri, // advisory_script_uri diff --git a/runtime/dart_isolate.h b/runtime/dart_isolate.h index f2167364effdd..e17ba08c66be0 100644 --- a/runtime/dart_isolate.h +++ b/runtime/dart_isolate.h @@ -12,6 +12,7 @@ #include "flutter/fml/compiler_specific.h" #include "flutter/fml/macros.h" #include "flutter/fml/mapping.h" +#include "flutter/lib/ui/snapshot_delegate.h" #include "flutter/lib/ui/ui_dart_state.h" #include "flutter/lib/ui/window/window.h" #include "flutter/runtime/dart_snapshot.h" @@ -44,6 +45,7 @@ class DartIsolate : public UIDartState { fml::RefPtr shared_snapshot, TaskRunners task_runners, std::unique_ptr window, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr unref_queue, std::string advisory_script_uri, @@ -54,6 +56,7 @@ class DartIsolate : public UIDartState { fml::RefPtr isolate_snapshot, fml::RefPtr shared_snapshot, TaskRunners task_runners, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr unref_queue, std::string advisory_script_uri, diff --git a/runtime/dart_isolate_unittests.cc b/runtime/dart_isolate_unittests.cc index f876d349a2648..44547d3190139 100644 --- a/runtime/dart_isolate_unittests.cc +++ b/runtime/dart_isolate_unittests.cc @@ -35,6 +35,7 @@ TEST_F(DartIsolateTest, RootIsolateCreationAndShutdown) { vm->GetSharedSnapshot(), // shared snapshot std::move(task_runners), // task runners nullptr, // window + {}, // snapshot delegate {}, // resource context nullptr, // unref qeueue "main.dart", // advisory uri @@ -64,6 +65,7 @@ TEST_F(DartIsolateTest, IsolateShutdownCallbackIsInIsolateScope) { vm->GetSharedSnapshot(), // shared snapshot std::move(task_runners), // task runners nullptr, // window + {}, // snapshot delegate {}, // resource context nullptr, // unref qeueue "main.dart", // advisory uri diff --git a/runtime/runtime_controller.cc b/runtime/runtime_controller.cc index 956a6a6a862c7..ace1b9b7a2183 100644 --- a/runtime/runtime_controller.cc +++ b/runtime/runtime_controller.cc @@ -24,6 +24,7 @@ RuntimeController::RuntimeController( fml::RefPtr p_isolate_snapshot, fml::RefPtr p_shared_snapshot, TaskRunners p_task_runners, + fml::WeakPtr p_snapshot_delegate, fml::WeakPtr p_resource_context, fml::RefPtr p_unref_queue, std::string p_advisory_script_uri, @@ -33,6 +34,7 @@ RuntimeController::RuntimeController( std::move(p_isolate_snapshot), std::move(p_shared_snapshot), std::move(p_task_runners), + std::move(p_snapshot_delegate), std::move(p_resource_context), std::move(p_unref_queue), std::move(p_advisory_script_uri), @@ -45,6 +47,7 @@ RuntimeController::RuntimeController( fml::RefPtr p_isolate_snapshot, fml::RefPtr p_shared_snapshot, TaskRunners p_task_runners, + fml::WeakPtr p_snapshot_delegate, fml::WeakPtr p_resource_context, fml::RefPtr p_unref_queue, std::string p_advisory_script_uri, @@ -55,6 +58,7 @@ RuntimeController::RuntimeController( isolate_snapshot_(std::move(p_isolate_snapshot)), shared_snapshot_(std::move(p_shared_snapshot)), task_runners_(p_task_runners), + snapshot_delegate_(p_snapshot_delegate), resource_context_(p_resource_context), unref_queue_(p_unref_queue), advisory_script_uri_(p_advisory_script_uri), @@ -66,6 +70,7 @@ RuntimeController::RuntimeController( shared_snapshot_, task_runners_, std::make_unique(this), + snapshot_delegate_, resource_context_, unref_queue_, p_advisory_script_uri, @@ -114,6 +119,7 @@ std::unique_ptr RuntimeController::Clone() const { isolate_snapshot_, // shared_snapshot_, // task_runners_, // + snapshot_delegate_, // resource_context_, // unref_queue_, // advisory_script_uri_, // diff --git a/runtime/runtime_controller.h b/runtime/runtime_controller.h index ac1bfca1f9333..839fcd6a327e0 100644 --- a/runtime/runtime_controller.h +++ b/runtime/runtime_controller.h @@ -32,6 +32,7 @@ class RuntimeController final : public WindowClient { fml::RefPtr isolate_snapshot, fml::RefPtr shared_snapshot, TaskRunners task_runners, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr unref_queue, std::string advisory_script_uri, @@ -112,6 +113,7 @@ class RuntimeController final : public WindowClient { fml::RefPtr isolate_snapshot_; fml::RefPtr shared_snapshot_; TaskRunners task_runners_; + fml::WeakPtr snapshot_delegate_; fml::WeakPtr resource_context_; fml::RefPtr unref_queue_; std::string advisory_script_uri_; @@ -125,6 +127,7 @@ class RuntimeController final : public WindowClient { fml::RefPtr isolate_snapshot, fml::RefPtr shared_snapshot, TaskRunners task_runners, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr unref_queue, std::string advisory_script_uri, diff --git a/shell/common/engine.cc b/shell/common/engine.cc index 3ab484c46f37c..59cff299b7ab0 100644 --- a/shell/common/engine.cc +++ b/shell/common/engine.cc @@ -45,6 +45,7 @@ Engine::Engine(Delegate& delegate, blink::TaskRunners task_runners, blink::Settings settings, std::unique_ptr animator, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr unref_queue) : delegate_(delegate), @@ -62,6 +63,7 @@ Engine::Engine(Delegate& delegate, std::move(isolate_snapshot), // isolate snapshot std::move(shared_snapshot), // shared snapshot std::move(task_runners), // task runners + std::move(snapshot_delegate), // snapshot delegate std::move(resource_context), // resource context std::move(unref_queue), // skia unref queue settings_.advisory_script_uri, // advisory script uri diff --git a/shell/common/engine.h b/shell/common/engine.h index 06436ce3683d0..0f79eeeb31c00 100644 --- a/shell/common/engine.h +++ b/shell/common/engine.h @@ -14,6 +14,7 @@ #include "flutter/fml/memory/weak_ptr.h" #include "flutter/lib/ui/semantics/custom_accessibility_action.h" #include "flutter/lib/ui/semantics/semantics_node.h" +#include "flutter/lib/ui/snapshot_delegate.h" #include "flutter/lib/ui/text/font_collection.h" #include "flutter/lib/ui/window/platform_message.h" #include "flutter/lib/ui/window/viewport_metrics.h" @@ -56,6 +57,7 @@ class Engine final : public blink::RuntimeDelegate { blink::TaskRunners task_runners, blink::Settings settings, std::unique_ptr animator, + fml::WeakPtr snapshot_delegate, fml::WeakPtr resource_context, fml::RefPtr unref_queue); diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 6f08b2afd0b7e..64e3a1c5459cc 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -39,6 +39,10 @@ fml::WeakPtr Rasterizer::GetWeakPtr() const { return weak_factory_.GetWeakPtr(); } +fml::WeakPtr Rasterizer::GetSnapshotDelegate() const { + return weak_factory_.GetWeakPtr(); +} + void Rasterizer::Setup(std::unique_ptr surface) { surface_ = std::move(surface); compositor_context_->OnGrContextCreated(); @@ -89,6 +93,53 @@ void Rasterizer::Draw( } } +sk_sp Rasterizer::MakeRasterSnapshot(sk_sp picture, + SkISize picture_size) { + TRACE_EVENT0("flutter", __FUNCTION__); + + sk_sp surface; + 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(SkImageInfo::MakeN32Premul(picture_size)); + } else { + // 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 + SkImageInfo::MakeN32Premul(picture_size) // image info + ); + } + + if (surface == nullptr || surface->getCanvas() == nullptr) { + return nullptr; + } + + surface->getCanvas()->drawPicture(picture.get()); + + surface->getCanvas()->flush(); + + sk_sp device_snapshot; + { + TRACE_EVENT0("flutter", "MakeDeviceSnpshot"); + device_snapshot = surface->makeImageSnapshot(); + } + + if (device_snapshot == nullptr) { + return nullptr; + } + + { + TRACE_EVENT0("flutter", "DeviceHostTranfer"); + if (auto raster_image = device_snapshot->makeRasterImage()) { + return raster_image; + } + } + + return nullptr; +} + void Rasterizer::DoDraw(std::unique_ptr layer_tree) { if (!layer_tree || !surface_) { return; diff --git a/shell/common/rasterizer.h b/shell/common/rasterizer.h index 1d3c03d8953df..5bffb104f8519 100644 --- a/shell/common/rasterizer.h +++ b/shell/common/rasterizer.h @@ -13,12 +13,13 @@ #include "flutter/fml/closure.h" #include "flutter/fml/memory/weak_ptr.h" #include "flutter/fml/synchronization/waitable_event.h" +#include "flutter/lib/ui/snapshot_delegate.h" #include "flutter/shell/common/surface.h" #include "flutter/synchronization/pipeline.h" namespace shell { -class Rasterizer final { +class Rasterizer final : public blink::SnapshotDelegate { public: Rasterizer(blink::TaskRunners task_runners); @@ -33,6 +34,8 @@ class Rasterizer final { fml::WeakPtr GetWeakPtr() const; + fml::WeakPtr GetSnapshotDelegate() const; + flow::LayerTree* GetLastLayerTree(); void DrawLastLayerTree(); @@ -75,6 +78,10 @@ class Rasterizer final { fml::closure next_frame_callback_; fml::WeakPtrFactory weak_factory_; + // |blink::SnapshotDelegate| + sk_sp MakeRasterSnapshot(sk_sp picture, + SkISize picture_size) override; + void DoDraw(std::unique_ptr layer_tree); bool DrawToSurface(flow::LayerTree& layer_tree); diff --git a/shell/common/shell.cc b/shell/common/shell.cc index 8f07f500588a4..1139be8531c94 100644 --- a/shell/common/shell.cc +++ b/shell/common/shell.cc @@ -92,31 +92,37 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( // Create the rasterizer on the GPU thread. fml::AutoResetWaitableEvent gpu_latch; std::unique_ptr rasterizer; + fml::WeakPtr snapshot_delegate; fml::TaskRunner::RunNowOrPostTask( task_runners.GetGPUTaskRunner(), [&gpu_latch, // &rasterizer, // on_create_rasterizer, // - shell = shell.get() // + shell = shell.get(), // + &snapshot_delegate // ]() { if (auto new_rasterizer = on_create_rasterizer(*shell)) { rasterizer = std::move(new_rasterizer); + snapshot_delegate = rasterizer->GetSnapshotDelegate(); } gpu_latch.Signal(); }); + gpu_latch.Wait(); + // Create the engine on the UI thread. fml::AutoResetWaitableEvent ui_latch; std::unique_ptr engine; fml::TaskRunner::RunNowOrPostTask( shell->GetTaskRunners().GetUITaskRunner(), - fml::MakeCopyable([&ui_latch, // - &engine, // - shell = shell.get(), // - isolate_snapshot = std::move(isolate_snapshot), // - shared_snapshot = std::move(shared_snapshot), // - vsync_waiter = std::move(vsync_waiter), // - resource_context = std::move(resource_context), // - unref_queue = std::move(unref_queue) // + fml::MakeCopyable([&ui_latch, // + &engine, // + shell = shell.get(), // + isolate_snapshot = std::move(isolate_snapshot), // + shared_snapshot = std::move(shared_snapshot), // + vsync_waiter = std::move(vsync_waiter), // + snapshot_delegate = std::move(snapshot_delegate), // + resource_context = std::move(resource_context), // + unref_queue = std::move(unref_queue) // ]() mutable { const auto& task_runners = shell->GetTaskRunners(); @@ -125,20 +131,20 @@ std::unique_ptr Shell::CreateShellOnPlatformThread( auto animator = std::make_unique(*shell, task_runners, std::move(vsync_waiter)); - engine = std::make_unique(*shell, // - shell->GetDartVM(), // - std::move(isolate_snapshot), // - std::move(shared_snapshot), // - task_runners, // - shell->GetSettings(), // - std::move(animator), // - std::move(resource_context), // - std::move(unref_queue) // + engine = std::make_unique(*shell, // + shell->GetDartVM(), // + std::move(isolate_snapshot), // + std::move(shared_snapshot), // + task_runners, // + shell->GetSettings(), // + std::move(animator), // + std::move(snapshot_delegate), // + std::move(resource_context), // + std::move(unref_queue) // ); ui_latch.Signal(); })); - gpu_latch.Wait(); ui_latch.Wait(); // We are already on the platform thread. So there is no platform latch to // wait on. From 9ee7e23eb0953e469863130108310b68fdba075e Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 22 Oct 2018 17:20:39 -0700 Subject: [PATCH 2/3] Licenses --- ci/licenses_golden/licenses_flutter | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index 905c8dcdf24de..acefd7e4a9672 100644 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -507,6 +507,7 @@ FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.cc FILE: ../../../flutter/lib/ui/isolate_name_server/isolate_name_server_natives.h FILE: ../../../flutter/lib/ui/plugins/callback_cache.cc FILE: ../../../flutter/lib/ui/plugins/callback_cache.h +FILE: ../../../flutter/lib/ui/snapshot_delegate.h FILE: ../../../flutter/runtime/dart_service_isolate_unittests.cc FILE: ../../../flutter/shell/common/isolate_configuration.cc FILE: ../../../flutter/shell/common/isolate_configuration.h From 6308e5aa7155d790bc59c5e5c11b971c8978db7d Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Mon, 22 Oct 2018 17:31:50 -0700 Subject: [PATCH 3/3] PR --- lib/ui/compositing/scene.cc | 2 +- shell/common/rasterizer.cc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/compositing/scene.cc b/lib/ui/compositing/scene.cc index 6bb51f215fd41..3629637688a2a 100644 --- a/lib/ui/compositing/scene.cc +++ b/lib/ui/compositing/scene.cc @@ -126,7 +126,7 @@ Dart_Handle Scene::toImage(uint32_t width, gpu_task_runner->PostTask([snapshot_delegate, picture, picture_bounds, ui_task]() { // Snapshot the picture on the GPU thread. This thread has access to the - // GPU contexts that may contain the sole references to a texture backed + // GPU contexts that may contain the sole references to texture backed // images in the picture. ui_task(snapshot_delegate->MakeRasterSnapshot(picture, picture_bounds)); }); diff --git a/shell/common/rasterizer.cc b/shell/common/rasterizer.cc index 64e3a1c5459cc..9a870326dd2d5 100644 --- a/shell/common/rasterizer.cc +++ b/shell/common/rasterizer.cc @@ -122,7 +122,7 @@ sk_sp Rasterizer::MakeRasterSnapshot(sk_sp picture, sk_sp device_snapshot; { - TRACE_EVENT0("flutter", "MakeDeviceSnpshot"); + TRACE_EVENT0("flutter", "MakeDeviceSnpashot"); device_snapshot = surface->makeImageSnapshot(); } @@ -131,7 +131,7 @@ sk_sp Rasterizer::MakeRasterSnapshot(sk_sp picture, } { - TRACE_EVENT0("flutter", "DeviceHostTranfer"); + TRACE_EVENT0("flutter", "DeviceHostTransfer"); if (auto raster_image = device_snapshot->makeRasterImage()) { return raster_image; }