Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 31 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
c82840f
delete dl flag from allowlist
Jul 7, 2022
856069a
hhacky
Jul 13, 2022
679d7f2
Merge branch 'master' of github.com:flutter/engine into hack_for_text…
Jul 13, 2022
614836d
Re-arrange interface
Jul 13, 2022
73197e9
++
Jul 13, 2022
8ba46b2
Update snapshot_delegate.h
Jul 13, 2022
11d1844
run flatten on raster thread
Jul 13, 2022
68bb764
make FlattenWithContext an optional parameter on Flatten
Jul 13, 2022
36bed16
++
Jul 13, 2022
550a907
Update layer_tree.h
Jul 13, 2022
cd92c27
Merge branch 'hack_for_texture_view' of github.com:jonahwilliams/engi…
Jul 13, 2022
a8c43a0
amost works
Jul 13, 2022
87c2edb
almost
Jul 13, 2022
1fb2718
change to shared_ptr
Jul 13, 2022
b3c0e00
++
Jul 14, 2022
f7c8de4
add nullchecks and texture test
Jul 18, 2022
f612d0e
Merge branch 'master' of github.com:flutter/engine into hack_for_text…
Jul 18, 2022
3d21528
++
Jul 18, 2022
abdf5b8
Update compositing_test.dart
Jul 18, 2022
62437b4
Merge branch 'hack_for_texture_view' of github.com:jonahwilliams/engi…
Jul 20, 2022
844c4dd
Merge branch 'master' of github.com:flutter/engine into hack_for_text…
Jul 20, 2022
bcb3f44
Work in progress unification of toImage and toImageSync
Jul 20, 2022
b628bfd
Merge branch 'master' of github.com:flutter/engine into hack_for_text…
Jul 21, 2022
535a8c8
++
Jul 21, 2022
9c0a286
include gr direct context
Jul 21, 2022
2a1a51c
++
Jul 21, 2022
acfb369
Merge branch 'master' of github.com:flutter/engine into hack_for_text…
Jul 22, 2022
a3e8b53
Merge branch 'master' of github.com:flutter/engine into hack_for_text…
Aug 19, 2022
fdf2f5a
sync to head
Aug 19, 2022
eff8964
I dont know cpp
Aug 19, 2022
8b3dd48
fix size
Aug 19, 2022
da5b3a1
revert toImage change
Aug 19, 2022
9708ebe
dnfield review
Aug 19, 2022
a802cc5
Add some doc comments
Aug 19, 2022
657902b
++
Aug 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions flow/layers/layer_tree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -171,29 +171,33 @@ void LayerTree::Paint(CompositorContext::ScopedFrame& frame,
}
}

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);

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,
.cull_rect = kGiantRect,
.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
Expand All @@ -209,12 +213,12 @@ sk_sp<DisplayList> 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_,
Expand Down
6 changes: 5 additions & 1 deletion flow/layers/layer_tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -41,7 +42,10 @@ class LayerTree {
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(); }

Expand Down
17 changes: 7 additions & 10 deletions lib/ui/compositing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ 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
/// will be shared with other methods or classes, [Image.clone] should be used
Expand All @@ -47,18 +46,16 @@ class Scene extends NativeFieldWrapperClass1 {
if (width <= 0 || height <= 0) {
throw Exception('Invalid image dimensions.');
}
return _futurize((_Callback<Image?> callback) => _toImage(width, height, (_Image? image) {
if (image == null) {
callback(null);
} else {
callback(Image._(image, image.width, image.height));
}
}),
);
final _Image image = _Image._();
final String? result = _toImage(width, height, image);
if (result != null) {
throw PictureRasterizationException._(result);
}
return Future<Image>.value(Image._(image, image.width, image.height));
}

@FfiNative<Handle Function(Pointer<Void>, Uint32, Uint32, Handle)>('Scene::toImage')
external String? _toImage(int width, int height, _Callback<_Image?> callback);
external String? _toImage(int width, int height, _Image outImage);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is the right choice here.

The current API returns a host copy of the image every time, which can't get lost of GPU context gets lost and is safe to use in the background.

The new API fails in this scenario:

final image = await scene.toImage(40, 40);
// go to background
final data = await image.toByteData(...); // won't work.

I think we should try to merge these in the C++ layer for now.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we could let the APIs diverge then, but I'm not sure of the exact mechanics here. Since the texture registry is only available on the raster thread, don't we need to both flatten and rasterize on that thread in order to retain the contents?

We can always punt on this for now, but I'd like to figure out what the path forward is.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e. can I tweak the toImage path to flatten/rasterize on the raster thread and still be safe here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toImage already posts a task to the raster thread. We'd just need to move the flattening of the layer tree to that task.

I think the path forward would be to refactor Picture::RasterizeToImage so that its guts live on Scene::RasterizeToImage and the scene version knows how to convert a layer tree to a display list on the raster thread (but also can still take a display list if the call is coming from Picture, which already has one).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it


/// Releases the resources used by this scene.
///
Expand Down
42 changes: 28 additions & 14 deletions lib/ui/compositing/scene.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -42,7 +43,7 @@ Scene::Scene(std::shared_ptr<flutter::Layer> rootLayer,
->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));
Expand All @@ -69,33 +70,46 @@ 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();
}

Dart_Handle Scene::toImage(uint32_t width,
uint32_t height,
Dart_Handle raw_image_callback) {
Dart_Handle raw_image_handle) {
TRACE_EVENT0("flutter", "Scene::toImage");

if (!layer_tree_) {
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.");
}
Scene::RasterizeToImage(width, height, raw_image_handle);
return Dart_Null();
}

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_), width, height,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

width, height are redundant with what's stored in the SkImageInfo.

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<flutter::LayerTree> Scene::takeLayerTree() {
std::shared_ptr<flutter::LayerTree> Scene::takeLayerTree() {
return std::move(layer_tree_);
}

Expand Down
25 changes: 17 additions & 8 deletions lib/ui/compositing/scene.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,25 +26,34 @@ class Scene : public RefCountedDartWrappable<Scene> {
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,
Dart_Handle raw_image_handle);

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);

std::unique_ptr<flutter::LayerTree> layer_tree_;
Scene(std::shared_ptr<flutter::Layer> 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<flutter::LayerTree> layer_tree_;
};

} // namespace flutter
Expand Down
71 changes: 63 additions & 8 deletions lib/ui/painting/display_list_deferred_image_gpu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ sk_sp<DlDeferredImageGPU> DlDeferredImageGPU::Make(
raster_task_runner));
}

sk_sp<DlDeferredImageGPU> DlDeferredImageGPU::MakeFromLayerTree(
const SkImageInfo& image_info,
std::shared_ptr<LayerTree> layer_tree,
uint32_t width,
uint32_t height,
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), width,
height, 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)
Expand Down Expand Up @@ -86,23 +102,50 @@ DlDeferredImageGPU::ImageWrapper::Make(
fml::RefPtr<fml::TaskRunner> raster_task_runner,
fml::RefPtr<SkiaUnrefQueue> unref_queue) {
auto wrapper = std::shared_ptr<ImageWrapper>(new ImageWrapper(
image_info, std::move(display_list), std::move(snapshot_delegate),
std::move(raster_task_runner), std::move(unref_queue)));
image_info,
std::variant<sk_sp<DisplayList>, std::shared_ptr<LayerTree>>(
std::move(display_list)),
std::move(snapshot_delegate), std::move(raster_task_runner),
std::move(unref_queue), 0, 0));
wrapper->SnapshotDisplayList();
return wrapper;
}

std::shared_ptr<DlDeferredImageGPU::ImageWrapper>
DlDeferredImageGPU::ImageWrapper::MakeFromLayerTree(
const SkImageInfo& image_info,
std::shared_ptr<LayerTree> layer_tree,
uint32_t width,
uint32_t height,
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,
std::variant<sk_sp<DisplayList>, std::shared_ptr<LayerTree>>(
std::move(layer_tree)),
std::move(snapshot_delegate), std::move(raster_task_runner),
std::move(unref_queue), width, height));
wrapper->SnapshotDisplayList();
return wrapper;
}

DlDeferredImageGPU::ImageWrapper::ImageWrapper(
const SkImageInfo& image_info,
sk_sp<DisplayList> display_list,
std::variant<sk_sp<DisplayList>, std::shared_ptr<LayerTree>>
display_list_or_layer_tree,
fml::WeakPtr<SnapshotDelegate> snapshot_delegate,
fml::RefPtr<fml::TaskRunner> raster_task_runner,
fml::RefPtr<SkiaUnrefQueue> unref_queue)
fml::RefPtr<SkiaUnrefQueue> unref_queue,
uint32_t width,
uint32_t height)
: image_info_(image_info),
display_list_(std::move(display_list)),
display_list_or_layer_tree_(std::move(display_list_or_layer_tree)),
snapshot_delegate_(std::move(snapshot_delegate)),
raster_task_runner_(std::move(raster_task_runner)),
unref_queue_(std::move(unref_queue)) {}
unref_queue_(std::move(unref_queue)),
width_(width),
height_(height) {}

void DlDeferredImageGPU::ImageWrapper::OnGrContextCreated() {
FML_DCHECK(raster_task_runner_->RunsTasksOnCurrentThread());
Expand Down Expand Up @@ -142,8 +185,20 @@ void DlDeferredImageGPU::ImageWrapper::SnapshotDisplayList() {
if (!snapshot_delegate) {
return;
}
auto result = snapshot_delegate->MakeGpuImage(wrapper->display_list_,
wrapper->image_info_);
if (std::holds_alternative<std::shared_ptr<LayerTree>>(
wrapper->display_list_or_layer_tree_)) {
auto layer_tree = std::get<std::shared_ptr<LayerTree>>(
wrapper->display_list_or_layer_tree_);
auto display_list = layer_tree->Flatten(
SkRect::MakeWH(wrapper->width_, wrapper->height_),
snapshot_delegate.get()->GetTextureRegistry(),
snapshot_delegate.get()->GetGrContext());
wrapper->display_list_or_layer_tree_.emplace<sk_sp<DisplayList>>(
display_list);
}
auto result = snapshot_delegate->MakeGpuImage(
std::get<sk_sp<DisplayList>>(wrapper->display_list_or_layer_tree_),
wrapper->image_info_);
if (result->texture.isValid()) {
wrapper->texture_ = result->texture;
wrapper->context_ = std::move(result->context);
Expand Down
Loading