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

Commit dfbe75d

Browse files
committed
[Embedder API] Add multi-view present callback
1 parent b2adf74 commit dfbe75d

13 files changed

+292
-63
lines changed

shell/platform/embedder/embedder.cc

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,14 +1290,23 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor,
12901290
SAFE_ACCESS(compositor, collect_backing_store_callback, nullptr);
12911291
auto c_present_callback =
12921292
SAFE_ACCESS(compositor, present_layers_callback, nullptr);
1293+
auto c_present_view_callback =
1294+
SAFE_ACCESS(compositor, present_view_callback, nullptr);
12931295
bool avoid_backing_store_cache =
12941296
SAFE_ACCESS(compositor, avoid_backing_store_cache, false);
12951297

12961298
// Make sure the required callbacks are present
1297-
if (!c_create_callback || !c_collect_callback || !c_present_callback) {
1299+
if (!c_create_callback || !c_collect_callback) {
12981300
FML_LOG(ERROR) << "Required compositor callbacks absent.";
12991301
return {nullptr, true};
13001302
}
1303+
// Either the present view or the present layers callback must be provided.
1304+
if ((!c_present_view_callback && !c_present_callback) ||
1305+
(c_present_view_callback && c_present_callback)) {
1306+
FML_LOG(ERROR) << "Either present_layers_callback or present_view_callback "
1307+
"must be provided but not both.";
1308+
return {nullptr, true};
1309+
}
13011310

13021311
FlutterCompositor captured_compositor = *compositor;
13031312

@@ -1312,15 +1321,33 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor,
13121321
enable_impeller);
13131322
};
13141323

1315-
flutter::EmbedderExternalViewEmbedder::PresentCallback present_callback =
1316-
[c_present_callback,
1317-
user_data = compositor->user_data](const auto& layers) {
1318-
TRACE_EVENT0("flutter", "FlutterCompositorPresentLayers");
1319-
return c_present_callback(
1320-
const_cast<const FlutterLayer**>(layers.data()), layers.size(),
1321-
user_data);
1324+
flutter::EmbedderExternalViewEmbedder::PresentCallback present_callback;
1325+
if (c_present_callback) {
1326+
present_callback = [c_present_callback, user_data = compositor->user_data](
1327+
FlutterViewId view_id, const auto& layers) {
1328+
TRACE_EVENT0("flutter", "FlutterCompositorPresentLayers");
1329+
return c_present_callback(const_cast<const FlutterLayer**>(layers.data()),
1330+
layers.size(), user_data);
1331+
};
1332+
} else {
1333+
FML_DCHECK(c_present_view_callback != nullptr);
1334+
present_callback = [c_present_view_callback,
1335+
user_data = compositor->user_data](
1336+
FlutterViewId view_id, const auto& layers) {
1337+
TRACE_EVENT0("flutter", "FlutterCompositorPresentLayers");
1338+
1339+
FlutterPresentViewInfo info = {
1340+
.struct_size = sizeof(FlutterPresentViewInfo),
1341+
.view_id = view_id,
1342+
.layers = const_cast<const FlutterLayer**>(layers.data()),
1343+
.layers_count = layers.size(),
1344+
.user_data = user_data,
13221345
};
13231346

1347+
return c_present_view_callback(&info);
1348+
};
1349+
}
1350+
13241351
return {std::make_unique<flutter::EmbedderExternalViewEmbedder>(
13251352
avoid_backing_store_cache, create_render_target_callback,
13261353
present_callback),

shell/platform/embedder/embedder.h

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,6 +1738,24 @@ typedef struct {
17381738
FlutterBackingStorePresentInfo* backing_store_present_info;
17391739
} FlutterLayer;
17401740

1741+
typedef struct {
1742+
/// The size of this struct.
1743+
/// Must be sizeof(FlutterPresentViewInfo).
1744+
size_t struct_size;
1745+
1746+
/// The identifier of the target view.
1747+
FlutterViewId view_id;
1748+
1749+
/// The layers that should be composited onto the view.
1750+
const FlutterLayer** layers;
1751+
1752+
/// The count of layers.
1753+
size_t layers_count;
1754+
1755+
/// The |FlutterCompositor.user_data|.
1756+
void* user_data;
1757+
} FlutterPresentViewInfo;
1758+
17411759
typedef bool (*FlutterBackingStoreCreateCallback)(
17421760
const FlutterBackingStoreConfig* config,
17431761
FlutterBackingStore* backing_store_out,
@@ -1751,13 +1769,22 @@ typedef bool (*FlutterLayersPresentCallback)(const FlutterLayer** layers,
17511769
size_t layers_count,
17521770
void* user_data);
17531771

1772+
/// The callback invoked when the embedder should present
1773+
/// to a view.
1774+
///
1775+
/// The |FlutterPresentViewInfo| will be deallocated
1776+
/// once the callback returns.
1777+
typedef bool (*FlutterPresentViewCallback)(
1778+
const FlutterPresentViewInfo* /* present info */);
1779+
17541780
typedef struct {
17551781
/// This size of this struct. Must be sizeof(FlutterCompositor).
17561782
size_t struct_size;
17571783
/// A baton that in not interpreted by the engine in any way. If it passed
17581784
/// back to the embedder in `FlutterCompositor.create_backing_store_callback`,
1759-
/// `FlutterCompositor.collect_backing_store_callback` and
1760-
/// `FlutterCompositor.present_layers_callback`
1785+
/// `FlutterCompositor.collect_backing_store_callback`,
1786+
/// `FlutterCompositor.present_layers_callback`, and
1787+
/// `FlutterCompositor.present_view_callback`.
17611788
void* user_data;
17621789
/// A callback invoked by the engine to obtain a backing store for a specific
17631790
/// `FlutterLayer`.
@@ -1771,10 +1798,23 @@ typedef struct {
17711798
/// embedder may collect any resources associated with the backing store.
17721799
FlutterBackingStoreCollectCallback collect_backing_store_callback;
17731800
/// Callback invoked by the engine to composite the contents of each layer
1774-
/// onto the screen.
1801+
/// onto the implicit view.
1802+
///
1803+
/// DEPRECATED: Use |present_view_callback| to support multiple views.
1804+
///
1805+
/// Only one of `present_layers_callback` and `present_view_callback` may be
1806+
/// provided. Providing both is an error and engine initialization will
1807+
/// terminate.
17751808
FlutterLayersPresentCallback present_layers_callback;
17761809
/// Avoid caching backing stores provided by this compositor.
17771810
bool avoid_backing_store_cache;
1811+
/// Callback invoked by the engine to composite the contents of each layer
1812+
/// onto the specified view.
1813+
///
1814+
/// Only one of `present_layers_callback` and `present_view_callback` may be
1815+
/// provided. Providing both is an error and engine initialization will
1816+
/// terminate.
1817+
FlutterPresentViewCallback present_view_callback;
17781818
} FlutterCompositor;
17791819

17801820
typedef struct {

shell/platform/embedder/embedder_external_view_embedder.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,10 @@ void EmbedderExternalViewEmbedder::SubmitFlutterView(
488488

489489
builder.PushLayers(presented_layers);
490490

491-
presented_layers.InvokePresentCallback(present_callback_);
491+
// TODO: Currently only supports a single view.
492+
// See https://github.com/flutter/flutter/issues/135530.
493+
presented_layers.InvokePresentCallback(kFlutterImplicitViewId,
494+
present_callback_);
492495
}
493496

494497
// See why this is necessary in the comment where this collection in

shell/platform/embedder/embedder_external_view_embedder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder {
3535
const std::shared_ptr<impeller::AiksContext>& aiks_context,
3636
const FlutterBackingStoreConfig& config)>;
3737
using PresentCallback =
38-
std::function<bool(const std::vector<const FlutterLayer*>& layers)>;
38+
std::function<bool(FlutterViewId view_id,
39+
const std::vector<const FlutterLayer*>& layers)>;
3940
using SurfaceTransformationCallback = std::function<SkMatrix(void)>;
4041

4142
//----------------------------------------------------------------------------

shell/platform/embedder/embedder_layers.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,13 +229,14 @@ void EmbedderLayers::PushPlatformViewLayer(
229229
}
230230

231231
void EmbedderLayers::InvokePresentCallback(
232+
FlutterViewId view_id,
232233
const PresentCallback& callback) const {
233234
std::vector<const FlutterLayer*> presented_layers_pointers;
234235
presented_layers_pointers.reserve(presented_layers_.size());
235236
for (const auto& layer : presented_layers_) {
236237
presented_layers_pointers.push_back(&layer);
237238
}
238-
callback(presented_layers_pointers);
239+
callback(view_id, presented_layers_pointers);
239240
}
240241

241242
} // namespace flutter

shell/platform/embedder/embedder_layers.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ class EmbedderLayers {
3131
const EmbeddedViewParams& params);
3232

3333
using PresentCallback =
34-
std::function<bool(const std::vector<const FlutterLayer*>& layers)>;
35-
void InvokePresentCallback(const PresentCallback& callback) const;
34+
std::function<bool(FlutterViewId view_id,
35+
const std::vector<const FlutterLayer*>& layers)>;
36+
void InvokePresentCallback(FlutterViewId view_id,
37+
const PresentCallback& callback) const;
3638

3739
private:
3840
const SkISize frame_size_;

shell/platform/embedder/fixtures/main.dart

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,26 @@ Future<void> key_data_late_echo() async {
814814
signalNativeTest();
815815
}
816816

817+
@pragma('vm:entry-point')
818+
void render_implicit_view() {
819+
PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
820+
final Size size = Size(800.0, 600.0);
821+
final Color red = Color.fromARGB(127, 255, 0, 0);
822+
823+
final SceneBuilder builder = SceneBuilder();
824+
825+
builder.pushOffset(0.0, 0.0);
826+
827+
builder.addPicture(
828+
Offset(0.0, 0.0), CreateColoredBox(red, size));
829+
830+
builder.pop();
831+
832+
PlatformDispatcher.instance.implicitView?.render(builder.build());
833+
};
834+
PlatformDispatcher.instance.scheduleFrame();
835+
}
836+
817837
@pragma('vm:entry-point')
818838
void render_gradient() {
819839
PlatformDispatcher.instance.onBeginFrame = (Duration duration) {

shell/platform/embedder/tests/embedder_config_builder.cc

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

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

7+
#include "flutter/common/constants.h"
78
#include "flutter/runtime/dart_vm.h"
89
#include "flutter/shell/platform/embedder/embedder.h"
910
#include "tests/embedder_test_context.h"
@@ -354,7 +355,8 @@ void EmbedderConfigBuilder::SetPlatformMessageCallback(
354355
context_.SetPlatformMessageCallback(callback);
355356
}
356357

357-
void EmbedderConfigBuilder::SetCompositor(bool avoid_backing_store_cache) {
358+
void EmbedderConfigBuilder::SetCompositor(bool avoid_backing_store_cache,
359+
bool use_present_layers_callback) {
358360
context_.SetupCompositor();
359361
auto& compositor = context_.GetCompositor();
360362
compositor_.struct_size = sizeof(compositor_);
@@ -374,16 +376,25 @@ void EmbedderConfigBuilder::SetCompositor(bool avoid_backing_store_cache) {
374376
return reinterpret_cast<EmbedderTestCompositor*>(user_data)
375377
->CollectBackingStore(backing_store);
376378
};
377-
compositor_.present_layers_callback = [](const FlutterLayer** layers, //
378-
size_t layers_count, //
379-
void* user_data //
380-
) {
381-
return reinterpret_cast<EmbedderTestCompositor*>(user_data)->Present(
382-
layers, //
383-
layers_count //
384-
385-
);
386-
};
379+
if (use_present_layers_callback) {
380+
compositor_.present_view_callback = [](const FlutterPresentViewInfo* info) {
381+
auto compositor =
382+
reinterpret_cast<EmbedderTestCompositor*>(info->user_data);
383+
384+
return compositor->Present(info->view_id, info->layers,
385+
info->layers_count);
386+
};
387+
} else {
388+
compositor_.present_layers_callback = [](const FlutterLayer** layers,
389+
size_t layers_count,
390+
void* user_data) {
391+
auto compositor = reinterpret_cast<EmbedderTestCompositor*>(user_data);
392+
393+
// The present layers callback is incompatible with multiple views;
394+
// it can only be used to render the implicit view.
395+
return compositor->Present(kFlutterImplicitViewId, layers, layers_count);
396+
};
397+
}
387398
compositor_.avoid_backing_store_cache = avoid_backing_store_cache;
388399
project_args_.compositor = &compositor_;
389400
}

shell/platform/embedder/tests/embedder_config_builder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ class EmbedderConfigBuilder {
105105
void SetPlatformMessageCallback(
106106
const std::function<void(const FlutterPlatformMessage*)>& callback);
107107

108-
void SetCompositor(bool avoid_backing_store_cache = false);
108+
void SetCompositor(bool avoid_backing_store_cache = false,
109+
bool use_present_layers_callback = false);
109110

110111
FlutterCompositor& GetCompositor();
111112

0 commit comments

Comments
 (0)