Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

[Embedder API] Add multi-view present callback #51267

Merged
merged 2 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 35 additions & 8 deletions shell/platform/embedder/embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1290,14 +1290,23 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor,
SAFE_ACCESS(compositor, collect_backing_store_callback, nullptr);
auto c_present_callback =
SAFE_ACCESS(compositor, present_layers_callback, nullptr);
auto c_present_view_callback =
SAFE_ACCESS(compositor, present_view_callback, nullptr);
bool avoid_backing_store_cache =
SAFE_ACCESS(compositor, avoid_backing_store_cache, false);

// Make sure the required callbacks are present
if (!c_create_callback || !c_collect_callback || !c_present_callback) {
if (!c_create_callback || !c_collect_callback) {
FML_LOG(ERROR) << "Required compositor callbacks absent.";
return {nullptr, true};
}
// Either the present view or the present layers callback must be provided.
if ((!c_present_view_callback && !c_present_callback) ||
(c_present_view_callback && c_present_callback)) {
FML_LOG(ERROR) << "Either present_layers_callback or present_view_callback "
"must be provided but not both.";
return {nullptr, true};
}

FlutterCompositor captured_compositor = *compositor;

Expand All @@ -1312,15 +1321,33 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor,
enable_impeller);
};

flutter::EmbedderExternalViewEmbedder::PresentCallback present_callback =
[c_present_callback,
user_data = compositor->user_data](const auto& layers) {
TRACE_EVENT0("flutter", "FlutterCompositorPresentLayers");
return c_present_callback(
const_cast<const FlutterLayer**>(layers.data()), layers.size(),
user_data);
flutter::EmbedderExternalViewEmbedder::PresentCallback present_callback;
if (c_present_callback) {
present_callback = [c_present_callback, user_data = compositor->user_data](
FlutterViewId view_id, const auto& layers) {
TRACE_EVENT0("flutter", "FlutterCompositorPresentLayers");
return c_present_callback(const_cast<const FlutterLayer**>(layers.data()),
layers.size(), user_data);
};
} else {
FML_DCHECK(c_present_view_callback != nullptr);
present_callback = [c_present_view_callback,
user_data = compositor->user_data](
FlutterViewId view_id, const auto& layers) {
TRACE_EVENT0("flutter", "FlutterCompositorPresentLayers");

FlutterPresentViewInfo info = {
.struct_size = sizeof(FlutterPresentViewInfo),
.view_id = view_id,
.layers = const_cast<const FlutterLayer**>(layers.data()),
.layers_count = layers.size(),
.user_data = user_data,
};

return c_present_view_callback(&info);
};
}

return {std::make_unique<flutter::EmbedderExternalViewEmbedder>(
avoid_backing_store_cache, create_render_target_callback,
present_callback),
Expand Down
44 changes: 41 additions & 3 deletions shell/platform/embedder/embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -1738,6 +1738,24 @@ typedef struct {
FlutterBackingStorePresentInfo* backing_store_present_info;
} FlutterLayer;

typedef struct {
/// The size of this struct.
/// Must be sizeof(FlutterPresentViewInfo).
size_t struct_size;

/// The identifier of the target view.
FlutterViewId view_id;

/// The layers that should be composited onto the view.
const FlutterLayer** layers;

/// The count of layers.
size_t layers_count;

/// The |FlutterCompositor.user_data|.
void* user_data;
} FlutterPresentViewInfo;

typedef bool (*FlutterBackingStoreCreateCallback)(
const FlutterBackingStoreConfig* config,
FlutterBackingStore* backing_store_out,
Expand All @@ -1751,13 +1769,20 @@ typedef bool (*FlutterLayersPresentCallback)(const FlutterLayer** layers,
size_t layers_count,
void* user_data);

/// The callback invoked when the embedder should present to a view.
///
/// The |FlutterPresentViewInfo| will be deallocated once the callback returns.
typedef bool (*FlutterPresentViewCallback)(
const FlutterPresentViewInfo* /* present info */);

typedef struct {
/// This size of this struct. Must be sizeof(FlutterCompositor).
size_t struct_size;
/// A baton that in not interpreted by the engine in any way. If it passed
/// back to the embedder in `FlutterCompositor.create_backing_store_callback`,
/// `FlutterCompositor.collect_backing_store_callback` and
/// `FlutterCompositor.present_layers_callback`
/// `FlutterCompositor.collect_backing_store_callback`,
/// `FlutterCompositor.present_layers_callback`, and
/// `FlutterCompositor.present_view_callback`.
void* user_data;
/// A callback invoked by the engine to obtain a backing store for a specific
/// `FlutterLayer`.
Expand All @@ -1771,10 +1796,23 @@ typedef struct {
/// embedder may collect any resources associated with the backing store.
FlutterBackingStoreCollectCallback collect_backing_store_callback;
/// Callback invoked by the engine to composite the contents of each layer
/// onto the screen.
/// onto the implicit view.
///
/// DEPRECATED: Use |present_view_callback| to support multiple views.
///
/// Only one of `present_layers_callback` and `present_view_callback` may be
/// provided. Providing both is an error and engine initialization will
/// terminate.
FlutterLayersPresentCallback present_layers_callback;
/// Avoid caching backing stores provided by this compositor.
bool avoid_backing_store_cache;
/// Callback invoked by the engine to composite the contents of each layer
/// onto the specified view.
///
/// Only one of `present_layers_callback` and `present_view_callback` may be
/// provided. Providing both is an error and engine initialization will
/// terminate.
FlutterPresentViewCallback present_view_callback;
} FlutterCompositor;

typedef struct {
Expand Down
5 changes: 4 additions & 1 deletion shell/platform/embedder/embedder_external_view_embedder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,10 @@ void EmbedderExternalViewEmbedder::SubmitFlutterView(

builder.PushLayers(presented_layers);

presented_layers.InvokePresentCallback(present_callback_);
// TODO(loic-sharma): Currently only supports a single view.
// See https://github.com/flutter/flutter/issues/135530.
presented_layers.InvokePresentCallback(kFlutterImplicitViewId,
present_callback_);
}

// See why this is necessary in the comment where this collection in
Expand Down
3 changes: 2 additions & 1 deletion shell/platform/embedder/embedder_external_view_embedder.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder {
const std::shared_ptr<impeller::AiksContext>& aiks_context,
const FlutterBackingStoreConfig& config)>;
using PresentCallback =
std::function<bool(const std::vector<const FlutterLayer*>& layers)>;
std::function<bool(FlutterViewId view_id,
const std::vector<const FlutterLayer*>& layers)>;
using SurfaceTransformationCallback = std::function<SkMatrix(void)>;

//----------------------------------------------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion shell/platform/embedder/embedder_layers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -229,13 +229,14 @@ void EmbedderLayers::PushPlatformViewLayer(
}

void EmbedderLayers::InvokePresentCallback(
FlutterViewId view_id,
const PresentCallback& callback) const {
std::vector<const FlutterLayer*> presented_layers_pointers;
presented_layers_pointers.reserve(presented_layers_.size());
for (const auto& layer : presented_layers_) {
presented_layers_pointers.push_back(&layer);
}
callback(presented_layers_pointers);
callback(view_id, presented_layers_pointers);
}

} // namespace flutter
6 changes: 4 additions & 2 deletions shell/platform/embedder/embedder_layers.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ class EmbedderLayers {
const EmbeddedViewParams& params);

using PresentCallback =
std::function<bool(const std::vector<const FlutterLayer*>& layers)>;
void InvokePresentCallback(const PresentCallback& callback) const;
std::function<bool(FlutterViewId view_id,
const std::vector<const FlutterLayer*>& layers)>;
void InvokePresentCallback(FlutterViewId view_id,
const PresentCallback& callback) const;

private:
const SkISize frame_size_;
Expand Down
20 changes: 20 additions & 0 deletions shell/platform/embedder/fixtures/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,26 @@ Future<void> key_data_late_echo() async {
signalNativeTest();
}

@pragma('vm:entry-point')
void render_implicit_view() {
PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
final Size size = Size(800.0, 600.0);
final Color red = Color.fromARGB(127, 255, 0, 0);

final SceneBuilder builder = SceneBuilder();

builder.pushOffset(0.0, 0.0);

builder.addPicture(
Offset(0.0, 0.0), CreateColoredBox(red, size));

builder.pop();

PlatformDispatcher.instance.implicitView?.render(builder.build());
};
PlatformDispatcher.instance.scheduleFrame();
}

@pragma('vm:entry-point')
void render_gradient() {
PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
Expand Down
33 changes: 22 additions & 11 deletions shell/platform/embedder/tests/embedder_config_builder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "flutter/shell/platform/embedder/tests/embedder_config_builder.h"

#include "flutter/common/constants.h"
#include "flutter/runtime/dart_vm.h"
#include "flutter/shell/platform/embedder/embedder.h"
#include "tests/embedder_test_context.h"
Expand Down Expand Up @@ -354,7 +355,8 @@ void EmbedderConfigBuilder::SetPlatformMessageCallback(
context_.SetPlatformMessageCallback(callback);
}

void EmbedderConfigBuilder::SetCompositor(bool avoid_backing_store_cache) {
void EmbedderConfigBuilder::SetCompositor(bool avoid_backing_store_cache,
bool use_present_layers_callback) {
context_.SetupCompositor();
auto& compositor = context_.GetCompositor();
compositor_.struct_size = sizeof(compositor_);
Expand All @@ -374,16 +376,25 @@ void EmbedderConfigBuilder::SetCompositor(bool avoid_backing_store_cache) {
return reinterpret_cast<EmbedderTestCompositor*>(user_data)
->CollectBackingStore(backing_store);
};
compositor_.present_layers_callback = [](const FlutterLayer** layers, //
size_t layers_count, //
void* user_data //
) {
return reinterpret_cast<EmbedderTestCompositor*>(user_data)->Present(
layers, //
layers_count //

);
};
if (use_present_layers_callback) {
compositor_.present_view_callback = [](const FlutterPresentViewInfo* info) {
auto compositor =
reinterpret_cast<EmbedderTestCompositor*>(info->user_data);

return compositor->Present(info->view_id, info->layers,
info->layers_count);
};
} else {
compositor_.present_layers_callback = [](const FlutterLayer** layers,
size_t layers_count,
void* user_data) {
auto compositor = reinterpret_cast<EmbedderTestCompositor*>(user_data);

// The present layers callback is incompatible with multiple views;
// it can only be used to render the implicit view.
return compositor->Present(kFlutterImplicitViewId, layers, layers_count);
};
}
compositor_.avoid_backing_store_cache = avoid_backing_store_cache;
project_args_.compositor = &compositor_;
}
Expand Down
3 changes: 2 additions & 1 deletion shell/platform/embedder/tests/embedder_config_builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ class EmbedderConfigBuilder {
void SetPlatformMessageCallback(
const std::function<void(const FlutterPlatformMessage*)>& callback);

void SetCompositor(bool avoid_backing_store_cache = false);
void SetCompositor(bool avoid_backing_store_cache = false,
bool use_present_layers_callback = false);

FlutterCompositor& GetCompositor();

Expand Down
Loading