[Embedder API] Add multi-view present callback (flutter/engine#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: https://github.com/flutter/engine/pull/51293

Part of https://github.com/flutter/flutter/issues/144806
Part of https://github.com/flutter/flutter/issues/142845

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
Loïc Sharma 2024-03-13 17:22:22 -07:00 committed by GitHub
parent 7a710c28dd
commit fbfbc4393f
14 changed files with 289 additions and 64 deletions

View File

@ -1288,14 +1288,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;
@ -1310,15 +1319,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),

View File

@ -1744,6 +1744,24 @@ typedef struct {
uint64_t presentation_time;
} 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,
@ -1757,13 +1775,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`.
@ -1777,10 +1802,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 {

View File

@ -494,7 +494,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

View File

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

View File

@ -234,13 +234,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

View File

@ -32,8 +32,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_;

View File

@ -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) {

View File

@ -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"
@ -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_);
@ -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_;
}

View File

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

View File

@ -73,6 +73,27 @@ TEST_F(EmbedderTest,
builder.GetCompositor().create_backing_store_callback = nullptr;
builder.GetCompositor().collect_backing_store_callback = nullptr;
builder.GetCompositor().present_layers_callback = nullptr;
builder.GetCompositor().present_view_callback = nullptr;
auto engine = builder.LaunchEngine();
ASSERT_FALSE(engine.is_valid());
}
//------------------------------------------------------------------------------
/// Either present_layers_callback or present_view_callback must be provided,
/// but not both, otherwise the engine must fail to launch instead of failing to
/// render a frame at a later point in time.
///
TEST_F(EmbedderTest, LaunchFailsWhenMultiplePresentCallbacks) {
auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
EmbedderConfigBuilder builder(context);
builder.SetOpenGLRendererConfig(SkISize::Make(1, 1));
builder.SetCompositor();
builder.GetCompositor().present_layers_callback =
[](const FlutterLayer** layers, size_t layers_count, void* user_data) {
return true;
};
builder.GetCompositor().present_view_callback =
[](const FlutterPresentViewInfo* info) { return true; };
auto engine = builder.LaunchEngine();
ASSERT_FALSE(engine.is_valid());
}
@ -94,7 +115,8 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLFramebuffer) {
fml::CountDownLatch latch(3);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
{
@ -215,7 +237,8 @@ TEST_F(EmbedderTest, RasterCacheDisabledWithPlatformViews) {
fml::CountDownLatch verify(1);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
{
@ -347,7 +370,8 @@ TEST_F(EmbedderTest, RasterCacheEnabled) {
fml::CountDownLatch verify(1);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 1u);
{
@ -430,7 +454,8 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToOpenGLTexture) {
fml::CountDownLatch latch(3);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
{
@ -550,7 +575,8 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderToSoftwareBuffer) {
fml::CountDownLatch latch(3);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
{
@ -673,7 +699,8 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownScene) {
auto scene_image = context.GetNextSceneImage();
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 5u);
// Layer Root
@ -898,7 +925,8 @@ TEST_F(EmbedderTest, CustomCompositorMustWorkWithCustomTaskRunner) {
fml::CountDownLatch latch(3);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
{
@ -1054,7 +1082,8 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithRootLayerOnly) {
auto scene_image = context.GetNextSceneImage();
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 1u);
// Layer Root
@ -1135,7 +1164,8 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderWithPlatformLayerOnBottom) {
auto scene_image = context.GetNextSceneImage();
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
// Layer Root
@ -1269,7 +1299,8 @@ TEST_F(EmbedderTest,
auto scene_image = context.GetNextSceneImage();
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 5u);
// Layer Root
@ -1659,7 +1690,8 @@ TEST_P(EmbedderTestMultiBackend,
builder.SetRenderTargetType(GetRenderTargetFromBackend(backend, true));
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
// Layer Root
@ -1799,7 +1831,8 @@ TEST_F(EmbedderTest, CanRenderGradientWithCompositorOnNonRootLayerWithXform) {
EmbedderTestBackingStoreProducer::RenderTargetType::kOpenGLFramebuffer);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
// Layer Root
@ -1954,7 +1987,8 @@ TEST_F(EmbedderTest, VerifyB141980393) {
fml::AutoResetWaitableEvent latch;
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 1u);
// Layer Root
@ -2171,7 +2205,8 @@ TEST_P(EmbedderTestMultiBackend,
auto rendered_scene = context.GetNextSceneImage();
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
// Layer 0 (Root)
@ -2293,7 +2328,8 @@ TEST_F(
fml::CountDownLatch latch(1);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
// Layer 0 (Root)
@ -2491,7 +2527,8 @@ TEST_P(EmbedderTestMultiBackend, PlatformViewMutatorsAreValid) {
fml::CountDownLatch latch(1);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
// Layer 0 (Root)
@ -2600,7 +2637,8 @@ TEST_F(EmbedderTest, PlatformViewMutatorsAreValidWithPixelRatio) {
fml::CountDownLatch latch(1);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
// Layer 0 (Root)
@ -2716,7 +2754,8 @@ TEST_F(EmbedderTest,
fml::CountDownLatch latch(1);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
// Layer 0 (Root)
@ -2921,7 +2960,8 @@ TEST_F(EmbedderTest, ClipsAreCorrectlyCalculated) {
fml::AutoResetWaitableEvent latch;
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
{
@ -3000,7 +3040,8 @@ TEST_F(EmbedderTest, ComplexClipsAreCorrectlyCalculated) {
fml::AutoResetWaitableEvent latch;
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
{
@ -3279,7 +3320,8 @@ TEST_F(EmbedderTest, CompositorCanPostZeroLayersForPresentation) {
fml::AutoResetWaitableEvent latch;
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 0u);
latch.Signal();
});
@ -3312,7 +3354,8 @@ TEST_F(EmbedderTest, CompositorCanPostOnlyPlatformViews) {
fml::AutoResetWaitableEvent latch;
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
// Layer 0
@ -3380,7 +3423,8 @@ TEST_F(EmbedderTest, CompositorRenderTargetsAreRecycled) {
}));
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 20u);
latch.CountDown();
});
@ -3427,7 +3471,8 @@ TEST_F(EmbedderTest, CompositorRenderTargetsAreInStableOrder) {
size_t frame_count = 0;
std::vector<void*> first_frame_backing_store_user_data;
context.GetCompositor().SetPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 20u);
if (first_frame_backing_store_user_data.empty()) {
@ -4236,7 +4281,8 @@ TEST_F(EmbedderTest, CompositorRenderTargetsNotRecycledWhenAvoidsCacheSet) {
}));
context.GetCompositor().SetPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 20u);
latch.CountDown();
},

View File

@ -138,7 +138,7 @@ TEST_F(EmbedderTest, MetalCompositorMustBeAbleToRenderPlatformViews) {
fml::CountDownLatch latch(3);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers, size_t layers_count) {
ASSERT_EQ(layers_count, 3u);
{
@ -326,7 +326,7 @@ TEST_F(EmbedderTest, CompositorMustBeAbleToRenderKnownSceneMetal) {
auto scene_image = context.GetNextSceneImage();
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers, size_t layers_count) {
ASSERT_EQ(layers_count, 5u);
// Layer Root

View File

@ -60,7 +60,8 @@ sk_sp<SkImage> EmbedderTestCompositor::GetLastComposition() {
return last_composition_;
}
bool EmbedderTestCompositor::Present(const FlutterLayer** layers,
bool EmbedderTestCompositor::Present(FlutterViewId view_id,
const FlutterLayer** layers,
size_t layers_count) {
if (!UpdateOffscrenComposition(layers, layers_count)) {
FML_LOG(ERROR)
@ -75,7 +76,7 @@ bool EmbedderTestCompositor::Present(const FlutterLayer** layers,
if (present_callback_is_one_shot_) {
present_callback_ = nullptr;
}
callback(layers, layers_count);
callback(view_id, layers, layers_count);
}
InvokeAllCallbacks(on_present_callbacks_);

View File

@ -21,8 +21,9 @@ class EmbedderTestCompositor {
using PlatformViewRendererCallback =
std::function<sk_sp<SkImage>(const FlutterLayer& layer,
GrDirectContext* context)>;
using PresentCallback =
std::function<void(const FlutterLayer** layers, size_t layers_count)>;
using PresentCallback = std::function<void(FlutterViewId view_id,
const FlutterLayer** layers,
size_t layers_count)>;
EmbedderTestCompositor(SkISize surface_size, sk_sp<GrDirectContext> context);
@ -36,7 +37,9 @@ class EmbedderTestCompositor {
bool CollectBackingStore(const FlutterBackingStore* backing_store);
bool Present(const FlutterLayer** layers, size_t layers_count);
bool Present(FlutterViewId view_id,
const FlutterLayer** layers,
size_t layers_count);
void SetPlatformViewRendererCallback(
const PlatformViewRendererCallback& callback);

View File

@ -10,6 +10,7 @@
#include "embedder.h"
#include "embedder_engine.h"
#include "flutter/common/constants.h"
#include "flutter/flow/raster_cache.h"
#include "flutter/fml/file.h"
#include "flutter/fml/make_copyable.h"
@ -640,6 +641,71 @@ TEST_F(EmbedderTest, VMAndIsolateSnapshotSizesAreRedundantInAOTMode) {
ASSERT_TRUE(engine.is_valid());
}
TEST_F(EmbedderTest, CanRenderImplicitView) {
auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
EmbedderConfigBuilder builder(context);
builder.SetSoftwareRendererConfig(SkISize::Make(800, 600));
builder.SetCompositor();
builder.SetDartEntrypoint("render_implicit_view");
builder.SetRenderTargetType(
EmbedderTestBackingStoreProducer::RenderTargetType::kSoftwareBuffer);
fml::AutoResetWaitableEvent latch;
context.GetCompositor().SetNextPresentCallback(
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(view_id, kFlutterImplicitViewId);
latch.Signal();
});
auto engine = builder.LaunchEngine();
FlutterWindowMetricsEvent event = {};
event.struct_size = sizeof(event);
event.width = 300;
event.height = 200;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
latch.Wait();
}
TEST_F(EmbedderTest, CanRenderImplicitViewUsingPresentLayersCallback) {
auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
EmbedderConfigBuilder builder(context);
builder.SetSoftwareRendererConfig(SkISize::Make(800, 600));
builder.SetCompositor(/* avoid_backing_store_cache = */ false,
/* use_present_layers_callback = */ true);
builder.SetDartEntrypoint("render_implicit_view");
builder.SetRenderTargetType(
EmbedderTestBackingStoreProducer::RenderTargetType::kSoftwareBuffer);
fml::AutoResetWaitableEvent latch;
context.GetCompositor().SetNextPresentCallback(
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(view_id, kFlutterImplicitViewId);
latch.Signal();
});
auto engine = builder.LaunchEngine();
FlutterWindowMetricsEvent event = {};
event.struct_size = sizeof(event);
event.width = 300;
event.height = 200;
event.pixel_ratio = 1.0;
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
kSuccess);
ASSERT_TRUE(engine.is_valid());
latch.Wait();
}
//------------------------------------------------------------------------------
/// Test the layer structure and pixels rendered when using a custom software
/// compositor.
@ -668,7 +734,8 @@ TEST_F(EmbedderTest,
auto scene_image = context.GetNextSceneImage();
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 5u);
// Layer Root
@ -886,7 +953,8 @@ TEST_F(EmbedderTest, NoLayerCreatedForTransparentOverlayOnTopOfPlatformLayer) {
auto scene_image = context.GetNextSceneImage();
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
// Layer Root
@ -1022,7 +1090,8 @@ TEST_F(EmbedderTest, NoLayerCreatedForNoOverlayOnTopOfPlatformLayer) {
auto scene_image = context.GetNextSceneImage();
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
// Layer Root
@ -1303,7 +1372,8 @@ TEST_F(EmbedderTest, VerifyB143464703WithSoftwareBackend) {
fml::CountDownLatch latch(1);
context.GetCompositor().SetNextPresentCallback(
[&](const FlutterLayer** layers, size_t layers_count) {
[&](FlutterViewId view_id, const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers_count, 2u);
// Layer 0 (Root)
@ -1935,7 +2005,8 @@ static void expectSoftwareRenderingOutputMatches(
ASSERT_TRUE(engine.is_valid());
context.GetCompositor().SetNextPresentCallback(
[&matches, &bytes, &latch](const FlutterLayer** layers,
[&matches, &bytes, &latch](FlutterViewId view_id,
const FlutterLayer** layers,
size_t layers_count) {
ASSERT_EQ(layers[0]->type, kFlutterLayerContentTypeBackingStore);
ASSERT_EQ(layers[0]->backing_store->type,