From 1fd6a547fb57b12b4ff925eb4f3fb8540312590b Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Mon, 12 Aug 2024 14:27:54 -0700 Subject: [PATCH] [iOS] keep threads merged when using Skia renderer on iOS (flutter/engine#54514) Potential fix for money crasher. --- .../Source/platform_views_controller.h | 6 +- .../Source/platform_views_controller.mm | 63 ++++++++++--------- .../darwin/ios/ios_external_view_embedder.mm | 8 ++- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.h b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.h index 551792ef8d..1079b6d767 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.h +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.h @@ -84,14 +84,16 @@ class PlatformViewsController { /// /// Called from the raster thread. PostPrerollResult PostPrerollAction( - const fml::RefPtr& raster_thread_merger); + const fml::RefPtr& raster_thread_merger, + bool impeller_enabled); /// @brief Mark the end of a compositor frame. /// /// May determine changes are required to the thread merging state. /// Called from the raster thread. void EndFrame(bool should_resubmit_frame, - const fml::RefPtr& raster_thread_merger); + const fml::RefPtr& raster_thread_merger, + bool impeller_enabled); /// @brief Returns the Canvas for the overlay slice for the given platform view. /// diff --git a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm index 2627268961..806d951001 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/framework/Source/platform_views_controller.mm @@ -15,13 +15,11 @@ namespace { -#ifdef FML_OS_IOS_SIMULATOR // The number of frames the rasterizer task runner will continue // to run on the platform thread after no platform view is rendered. // // Note: this is an arbitrary number. static const int kDefaultMergedLeaseDuration = 10; -#endif // FML_OS_IOS_SIMULATOR static constexpr NSUInteger kFlutterClippingMaskViewPoolCapacity = 5; @@ -291,43 +289,52 @@ void PlatformViewsController::CancelFrame() { } PostPrerollResult PlatformViewsController::PostPrerollAction( - const fml::RefPtr& raster_thread_merger) { + const fml::RefPtr& raster_thread_merger, + bool impeller_enabled) { // TODO(jonahwilliams): remove this once Software backend is removed for iOS Sim. #ifdef FML_OS_IOS_SIMULATOR - if (composition_order_.empty()) { - return PostPrerollResult::kSuccess; - } - if (!raster_thread_merger->IsMerged()) { - // The raster thread merger may be disabled if the rasterizer is being - // created or teared down. - // - // In such cases, the current frame is dropped, and a new frame is attempted - // with the same layer tree. - // - // Eventually, the frame is submitted once this method returns `kSuccess`. - // At that point, the raster tasks are handled on the platform thread. - CancelFrame(); - return PostPrerollResult::kSkipAndRetryFrame; - } - // If the post preroll action is successful, we will display platform views in the current frame. - // In order to sync the rendering of the platform views (quartz) with skia's rendering, - // We need to begin an explicit CATransaction. This transaction needs to be submitted - // after the current frame is submitted. - raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration); - return PostPrerollResult::kSuccess; + const bool merge_threads = true; #else - return PostPrerollResult::kSuccess; + const bool merge_threads = !impeller_enabled; #endif // FML_OS_IOS_SIMULATOR + + if (merge_threads) { + if (composition_order_.empty()) { + return PostPrerollResult::kSuccess; + } + if (!raster_thread_merger->IsMerged()) { + // The raster thread merger may be disabled if the rasterizer is being + // created or teared down. + // + // In such cases, the current frame is dropped, and a new frame is attempted + // with the same layer tree. + // + // Eventually, the frame is submitted once this method returns `kSuccess`. + // At that point, the raster tasks are handled on the platform thread. + CancelFrame(); + return PostPrerollResult::kSkipAndRetryFrame; + } + // If the post preroll action is successful, we will display platform views in the current + // frame. In order to sync the rendering of the platform views (quartz) with skia's rendering, + // We need to begin an explicit CATransaction. This transaction needs to be submitted + // after the current frame is submitted. + raster_thread_merger->ExtendLeaseTo(kDefaultMergedLeaseDuration); + } + return PostPrerollResult::kSuccess; } void PlatformViewsController::EndFrame( bool should_resubmit_frame, - const fml::RefPtr& raster_thread_merger) { + const fml::RefPtr& raster_thread_merger, + bool impeller_enabled) { #if FML_OS_IOS_SIMULATOR - if (should_resubmit_frame) { + bool run_check = true; +#else + bool run_check = !impeller_enabled; +#endif // FML_OS_IOS_SIMULATOR + if (run_check && should_resubmit_frame) { raster_thread_merger->MergeWithLease(kDefaultMergedLeaseDuration); } -#endif // FML_OS_IOS_SIMULATOR } void PlatformViewsController::PushFilterToVisitedPlatformViews( diff --git a/engine/src/flutter/shell/platform/darwin/ios/ios_external_view_embedder.mm b/engine/src/flutter/shell/platform/darwin/ios/ios_external_view_embedder.mm index b7c1333d91..f8c2f47c7a 100644 --- a/engine/src/flutter/shell/platform/darwin/ios/ios_external_view_embedder.mm +++ b/engine/src/flutter/shell/platform/darwin/ios/ios_external_view_embedder.mm @@ -59,7 +59,8 @@ PostPrerollResult IOSExternalViewEmbedder::PostPrerollAction( const fml::RefPtr& raster_thread_merger) { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::PostPrerollAction"); FML_CHECK(platform_views_controller_); - PostPrerollResult result = platform_views_controller_->PostPrerollAction(raster_thread_merger); + PostPrerollResult result = platform_views_controller_->PostPrerollAction( + raster_thread_merger, ios_context_->GetBackend() != IOSRenderingBackend::kSkia); return result; } @@ -91,7 +92,8 @@ void IOSExternalViewEmbedder::EndFrame( bool should_resubmit_frame, const fml::RefPtr& raster_thread_merger) { TRACE_EVENT0("flutter", "IOSExternalViewEmbedder::EndFrame"); - platform_views_controller_->EndFrame(should_resubmit_frame, raster_thread_merger); + platform_views_controller_->EndFrame(should_resubmit_frame, raster_thread_merger, + ios_context_->GetBackend() != IOSRenderingBackend::kSkia); } // |ExternalViewEmbedder| @@ -100,7 +102,7 @@ bool IOSExternalViewEmbedder::SupportsDynamicThreadMerging() { #if FML_OS_IOS_SIMULATOR return true; #else - return false; + return ios_context_->GetBackend() == IOSRenderingBackend::kSkia; #endif // FML_OS_IOS_SIMULATOR }