diff --git a/shell/platform/windows/flutter_windows_view.cc b/shell/platform/windows/flutter_windows_view.cc index 815cbaa3bb4f8..93f523194714a 100644 --- a/shell/platform/windows/flutter_windows_view.cc +++ b/shell/platform/windows/flutter_windows_view.cc @@ -7,7 +7,9 @@ #include #include "flutter/common/constants.h" +#include "flutter/fml/make_copyable.h" #include "flutter/fml/platform/win/wstring_conversion.h" +#include "flutter/fml/synchronization/waitable_event.h" #include "flutter/shell/platform/common/accessibility_bridge.h" #include "flutter/shell/platform/windows/keyboard_key_channel_handler.h" #include "flutter/shell/platform/windows/text_input_plugin.h" @@ -81,6 +83,22 @@ void UpdateVsync(const FlutterWindowsEngine& engine, } } +/// Destroys a rendering surface that backs a Flutter view. +void DestroyWindowSurface(const FlutterWindowsEngine& engine, + std::unique_ptr surface) { + // EGL surfaces are used on the raster thread if the engine is running. + // There may be pending raster tasks that use this surface. Destroy the + // surface on the raster thread to avoid concurrent uses. + if (engine.running()) { + engine.PostRasterThreadTask(fml::MakeCopyable( + [surface = std::move(surface)] { surface->Destroy(); })); + } else { + // There's no raster thread if engine isn't running. The surface can be + // destroyed on the platform thread. + surface->Destroy(); + } +} + } // namespace FlutterWindowsView::FlutterWindowsView( @@ -105,7 +123,9 @@ FlutterWindowsView::~FlutterWindowsView() { // Notify the engine the view's child window will no longer be visible. engine_->OnWindowStateEvent(GetWindowHandle(), WindowStateEvent::kHide); - DestroyRenderSurface(); + if (surface_) { + DestroyWindowSurface(*engine_, std::move(surface_)); + } } bool FlutterWindowsView::OnEmptyFrameGenerated() { @@ -706,12 +726,6 @@ bool FlutterWindowsView::ResizeRenderSurface(size_t width, size_t height) { return true; } -void FlutterWindowsView::DestroyRenderSurface() { - if (surface_) { - surface_->Destroy(); - } -} - egl::WindowSurface* FlutterWindowsView::surface() const { return surface_.get(); } diff --git a/shell/platform/windows/flutter_windows_view.h b/shell/platform/windows/flutter_windows_view.h index 8cd4e5e71312b..782e63ad53136 100644 --- a/shell/platform/windows/flutter_windows_view.h +++ b/shell/platform/windows/flutter_windows_view.h @@ -50,9 +50,6 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { // Should be called before calling FlutterEngineRun using this view. void CreateRenderSurface(); - // Destroys current rendering surface if one has been allocated. - void DestroyRenderSurface(); - // Get the EGL surface that backs the Flutter view. // // This might be nullptr or an invalid surface. diff --git a/shell/platform/windows/flutter_windows_view_unittests.cc b/shell/platform/windows/flutter_windows_view_unittests.cc index b4bb9a4789d90..c22459f32bd3d 100644 --- a/shell/platform/windows/flutter_windows_view_unittests.cc +++ b/shell/platform/windows/flutter_windows_view_unittests.cc @@ -264,6 +264,12 @@ TEST(FlutterWindowsViewTest, Shutdown) { InSequence s; EXPECT_CALL(*engine_ptr, running).WillOnce(Return(true)); EXPECT_CALL(*engine_ptr, RemoveView(view_id)).Times(1); + EXPECT_CALL(*engine_ptr, running).WillOnce(Return(true)); + EXPECT_CALL(*engine_ptr, PostRasterThreadTask) + .WillOnce([](fml::closure callback) { + callback(); + return true; + }); EXPECT_CALL(*surface_ptr, Destroy).Times(1); } } @@ -825,7 +831,14 @@ TEST(FlutterWindowsViewTest, WindowResizeTests) { auto windows_proc_table = std::make_shared>(); std::unique_ptr engine = GetTestEngine(windows_proc_table); + EngineModifier engine_modifier{engine.get()}; + engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC( + PostRenderThreadTask, + ([](auto engine, VoidCallback callback, void* user_data) { + callback(user_data); + return kSuccess; + })); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); @@ -883,7 +896,14 @@ TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) { auto windows_proc_table = std::make_shared>(); std::unique_ptr engine = GetTestEngine(windows_proc_table); + EngineModifier engine_modifier{engine.get()}; + engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC( + PostRenderThreadTask, + ([](auto engine, VoidCallback callback, void* user_data) { + callback(user_data); + return kSuccess; + })); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); @@ -940,7 +960,14 @@ TEST(FlutterWindowsViewTest, TestEmptyFrameResizes) { // https://github.com/flutter/flutter/issues/141855 TEST(FlutterWindowsViewTest, WindowResizeRace) { std::unique_ptr engine = GetTestEngine(); + EngineModifier engine_modifier(engine.get()); + engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC( + PostRenderThreadTask, + ([](auto engine, VoidCallback callback, void* user_data) { + callback(user_data); + return kSuccess; + })); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); @@ -980,7 +1007,14 @@ TEST(FlutterWindowsViewTest, WindowResizeRace) { // even though EGL initialized successfully. TEST(FlutterWindowsViewTest, WindowResizeInvalidSurface) { std::unique_ptr engine = GetTestEngine(); + EngineModifier engine_modifier(engine.get()); + engine_modifier.embedder_api().PostRenderThreadTask = MOCK_ENGINE_PROC( + PostRenderThreadTask, + ([](auto engine, VoidCallback callback, void* user_data) { + callback(user_data); + return kSuccess; + })); auto egl_manager = std::make_unique(); auto surface = std::make_unique(); @@ -1477,6 +1511,11 @@ TEST(FlutterWindowsViewTest, DisablesVSyncAfterStartup) { EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(true)); EXPECT_CALL(*surface_ptr, SetVSyncEnabled(false)).WillOnce(Return(true)); EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(true)); + EXPECT_CALL(*engine.get(), PostRasterThreadTask) + .WillOnce([](fml::closure callback) { + callback(); + return true; + }); EXPECT_CALL(*surface_ptr, Destroy).Times(1); EngineModifier modifier{engine.get()}; @@ -1519,6 +1558,12 @@ TEST(FlutterWindowsViewTest, EnablesVSyncAfterStartup) { EXPECT_CALL(*surface_ptr, MakeCurrent).WillOnce(Return(true)); EXPECT_CALL(*surface_ptr, SetVSyncEnabled(true)).WillOnce(Return(true)); EXPECT_CALL(render_context, ClearCurrent).WillOnce(Return(true)); + + EXPECT_CALL(*engine.get(), PostRasterThreadTask) + .WillOnce([](fml::closure callback) { + callback(); + return true; + }); EXPECT_CALL(*surface_ptr, Destroy).Times(1); EngineModifier modifier{engine.get()};