From 72ca2e130eee8dd32573801256694b3dda786345 Mon Sep 17 00:00:00 2001 From: Tong Mu Date: Wed, 13 Mar 2024 17:00:17 -0700 Subject: [PATCH 1/3] Multi-view View Metrics (#46174) This PR adds `FlutterWindowMetricsEvent.viewId` to the embedder API. This PR only tests the ability to send metrics event for the implicit view. Once multiple views can be added via embedder API, we should test the ability to send different IDs. Part of https://github.com/flutter/flutter/issues/144806 Part of https://github.com/flutter/flutter/issues/142845 ## Pre-launch Checklist - [ ] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [ ] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [ ] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [ ] I listed at least one issue that this PR fixes in the description above. - [ ] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [ ] I updated/added relevant documentation (doc comments with `///`). - [ ] I signed the [CLA]. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- examples/glfw/FlutterEmbedderGLFW.cc | 3 + examples/glfw_drm/FlutterEmbedderGLFW.cc | 3 + examples/vulkan_glfw/src/main.cc | 7 ++ .../macos/framework/Source/FlutterEngine.mm | 7 +- shell/platform/embedder/embedder.cc | 4 +- shell/platform/embedder/embedder.h | 2 + shell/platform/embedder/fixtures/main.dart | 36 +++++++ .../embedder/tests/embedder_unittests.cc | 99 ++++++++++++++++++- shell/platform/glfw/flutter_glfw.cc | 3 + shell/platform/linux/fl_engine.cc | 4 + .../platform/windows/flutter_windows_view.cc | 6 +- 11 files changed, 161 insertions(+), 13 deletions(-) diff --git a/examples/glfw/FlutterEmbedderGLFW.cc b/examples/glfw/FlutterEmbedderGLFW.cc index ae7fad5dec2ba..a5e5e63643809 100644 --- a/examples/glfw/FlutterEmbedderGLFW.cc +++ b/examples/glfw/FlutterEmbedderGLFW.cc @@ -81,6 +81,9 @@ void GLFWwindowSizeCallback(GLFWwindow* window, int width, int height) { event.width = width * g_pixelRatio; event.height = height * g_pixelRatio; event.pixel_ratio = g_pixelRatio; + // This example only supports a single window, therefore we assume the event + // occurred in the only view, the implicit view. + event.view_id = kImplicitViewId; FlutterEngineSendWindowMetricsEvent( reinterpret_cast(glfwGetWindowUserPointer(window)), &event); diff --git a/examples/glfw_drm/FlutterEmbedderGLFW.cc b/examples/glfw_drm/FlutterEmbedderGLFW.cc index f4a9ce8ead473..79caba2dc2fef 100644 --- a/examples/glfw_drm/FlutterEmbedderGLFW.cc +++ b/examples/glfw_drm/FlutterEmbedderGLFW.cc @@ -104,6 +104,9 @@ void GLFWwindowSizeCallback(GLFWwindow* window, int width, int height) { event.width = width * g_pixelRatio; event.height = height * g_pixelRatio; event.pixel_ratio = g_pixelRatio; + // This example only supports a single window, therefore we assume the event + // occurred in the only view, the implicit view. + event.view_id = kImplicitViewId; FlutterEngineSendWindowMetricsEvent( reinterpret_cast(glfwGetWindowUserPointer(window)), &event); diff --git a/examples/vulkan_glfw/src/main.cc b/examples/vulkan_glfw/src/main.cc index c6fb9d591d496..ebd55dec02e9d 100644 --- a/examples/vulkan_glfw/src/main.cc +++ b/examples/vulkan_glfw/src/main.cc @@ -32,6 +32,7 @@ static const size_t kInitialWindowHeight = 600; // `VK_PRESENT_MODE_MAILBOX_KHR` for continual swap without horizontal tearing, // or `VK_PRESENT_MODE_IMMEDIATE_KHR` for no vsync. static const VkPresentModeKHR kPreferredPresentMode = VK_PRESENT_MODE_FIFO_KHR; +static constexpr FlutterViewId kImplicitViewId = 0; static_assert(FLUTTER_ENGINE_VERSION == 1, "This Flutter Embedder was authored against the stable Flutter " @@ -86,6 +87,9 @@ void GLFWcursorPositionCallbackAtPhase(GLFWwindow* window, std::chrono::duration_cast( std::chrono::high_resolution_clock::now().time_since_epoch()) .count(); + // This example only supports a single window, therefore we assume the event + // occurred in the only view, the implicit view. + event.view_id = kImplicitViewId; FlutterEngineSendPointerEvent(g_state.engine, &event, 1); } @@ -130,6 +134,9 @@ void GLFWframebufferSizeCallback(GLFWwindow* window, int width, int height) { event.width = width; event.height = height; event.pixel_ratio = g_pixelRatio; + // This example only supports a single window, therefore we assume the event + // occurred in the only view, the implicit view. + event.view_id = kImplicitViewId; FlutterEngineSendWindowMetricsEvent(g_state.engine, &event); } diff --git a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm index c8c1b98344dc4..56419b18a661c 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterEngine.mm @@ -962,12 +962,6 @@ - (nonnull NSString*)executableName { } - (void)updateWindowMetricsForViewController:(FlutterViewController*)viewController { - if (viewController.viewId != kFlutterImplicitViewId) { - // TODO(dkwingsmt): The embedder API only supports single-view for now. As - // embedder APIs are converted to multi-view, this method should support any - // views. - return; - } if (!_engine || !viewController || !viewController.viewLoaded) { return; } @@ -986,6 +980,7 @@ - (void)updateWindowMetricsForViewController:(FlutterViewController*)viewControl .left = static_cast(scaledBounds.origin.x), .top = static_cast(scaledBounds.origin.y), .display_id = static_cast(displayId), + .view_id = viewController.viewId, }; _embedderAPI.SendWindowMetricsEvent(_engine, &windowMetricsEvent); } diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index f35dd805ecb77..8d4646eb5ffb8 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -2141,8 +2141,8 @@ FlutterEngineResult FlutterEngineSendWindowMetricsEvent( if (engine == nullptr || flutter_metrics == nullptr) { return LOG_EMBEDDER_ERROR(kInvalidArguments, "Engine handle was invalid."); } - // TODO(dkwingsmt): Use a real view ID when multiview is supported. - int64_t view_id = kFlutterImplicitViewId; + FlutterViewId view_id = + SAFE_ACCESS(flutter_metrics, view_id, kFlutterImplicitViewId); flutter::ViewportMetrics metrics; diff --git a/shell/platform/embedder/embedder.h b/shell/platform/embedder/embedder.h index dce500fe66897..f4afc9f5945d8 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -859,6 +859,8 @@ typedef struct { double physical_view_inset_left; /// The identifier of the display the view is rendering on. FlutterEngineDisplayId display_id; + /// The view that this event is describing. + int64_t view_id; } FlutterWindowMetricsEvent; /// The phase of the pointer event. diff --git a/shell/platform/embedder/fixtures/main.dart b/shell/platform/embedder/fixtures/main.dart index dffa430fbb520..7270526b830e1 100644 --- a/shell/platform/embedder/fixtures/main.dart +++ b/shell/platform/embedder/fixtures/main.dart @@ -1334,6 +1334,42 @@ void pointer_data_packet_view_id() { signalNativeTest(); } +Map _getAllViewSizes() { + final Map result = {}; + for (final FlutterView view in PlatformDispatcher.instance.views) { + result[view.viewId] = view.physicalSize; + } + return result; +} + +List _findDifferences(Map a, Map b) { + final Set result = {}; + a.forEach((int viewId, Size sizeA) { + if (!b.containsKey(viewId) || b[viewId] != sizeA) { + result.add(viewId); + } + }); + b.forEach((int viewId, Size sizeB) { + if (!a.containsKey(viewId)) { + result.add(viewId); + } + }); + return result.toList()..sort(); +} + +@pragma('vm:entry-point') +void window_metrics_event_view_id() { + Map sizes = _getAllViewSizes(); + PlatformDispatcher.instance.onMetricsChanged = () { + final Map newSizes = _getAllViewSizes(); + final List differences = _findDifferences(sizes, newSizes); + sizes = newSizes; + signalNativeMessage('Changed: $differences'); + }; + + signalNativeTest(); +} + @pragma('vm:entry-point') Future channel_listener_response() async { channelBuffers.setListener('test/listen', diff --git a/shell/platform/embedder/tests/embedder_unittests.cc b/shell/platform/embedder/tests/embedder_unittests.cc index 44c7426fd70fd..33864fd33d59f 100644 --- a/shell/platform/embedder/tests/embedder_unittests.cc +++ b/shell/platform/embedder/tests/embedder_unittests.cc @@ -2727,7 +2727,7 @@ TEST_F(EmbedderTest, CanSendPointer) { /// Send a pointer event to Dart and wait until the Dart code echos with the /// view ID. -TEST_F(EmbedderTest, CanSendPointerWithViewId) { +TEST_F(EmbedderTest, CanSendPointerEventWithViewId) { auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext); EmbedderConfigBuilder builder(context); builder.SetSoftwareRendererConfig(); @@ -2767,6 +2767,103 @@ TEST_F(EmbedderTest, CanSendPointerWithViewId) { message_latch.Wait(); } +TEST_F(EmbedderTest, WindowMetricsEventDefaultsToImplicitView) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext); + EmbedderConfigBuilder builder(context); + builder.SetSoftwareRendererConfig(); + builder.SetDartEntrypoint("window_metrics_event_view_id"); + + fml::AutoResetWaitableEvent ready_latch, message_latch; + context.AddNativeCallback( + "SignalNativeTest", + CREATE_NATIVE_ENTRY( + [&ready_latch](Dart_NativeArguments args) { ready_latch.Signal(); })); + context.AddNativeCallback( + "SignalNativeMessage", + CREATE_NATIVE_ENTRY([&message_latch](Dart_NativeArguments args) { + auto message = tonic::DartConverter::FromDart( + Dart_GetNativeArgument(args, 0)); + ASSERT_EQ("Changed: [0]", message); + message_latch.Signal(); + })); + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + ready_latch.Wait(); + + FlutterWindowMetricsEvent event = {}; + // Simulate an event that comes from an old version of embedder.h that doesn't + // have the view_id field. + event.struct_size = offsetof(FlutterWindowMetricsEvent, view_id); + event.width = 200; + event.height = 300; + event.pixel_ratio = 1.5; + // Skip assigning event.view_id here to test the default behavior. + + FlutterEngineResult result = + FlutterEngineSendWindowMetricsEvent(engine.get(), &event); + ASSERT_EQ(result, kSuccess); + + message_latch.Wait(); +} + +TEST_F(EmbedderTest, IgnoresWindowMetricsEventForUnknownView) { + auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext); + EmbedderConfigBuilder builder(context); + builder.SetSoftwareRendererConfig(); + builder.SetDartEntrypoint("window_metrics_event_view_id"); + + fml::AutoResetWaitableEvent ready_latch, message_latch; + context.AddNativeCallback( + "SignalNativeTest", + CREATE_NATIVE_ENTRY( + [&ready_latch](Dart_NativeArguments args) { ready_latch.Signal(); })); + + context.AddNativeCallback( + "SignalNativeMessage", + CREATE_NATIVE_ENTRY([&message_latch](Dart_NativeArguments args) { + auto message = tonic::DartConverter::FromDart( + Dart_GetNativeArgument(args, 0)); + // Message latch should only be signaled once as the bad + // view metric should be dropped by the engine. + ASSERT_FALSE(message_latch.IsSignaledForTest()); + ASSERT_EQ("Changed: [0]", message); + message_latch.Signal(); + })); + + auto engine = builder.LaunchEngine(); + ASSERT_TRUE(engine.is_valid()); + + ready_latch.Wait(); + + // Send a window metric for a nonexistent view, which should be dropped by the + // engine. + FlutterWindowMetricsEvent bad_event = {}; + bad_event.struct_size = sizeof(FlutterWindowMetricsEvent); + bad_event.width = 200; + bad_event.height = 300; + bad_event.pixel_ratio = 1.5; + bad_event.view_id = 100; + + FlutterEngineResult result = + FlutterEngineSendWindowMetricsEvent(engine.get(), &bad_event); + ASSERT_EQ(result, kSuccess); + + // Send a window metric for a valid view. The engine notifies the Dart app. + FlutterWindowMetricsEvent event = {}; + event.struct_size = sizeof(FlutterWindowMetricsEvent); + event.width = 200; + event.height = 300; + event.pixel_ratio = 1.5; + event.view_id = 0; + + result = FlutterEngineSendWindowMetricsEvent(engine.get(), &event); + ASSERT_EQ(result, kSuccess); + + message_latch.Wait(); +} + TEST_F(EmbedderTest, RegisterChannelListener) { auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext); diff --git a/shell/platform/glfw/flutter_glfw.cc b/shell/platform/glfw/flutter_glfw.cc index 266a97bec58cc..b00bab8cedbca 100644 --- a/shell/platform/glfw/flutter_glfw.cc +++ b/shell/platform/glfw/flutter_glfw.cc @@ -297,6 +297,9 @@ static void SendWindowMetrics(FlutterDesktopWindowControllerState* controller, } else { event.pixel_ratio = controller->window_wrapper->pixel_ratio_override; } + // The GLFW embedder doesn't support multiple views. We assume all pointer + // events come from the only view, the implicit view. + event.view_id = flutter::kFlutterImplicitViewId; FlutterEngineSendWindowMetricsEvent(controller->engine->flutter_engine, &event); } diff --git a/shell/platform/linux/fl_engine.cc b/shell/platform/linux/fl_engine.cc index 3069cd2b39710..f2c8040aa41d2 100644 --- a/shell/platform/linux/fl_engine.cc +++ b/shell/platform/linux/fl_engine.cc @@ -760,6 +760,10 @@ void fl_engine_send_window_metrics_event(FlEngine* self, event.width = width; event.height = height; event.pixel_ratio = pixel_ratio; + // TODO(dkwingsmt): Assign the correct view ID once the Linux embedder + // supports multiple views. + // https://github.com/flutter/flutter/issues/138178 + event.view_id = flutter::kFlutterImplicitViewId; self->embedder_api.SendWindowMetricsEvent(self->engine, &event); } diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 996a0da3d9a5d..f8a87c825979f 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -352,6 +352,7 @@ void FlutterWindowsView::SendWindowMetrics(size_t width, event.width = width; event.height = height; event.pixel_ratio = dpiScale; + event.view_id = view_id_; engine_->SendWindowMetricsEvent(event); } @@ -588,10 +589,7 @@ void FlutterWindowsView::SendPointerEventWithData( event.device_kind = state->device_kind; event.device = state->pointer_id; event.buttons = state->buttons; - // TODO(dkwingsmt): Use the correct view ID for pointer events once the - // Windows embedder supports multiple views. - // https://github.com/flutter/flutter/issues/138179 - event.view_id = flutter::kFlutterImplicitViewId; + event.view_id = view_id_; // Set metadata that's always the same regardless of the event. event.struct_size = sizeof(event); From 01015e988a1f024744641c2f6137c7acaa5593df Mon Sep 17 00:00:00 2001 From: skia-flutter-autoroll Date: Wed, 13 Mar 2024 20:06:27 -0400 Subject: [PATCH 2/3] Roll Skia from a315e4572f4e to cac09f152d9b (10 revisions) (#51398) https://skia.googlesource.com/skia.git/+log/a315e4572f4e..cac09f152d9b 2024-03-13 skia-autoroll@skia-public.iam.gserviceaccount.com Roll skcms from b440ca2fa89c to d52adb9ccd98 (1 revision) 2024-03-13 skia-autoroll@skia-public.iam.gserviceaccount.com Roll vulkan-deps from 91aab7b7e25f to e6550748fb1e (4 revisions) 2024-03-13 jlavrova@google.com Fix SkTypeface_Fuchsia creation 2024-03-13 fmalita@google.com Revert "Use Chromium's abseil-cpp to unblock the Dawn roll" 2024-03-13 fmalita@chromium.org Use Chromium's abseil-cpp to unblock the Dawn roll 2024-03-13 skia-autoroll@skia-public.iam.gserviceaccount.com Manual roll ANGLE from f16eea308ae1 to 66bc9cfa0014 (21 revisions) 2024-03-13 drott@chromium.org [Fontations-backend] Part 2 of getAdvancedMetrics() 2024-03-13 jlavrova@google.com Creating named instances for each variation in a variable font 2024-03-13 bungeman@google.com Ensure generated ICC profiles have non-empty descriptions 2024-03-13 kjlubick@google.com Remove SK_METAL defines from GrBackendSemaphore If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/skia-flutter-autoroll Please CC bdero@google.com,brianosman@google.com,fmalita@google.com,rmistry@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Skia: https://bugs.chromium.org/p/skia/issues/entry To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- DEPS | 2 +- ci/licenses_golden/licenses_skia | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/DEPS b/DEPS index 7eb2af5b38917..489b9be0f18ff 100644 --- a/DEPS +++ b/DEPS @@ -14,7 +14,7 @@ vars = { 'flutter_git': 'https://flutter.googlesource.com', 'skia_git': 'https://skia.googlesource.com', 'llvm_git': 'https://llvm.googlesource.com', - 'skia_revision': 'a315e4572f4eb86e657df2748d008d0e0482c540', + 'skia_revision': 'cac09f152d9b6ea7fd1694c0a70fc5c58591b554', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 69659ea3d1890..e1c97e379c2b8 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e7589dacd552d6e02831703726d8b1b6 +Signature: dbd979695820689b6c17b9ac998d0238 ==================================================================================================== LIBRARY: etc1 @@ -400,6 +400,7 @@ FILE: ../../../flutter/third_party/skia/package-lock.json FILE: ../../../flutter/third_party/skia/relnotes/FilterColorDeprecated.md FILE: ../../../flutter/third_party/skia/relnotes/PerlinNoise.md FILE: ../../../flutter/third_party/skia/relnotes/WrapImageGenMipmaps.md +FILE: ../../../flutter/third_party/skia/relnotes/mtl_backend.md FILE: ../../../flutter/third_party/skia/relnotes/skcodec_deferred.md FILE: ../../../flutter/third_party/skia/relnotes/skshaper.md FILE: ../../../flutter/third_party/skia/relnotes/skstream.md @@ -9515,12 +9516,14 @@ LIBRARY: skia ORIGIN: ../../../flutter/third_party/skia/gm/emptyshader.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/gm/imagedither.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/include/gpu/ganesh/gl/GrGLMakeWebGLInterface.h + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/include/gpu/ganesh/mtl/GrMtlBackendSemaphore.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_coretext.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_harfbuzz.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_skunicode.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/core/SkKnownRuntimeEffects.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/core/SkKnownRuntimeEffects.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/SwizzlePriv.h + ../../../flutter/third_party/skia/LICENSE +ORIGIN: ../../../flutter/third_party/skia/src/gpu/ganesh/mtl/GrMtlBackendSemaphore.mm + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/RasterPathUtils.cpp + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/gpu/graphite/RasterPathUtils.h + ../../../flutter/third_party/skia/LICENSE ORIGIN: ../../../flutter/third_party/skia/src/sksl/analysis/SkSLCheckSymbolTableCorrectness.cpp + ../../../flutter/third_party/skia/LICENSE @@ -9530,12 +9533,14 @@ TYPE: LicenseType.bsd FILE: ../../../flutter/third_party/skia/gm/emptyshader.cpp FILE: ../../../flutter/third_party/skia/gm/imagedither.cpp FILE: ../../../flutter/third_party/skia/include/gpu/ganesh/gl/GrGLMakeWebGLInterface.h +FILE: ../../../flutter/third_party/skia/include/gpu/ganesh/mtl/GrMtlBackendSemaphore.h FILE: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_coretext.h FILE: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_harfbuzz.h FILE: ../../../flutter/third_party/skia/modules/skshaper/include/SkShaper_skunicode.h FILE: ../../../flutter/third_party/skia/src/core/SkKnownRuntimeEffects.cpp FILE: ../../../flutter/third_party/skia/src/core/SkKnownRuntimeEffects.h FILE: ../../../flutter/third_party/skia/src/gpu/SwizzlePriv.h +FILE: ../../../flutter/third_party/skia/src/gpu/ganesh/mtl/GrMtlBackendSemaphore.mm FILE: ../../../flutter/third_party/skia/src/gpu/graphite/RasterPathUtils.cpp FILE: ../../../flutter/third_party/skia/src/gpu/graphite/RasterPathUtils.h FILE: ../../../flutter/third_party/skia/src/sksl/analysis/SkSLCheckSymbolTableCorrectness.cpp From 599dbd7382ecbe1fa053d47a4e0ac862225d8401 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Sharma?= <737941+loic-sharma@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:22:22 -0700 Subject: [PATCH 3/3] [Embedder API] Add multi-view present callback (#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 --- shell/platform/embedder/embedder.cc | 43 +++++++-- shell/platform/embedder/embedder.h | 44 ++++++++- .../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, 290 insertions(+), 65 deletions(-) diff --git a/shell/platform/embedder/embedder.cc b/shell/platform/embedder/embedder.cc index 8d4646eb5ffb8..b3f39fa9b7c64 100644 --- a/shell/platform/embedder/embedder.cc +++ b/shell/platform/embedder/embedder.cc @@ -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(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 f4afc9f5945d8..291dc88bb5ac5 100644 --- a/shell/platform/embedder/embedder.h +++ b/shell/platform/embedder/embedder.h @@ -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 { diff --git a/shell/platform/embedder/embedder_external_view_embedder.cc b/shell/platform/embedder/embedder_external_view_embedder.cc index b80548d09392e..fe699575e77ea 100644 --- a/shell/platform/embedder/embedder_external_view_embedder.cc +++ b/shell/platform/embedder/embedder_external_view_embedder.cc @@ -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 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 96e5d71f610db..6759350cfe8d7 100644 --- a/shell/platform/embedder/embedder_layers.cc +++ b/shell/platform/embedder/embedder_layers.cc @@ -234,13 +234,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 32727ab329f87..49fd9204f582f 100644 --- a/shell/platform/embedder/embedder_layers.h +++ b/shell/platform/embedder/embedder_layers.h @@ -32,8 +32,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 7270526b830e1..b5ddfac5855c8 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 33864fd33d59f..7119fa1612549 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,