forked from firka/flutter
Ensure that Scene::toImage renders texture backed images. (flutter/engine#6636)
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.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -53,46 +53,6 @@ void Scene::dispose() {
|
||||
ClearDartWrapper();
|
||||
}
|
||||
|
||||
static sk_sp<SkImage> CreateSceneSnapshot(GrContext* context,
|
||||
sk_sp<SkPicture> picture,
|
||||
const SkSize& size) {
|
||||
TRACE_EVENT0("flutter", "CreateSceneSnapshot");
|
||||
auto image_info =
|
||||
SkImageInfo::MakeN32Premul(SkISize::Make(size.width(), size.height()));
|
||||
|
||||
sk_sp<SkSurface> 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<tonic::DartPersistentValue>(
|
||||
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();
|
||||
auto ui_task = fml::MakeCopyable([ui_task_runner,
|
||||
image_callback = std::move(image_callback),
|
||||
unref_queue](
|
||||
sk_sp<SkImage> 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);
|
||||
|
||||
// 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);
|
||||
if (!raster_image) {
|
||||
tonic::DartInvoke(image_callback->Get(), {Dart_Null()});
|
||||
return;
|
||||
}
|
||||
|
||||
// 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);
|
||||
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));
|
||||
|
||||
if (!image) {
|
||||
tonic::DartInvoke(image_callback->Get(), {Dart_Null()});
|
||||
return;
|
||||
}
|
||||
// All done!
|
||||
tonic::DartInvoke(image_callback->Get(), {raw_dart_image});
|
||||
}));
|
||||
});
|
||||
|
||||
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));
|
||||
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 texture backed
|
||||
// images in the picture.
|
||||
ui_task(snapshot_delegate->MakeRasterSnapshot(picture, picture_bounds));
|
||||
});
|
||||
});
|
||||
|
||||
// All done!
|
||||
tonic::DartInvoke(image_callback->Get(), {raw_dart_image});
|
||||
}));
|
||||
}));
|
||||
// Kick things off on the GPU.
|
||||
gpu_task();
|
||||
|
||||
return Dart_Null();
|
||||
}
|
||||
|
||||
21
engine/src/flutter/lib/ui/snapshot_delegate.h
Normal file
21
engine/src/flutter/lib/ui/snapshot_delegate.h
Normal file
@@ -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<SkImage> MakeRasterSnapshot(sk_sp<SkPicture> picture,
|
||||
SkISize picture_size) = 0;
|
||||
};
|
||||
|
||||
} // namespace blink
|
||||
|
||||
#endif // FLUTTER_LIB_UI_SNAPSHOT_DELEGATE_H_
|
||||
@@ -16,6 +16,7 @@ namespace blink {
|
||||
UIDartState::UIDartState(TaskRunners task_runners,
|
||||
TaskObserverAdd add_callback,
|
||||
TaskObserverRemove remove_callback,
|
||||
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> 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<SnapshotDelegate> UIDartState::GetSnapshotDelegate() const {
|
||||
return snapshot_delegate_;
|
||||
}
|
||||
|
||||
fml::WeakPtr<GrContext> UIDartState::GetResourceContext() const {
|
||||
return resource_context_;
|
||||
}
|
||||
|
||||
@@ -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<flow::SkiaUnrefQueue> GetSkiaUnrefQueue() const;
|
||||
|
||||
fml::WeakPtr<SnapshotDelegate> GetSnapshotDelegate() const;
|
||||
|
||||
fml::WeakPtr<GrContext> 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<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> 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<SnapshotDelegate> snapshot_delegate_;
|
||||
fml::WeakPtr<GrContext> resource_context_;
|
||||
const std::string advisory_script_uri_;
|
||||
const std::string advisory_script_entrypoint_;
|
||||
|
||||
@@ -38,6 +38,7 @@ std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
|
||||
fml::RefPtr<DartSnapshot> shared_snapshot,
|
||||
TaskRunners task_runners,
|
||||
std::unique_ptr<Window> window,
|
||||
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
|
||||
std::string advisory_script_uri,
|
||||
@@ -54,14 +55,15 @@ std::weak_ptr<DartIsolate> DartIsolate::CreateRootIsolate(
|
||||
// isolate lifecycle is entirely managed by the VM).
|
||||
auto root_embedder_data = std::make_unique<std::shared_ptr<DartIsolate>>(
|
||||
std::make_shared<DartIsolate>(
|
||||
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<DartSnapshot> isolate_snapshot,
|
||||
fml::RefPtr<DartSnapshot> shared_snapshot,
|
||||
TaskRunners task_runners,
|
||||
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> 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<SnapshotDelegate>{}, // snapshot_delegate
|
||||
fml::WeakPtr<GrContext>{}, // resource_context
|
||||
nullptr, // unref_queue
|
||||
advisory_script_uri, // advisory_script_uri
|
||||
|
||||
@@ -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<DartSnapshot> shared_snapshot,
|
||||
TaskRunners task_runners,
|
||||
std::unique_ptr<Window> window,
|
||||
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
|
||||
std::string advisory_script_uri,
|
||||
@@ -54,6 +56,7 @@ class DartIsolate : public UIDartState {
|
||||
fml::RefPtr<DartSnapshot> isolate_snapshot,
|
||||
fml::RefPtr<DartSnapshot> shared_snapshot,
|
||||
TaskRunners task_runners,
|
||||
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
|
||||
std::string advisory_script_uri,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -24,6 +24,7 @@ RuntimeController::RuntimeController(
|
||||
fml::RefPtr<DartSnapshot> p_isolate_snapshot,
|
||||
fml::RefPtr<DartSnapshot> p_shared_snapshot,
|
||||
TaskRunners p_task_runners,
|
||||
fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> p_resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> 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<DartSnapshot> p_isolate_snapshot,
|
||||
fml::RefPtr<DartSnapshot> p_shared_snapshot,
|
||||
TaskRunners p_task_runners,
|
||||
fml::WeakPtr<SnapshotDelegate> p_snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> p_resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> 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<Window>(this),
|
||||
snapshot_delegate_,
|
||||
resource_context_,
|
||||
unref_queue_,
|
||||
p_advisory_script_uri,
|
||||
@@ -114,6 +119,7 @@ std::unique_ptr<RuntimeController> RuntimeController::Clone() const {
|
||||
isolate_snapshot_, //
|
||||
shared_snapshot_, //
|
||||
task_runners_, //
|
||||
snapshot_delegate_, //
|
||||
resource_context_, //
|
||||
unref_queue_, //
|
||||
advisory_script_uri_, //
|
||||
|
||||
@@ -32,6 +32,7 @@ class RuntimeController final : public WindowClient {
|
||||
fml::RefPtr<DartSnapshot> isolate_snapshot,
|
||||
fml::RefPtr<DartSnapshot> shared_snapshot,
|
||||
TaskRunners task_runners,
|
||||
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
|
||||
std::string advisory_script_uri,
|
||||
@@ -112,6 +113,7 @@ class RuntimeController final : public WindowClient {
|
||||
fml::RefPtr<DartSnapshot> isolate_snapshot_;
|
||||
fml::RefPtr<DartSnapshot> shared_snapshot_;
|
||||
TaskRunners task_runners_;
|
||||
fml::WeakPtr<SnapshotDelegate> snapshot_delegate_;
|
||||
fml::WeakPtr<GrContext> resource_context_;
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue_;
|
||||
std::string advisory_script_uri_;
|
||||
@@ -125,6 +127,7 @@ class RuntimeController final : public WindowClient {
|
||||
fml::RefPtr<DartSnapshot> isolate_snapshot,
|
||||
fml::RefPtr<DartSnapshot> shared_snapshot,
|
||||
TaskRunners task_runners,
|
||||
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue,
|
||||
std::string advisory_script_uri,
|
||||
|
||||
@@ -45,6 +45,7 @@ Engine::Engine(Delegate& delegate,
|
||||
blink::TaskRunners task_runners,
|
||||
blink::Settings settings,
|
||||
std::unique_ptr<Animator> animator,
|
||||
fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> 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
|
||||
|
||||
@@ -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> animator,
|
||||
fml::WeakPtr<blink::SnapshotDelegate> snapshot_delegate,
|
||||
fml::WeakPtr<GrContext> resource_context,
|
||||
fml::RefPtr<flow::SkiaUnrefQueue> unref_queue);
|
||||
|
||||
|
||||
@@ -39,6 +39,10 @@ fml::WeakPtr<Rasterizer> Rasterizer::GetWeakPtr() const {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
fml::WeakPtr<blink::SnapshotDelegate> Rasterizer::GetSnapshotDelegate() const {
|
||||
return weak_factory_.GetWeakPtr();
|
||||
}
|
||||
|
||||
void Rasterizer::Setup(std::unique_ptr<Surface> surface) {
|
||||
surface_ = std::move(surface);
|
||||
compositor_context_->OnGrContextCreated();
|
||||
@@ -89,6 +93,53 @@ void Rasterizer::Draw(
|
||||
}
|
||||
}
|
||||
|
||||
sk_sp<SkImage> Rasterizer::MakeRasterSnapshot(sk_sp<SkPicture> picture,
|
||||
SkISize picture_size) {
|
||||
TRACE_EVENT0("flutter", __FUNCTION__);
|
||||
|
||||
sk_sp<SkSurface> 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<SkImage> device_snapshot;
|
||||
{
|
||||
TRACE_EVENT0("flutter", "MakeDeviceSnpashot");
|
||||
device_snapshot = surface->makeImageSnapshot();
|
||||
}
|
||||
|
||||
if (device_snapshot == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
TRACE_EVENT0("flutter", "DeviceHostTransfer");
|
||||
if (auto raster_image = device_snapshot->makeRasterImage()) {
|
||||
return raster_image;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Rasterizer::DoDraw(std::unique_ptr<flow::LayerTree> layer_tree) {
|
||||
if (!layer_tree || !surface_) {
|
||||
return;
|
||||
|
||||
@@ -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<Rasterizer> GetWeakPtr() const;
|
||||
|
||||
fml::WeakPtr<blink::SnapshotDelegate> GetSnapshotDelegate() const;
|
||||
|
||||
flow::LayerTree* GetLastLayerTree();
|
||||
|
||||
void DrawLastLayerTree();
|
||||
@@ -75,6 +78,10 @@ class Rasterizer final {
|
||||
fml::closure next_frame_callback_;
|
||||
fml::WeakPtrFactory<Rasterizer> weak_factory_;
|
||||
|
||||
// |blink::SnapshotDelegate|
|
||||
sk_sp<SkImage> MakeRasterSnapshot(sk_sp<SkPicture> picture,
|
||||
SkISize picture_size) override;
|
||||
|
||||
void DoDraw(std::unique_ptr<flow::LayerTree> layer_tree);
|
||||
|
||||
bool DrawToSurface(flow::LayerTree& layer_tree);
|
||||
|
||||
@@ -92,31 +92,37 @@ std::unique_ptr<Shell> Shell::CreateShellOnPlatformThread(
|
||||
// Create the rasterizer on the GPU thread.
|
||||
fml::AutoResetWaitableEvent gpu_latch;
|
||||
std::unique_ptr<Rasterizer> rasterizer;
|
||||
fml::WeakPtr<blink::SnapshotDelegate> 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> 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> Shell::CreateShellOnPlatformThread(
|
||||
auto animator = std::make_unique<Animator>(*shell, task_runners,
|
||||
std::move(vsync_waiter));
|
||||
|
||||
engine = std::make_unique<Engine>(*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<Engine>(*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.
|
||||
|
||||
Reference in New Issue
Block a user