From 0bff9574d462ca376365bf73515a0ebeaf4e66dc Mon Sep 17 00:00:00 2001 From: Loic Sharma Date: Tue, 5 Mar 2024 15:06:28 -0800 Subject: [PATCH 1/2] [Embedder API] Add multi-view present callback --- shell/platform/embedder/embedder.cc | 43 +++++++-- shell/platform/embedder/embedder.h | 46 ++++++++- .../embedder_external_view_embedder.cc | 5 +- .../embedder_external_view_embedder.h | 3 +- shell/platform/embedder/embedder_layers.cc | 3 +- shell/platform/embedder/embedder_layers.h | 6 +- shell/platform/embedder/fixtures/main.dart | 20 ++++ .../embedder/tests/embedder_config_builder.cc | 33 ++++--- .../embedder/tests/embedder_config_builder.h | 3 +- .../embedder/tests/embedder_gl_unittests.cc | 96 ++++++++++++++----- .../tests/embedder_metal_unittests.mm | 4 +- .../tests/embedder_test_compositor.cc | 5 +- .../embedder/tests/embedder_test_compositor.h | 9 +- .../embedder/tests/embedder_unittests.cc | 81 +++++++++++++++- 14 files changed, 292 insertions(+), 65 deletions(-) diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 4633fcad552d2..4603b20104cd3 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -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; @@ -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(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(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(layers.data()), + .layers_count = layers.size(), + .user_data = user_data, }; + return c_present_view_callback(&info); + }; + } + return {std::make_unique( avoid_backing_store_cache, create_render_target_callback, present_callback), diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index d8adf5e77834c..d2f26ac3eb505 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -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, @@ -1751,13 +1769,22 @@ 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`. @@ -1771,10 +1798,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 { diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index aaf78f6e75c27..87656a37a598a 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -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 diff --git a/shell/platform/embedder/embedder_external_view_embedder.h b/shell/platform/embedder/embedder_external_view_embedder.h index ae7cd4fecd318..d850fa85e8443 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.h +++ b/shell/platform/embedder/embedder_external_view_embedder.h @@ -35,7 +35,8 @@ class EmbedderExternalViewEmbedder final : public ExternalViewEmbedder { const std::shared_ptr& aiks_context, const FlutterBackingStoreConfig& config)>; using PresentCallback = - std::function& layers)>; + std::function& layers)>; using SurfaceTransformationCallback = std::function; //---------------------------------------------------------------------------- diff --git a/shell/platform/embedder/embedder_layers.cc b/shell/platform/embedder/embedder_layers.cc index 2b1035908550c..d07b614bf95bf 100644 --- a/shell/platform/embedder/embedder_layers.cc +++ b/shell/platform/embedder/embedder_layers.cc @@ -229,13 +229,14 @@ void EmbedderLayers::PushPlatformViewLayer( } void EmbedderLayers::InvokePresentCallback( + FlutterViewId view_id, const PresentCallback& callback) const { std::vector 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 diff --git a/shell/platform/embedder/embedder_layers.h b/shell/platform/embedder/embedder_layers.h index e821cb09a7e85..98bcffc7886a8 100644 --- a/shell/platform/embedder/embedder_layers.h +++ b/shell/platform/embedder/embedder_layers.h @@ -31,8 +31,10 @@ class EmbedderLayers { const EmbeddedViewParams& params); using PresentCallback = - std::function& layers)>; - void InvokePresentCallback(const PresentCallback& callback) const; + std::function& layers)>; + void InvokePresentCallback(FlutterViewId view_id, + const PresentCallback& callback) const; private: const SkISize frame_size_; diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index dffa430fbb520..d26bface876d1 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -814,6 +814,26 @@ Future 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) { diff --git a/shell/platform/embedder/tests/embedder_config_builder.cc b/shell/platform/embedder/tests/embedder_config_builder.cc index 03844fffd3971..72e10f0ebbdc0 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.cc +++ b/shell/platform/embedder/tests/embedder_config_builder.cc @@ -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(user_data) ->CollectBackingStore(backing_store); }; - compositor_.present_layers_callback = [](const FlutterLayer** layers, // - size_t layers_count, // - void* user_data // - ) { - return reinterpret_cast(user_data)->Present( - layers, // - layers_count // - - ); - }; + if (use_present_layers_callback) { + compositor_.present_view_callback = [](const FlutterPresentViewInfo* info) { + auto compositor = + reinterpret_cast(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(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_; } diff --git a/shell/platform/embedder/tests/embedder_config_builder.h b/shell/platform/embedder/tests/embedder_config_builder.h index a79cedf812b2f..82498ac06b17b 100644 --- a/shell/platform/embedder/tests/embedder_config_builder.h +++ b/shell/platform/embedder/tests/embedder_config_builder.h @@ -105,7 +105,8 @@ class EmbedderConfigBuilder { void SetPlatformMessageCallback( const std::function& 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(); diff --git a/shell/platform/embedder/tests/embedder_gl_unittests.cc b/shell/platform/embedder/tests/embedder_gl_unittests.cc index f62985df3592d..0720e54a458de 100644 --- a/shell/platform/embedder/tests/embedder_gl_unittests.cc +++ b/shell/platform/embedder/tests/embedder_gl_unittests.cc @@ -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 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(); }, diff --git a/shell/platform/embedder/tests/embedder_metal_unittests.mm b/shell/platform/embedder/tests/embedder_metal_unittests.mm index c23a6553a5360..13a9d49f552f0 100644 --- a/shell/platform/embedder/tests/embedder_metal_unittests.mm +++ b/shell/platform/embedder/tests/embedder_metal_unittests.mm @@ -138,7 +138,7 @@ GrBackendTexture backend_texture(texture_size.width(), texture_size.height(), 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 @@ GrBackendTexture backend_texture(texture_size.width(), texture_size.height(), 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 diff --git a/shell/platform/embedder/tests/embedder_test_compositor.cc b/shell/platform/embedder/tests/embedder_test_compositor.cc index 4bbcf2ac83cac..66f6d55af0c7f 100644 --- a/shell/platform/embedder/tests/embedder_test_compositor.cc +++ b/shell/platform/embedder/tests/embedder_test_compositor.cc @@ -60,7 +60,8 @@ sk_sp 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_); diff --git a/shell/platform/embedder/tests/embedder_test_compositor.h b/shell/platform/embedder/tests/embedder_test_compositor.h index e9ad712034014..705579d76e08b 100644 --- a/shell/platform/embedder/tests/embedder_test_compositor.h +++ b/shell/platform/embedder/tests/embedder_test_compositor.h @@ -21,8 +21,9 @@ class EmbedderTestCompositor { using PlatformViewRendererCallback = std::function(const FlutterLayer& layer, GrDirectContext* context)>; - using PresentCallback = - std::function; + using PresentCallback = std::function; EmbedderTestCompositor(SkISize surface_size, sk_sp 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); diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index da76770763d34..40c5a91cee0b3 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -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, From e94fa08da9aeda501fb3e869861f8c5a91d11352 Mon Sep 17 00:00:00 2001 From: Loic Sharma Date: Wed, 13 Mar 2024 16:31:52 -0700 Subject: [PATCH 2/2] Format --- shell/platform/embedder/embedder.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index d2f26ac3eb505..241d3dc58c5e2 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -1769,11 +1769,9 @@ 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 callback invoked when the embedder should present to a view. /// -/// The |FlutterPresentViewInfo| will be deallocated -/// once the callback returns. +/// The |FlutterPresentViewInfo| will be deallocated once the callback returns. typedef bool (*FlutterPresentViewCallback)( const FlutterPresentViewInfo* /* present info */);