Skip to content

Commit 599dbd7

Browse files
authored
[Embedder API] Add multi-view present callback (flutter#51267)
Adds `FlutterCompositor.present_view_callback` to the embedder API. This new present callback adds a `view_id` member to allow embedders know which view is being presented. The embedder API does not allow embedders to create multiple views yet. This will be added in a future pull request. Design doc: https://flutter.dev/go/multi-view-embedder-apis Pull request that migrates the Windows embedder to this new embedder API: flutter/engine#51293 Part of flutter#144806 Part of flutter#142845 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 01015e9 commit 599dbd7

14 files changed

Lines changed: 290 additions & 65 deletions

shell/platform/embedder/embedder.cc

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,14 +1288,23 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor,
12881288
SAFE_ACCESS(compositor, collect_backing_store_callback, nullptr);
12891289
auto c_present_callback =
12901290
SAFE_ACCESS(compositor, present_layers_callback, nullptr);
1291+
auto c_present_view_callback =
1292+
SAFE_ACCESS(compositor, present_view_callback, nullptr);
12911293
bool avoid_backing_store_cache =
12921294
SAFE_ACCESS(compositor, avoid_backing_store_cache, false);
12931295

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

13001309
FlutterCompositor captured_compositor = *compositor;
13011310

@@ -1310,15 +1319,33 @@ InferExternalViewEmbedderFromArgs(const FlutterCompositor* compositor,
13101319
enable_impeller);
13111320
};
13121321

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

1345+
return c_present_view_callback(&info);
1346+
};
1347+
}
1348+
13221349
return {std::make_unique<flutter::EmbedderExternalViewEmbedder>(
13231350
avoid_backing_store_cache, create_render_target_callback,
13241351
present_callback),

shell/platform/embedder/embedder.h

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1744,6 +1744,24 @@ typedef struct {
17441744
uint64_t presentation_time;
17451745
} FlutterLayer;
17461746

1747+
typedef struct {
1748+
/// The size of this struct.
1749+
/// Must be sizeof(FlutterPresentViewInfo).
1750+
size_t struct_size;
1751+
1752+
/// The identifier of the target view.
1753+
FlutterViewId view_id;
1754+
1755+
/// The layers that should be composited onto the view.
1756+
const FlutterLayer** layers;
1757+
1758+
/// The count of layers.
1759+
size_t layers_count;
1760+
1761+
/// The |FlutterCompositor.user_data|.
1762+
void* user_data;
1763+
} FlutterPresentViewInfo;
1764+
17471765
typedef bool (*FlutterBackingStoreCreateCallback)(
17481766
const FlutterBackingStoreConfig* config,
17491767
FlutterBackingStore* backing_store_out,
@@ -1757,13 +1775,20 @@ typedef bool (*FlutterLayersPresentCallback)(const FlutterLayer** layers,
17571775
size_t layers_count,
17581776
void* user_data);
17591777

1778+
/// The callback invoked when the embedder should present to a view.
1779+
///
1780+
/// The |FlutterPresentViewInfo| will be deallocated once the callback returns.
1781+
typedef bool (*FlutterPresentViewCallback)(
1782+
const FlutterPresentViewInfo* /* present info */);
1783+
17601784
typedef struct {
17611785
/// This size of this struct. Must be sizeof(FlutterCompositor).
17621786
size_t struct_size;
17631787
/// A baton that in not interpreted by the engine in any way. If it passed
17641788
/// back to the embedder in `FlutterCompositor.create_backing_store_callback`,
1765-
/// `FlutterCompositor.collect_backing_store_callback` and
1766-
/// `FlutterCompositor.present_layers_callback`
1789+
/// `FlutterCompositor.collect_backing_store_callback`,
1790+
/// `FlutterCompositor.present_layers_callback`, and
1791+
/// `FlutterCompositor.present_view_callback`.
17671792
void* user_data;
17681793
/// A callback invoked by the engine to obtain a backing store for a specific
17691794
/// `FlutterLayer`.
@@ -1777,10 +1802,23 @@ typedef struct {
17771802
/// embedder may collect any resources associated with the backing store.
17781803
FlutterBackingStoreCollectCallback collect_backing_store_callback;
17791804
/// Callback invoked by the engine to composite the contents of each layer
1780-
/// onto the screen.
1805+
/// onto the implicit view.
1806+
///
1807+
/// DEPRECATED: Use |present_view_callback| to support multiple views.
1808+
///
1809+
/// Only one of `present_layers_callback` and `present_view_callback` may be
1810+
/// provided. Providing both is an error and engine initialization will
1811+
/// terminate.
17811812
FlutterLayersPresentCallback present_layers_callback;
17821813
/// Avoid caching backing stores provided by this compositor.
17831814
bool avoid_backing_store_cache;
1815+
/// Callback invoked by the engine to composite the contents of each layer
1816+
/// onto the specified view.
1817+
///
1818+
/// Only one of `present_layers_callback` and `present_view_callback` may be
1819+
/// provided. Providing both is an error and engine initialization will
1820+
/// terminate.
1821+
FlutterPresentViewCallback present_view_callback;
17841822
} FlutterCompositor;
17851823

17861824
typedef struct {

shell/platform/embedder/embedder_external_view_embedder.cc

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

495495
builder.PushLayers(presented_layers);
496496

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

500503
// 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
@@ -234,13 +234,14 @@ void EmbedderLayers::PushPlatformViewLayer(
234234
}
235235

236236
void EmbedderLayers::InvokePresentCallback(
237+
FlutterViewId view_id,
237238
const PresentCallback& callback) const {
238239
std::vector<const FlutterLayer*> presented_layers_pointers;
239240
presented_layers_pointers.reserve(presented_layers_.size());
240241
for (const auto& layer : presented_layers_) {
241242
presented_layers_pointers.push_back(&layer);
242243
}
243-
callback(presented_layers_pointers);
244+
callback(view_id, presented_layers_pointers);
244245
}
245246

246247
} // namespace flutter

shell/platform/embedder/embedder_layers.h

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

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

3840
private:
3941
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)