-
Notifications
You must be signed in to change notification settings - Fork 6k
[iOS] Supported rendering platform views without merging the raster thread. #53826
Changes from 1 commit
02556ae
b3f6670
b31aae6
75f931a
4525bd8
6ce3aa0
be03cf8
6770376
912cd40
1f65cc3
53adc81
870b950
f8267bd
80565d5
2b9a825
0a7dc5a
2745e88
6002aa0
e7a832f
f099d74
e2e6a2a
44d5b5b
b53063a
9a84539
65a5210
735ce22
a4f523b
b6c3345
a4b771e
cd8e1de
6603d18
27c0daa
d794211
2f4314b
25a4e06
ea2e66d
d220885
9b534cd
970e13a
63ebe66
ff4802a
e3fc731
c0fab3b
d73671e
7285907
bcd8519
b25a742
5f6a8d4
be7853d
b19b4d8
ab08739
6e6e5a2
355ab30
8cd1c74
30e7b97
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -666,31 +666,7 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, | |
| // thread, at least until we've refactored iOS surface creation to use IOSurfaces | ||
| // instead of CALayers. | ||
| if (required_overlay_layers > layer_pool_->size()) { | ||
| auto missing_layer_count = required_overlay_layers - layer_pool_->size(); | ||
| TRACE_EVENT0("flutter", "FlutterPlatformViewsController::CreateMissingLayers"); | ||
| // Workaround for FLutterPlatformViewsTest | ||
| if ([[NSThread currentThread] isMainThread]) { | ||
| // Create Missing Layers | ||
| for (auto i = 0u; i < missing_layer_count; i++) { | ||
| CreateLayer(gr_context, // | ||
| ios_context, // | ||
| ((FlutterView*)flutter_view_.get()).pixelFormat // | ||
| ); | ||
| } | ||
| } else { | ||
| auto latch = std::make_shared<fml::CountDownLatch>(1u); | ||
| platform_task_runner_->PostTask([&]() { | ||
| // Create Missing Layers | ||
| for (auto i = 0u; i < missing_layer_count; i++) { | ||
| CreateLayer(gr_context, // | ||
| ios_context, // | ||
| ((FlutterView*)flutter_view_.get()).pixelFormat // | ||
| ); | ||
| } | ||
| latch->CountDown(); | ||
| }); | ||
| latch->Wait(); | ||
| } | ||
| CreateMissingOverlays(gr_context, ios_context, required_overlay_layers); | ||
| } | ||
|
|
||
| int64_t overlay_id = 0; | ||
|
|
@@ -745,66 +721,117 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect, | |
| layer_pool_->RemoveUnusedLayers(); | ||
| layer_pool_->RecycleLayers(); | ||
|
|
||
| // Dispose unused Flutter Views. | ||
| auto views_to_dispose = DisposeViews(); | ||
|
|
||
| auto task = [&, platform_view_layers = std::move(platform_view_layers), // | ||
| current_composition_params = current_composition_params_, // | ||
| views_to_recomposite = views_to_recomposite_, // | ||
| callbacks = callbacks, // | ||
| callbacks = std::move(callbacks), // | ||
| composition_order = composition_order_, // | ||
| unused_layers = unused_layers, views_to_dispose]() mutable { | ||
| TRACE_EVENT0("flutter", "FlutterPlatformViewsController::SubmitFrame::CATransaction"); | ||
|
|
||
| [CATransaction begin]; | ||
|
|
||
| // Configure Flutter overlay views. | ||
| for (const auto& [key, layers] : platform_view_layers) { | ||
| for (const auto& layer_data : layers) { | ||
| layer_data.layer->UpdateViewState(flutter_view_, // | ||
| layer_data.rect, // | ||
| layer_data.view_id, // | ||
| layer_data.overlay_id // | ||
| ); | ||
| } | ||
| } | ||
| unused_layers = std::move(unused_layers), | ||
| views_to_dispose = DisposeViews() // | ||
| ]() mutable { | ||
| PerformSubmit(std::move(platform_view_layers), // | ||
| std::move(callbacks), // | ||
| std::move(current_composition_params), // | ||
| std::move(views_to_recomposite), // | ||
| std::move(composition_order), // | ||
| std::move(unused_layers), // | ||
| std::move(views_to_dispose) // | ||
| ); | ||
| }; | ||
|
|
||
| // Dispose unused Flutter Views. | ||
| for (auto& view : views_to_dispose) { | ||
| [view removeFromSuperview]; | ||
| } | ||
| // Workaround for FlutterPlatformViewsTest.mm | ||
| if ([[NSThread currentThread] isMainThread]) { | ||
| task(); | ||
| } else { | ||
| platform_task_runner_->PostTask(task); | ||
| } | ||
|
|
||
| return did_submit; | ||
| } | ||
|
|
||
| void FlutterPlatformViewsController::CreateMissingOverlays( | ||
| GrDirectContext* gr_context, | ||
| const std::shared_ptr<IOSContext>& ios_context, | ||
| size_t required_overlay_layers) { | ||
| TRACE_EVENT0("flutter", "FlutterPlatformViewsController::CreateMissingLayers"); | ||
|
|
||
| // Composite Platform Views. | ||
| for (int64_t view_id : views_to_recomposite) { | ||
| CompositeWithParams(view_id, current_composition_params[view_id]); | ||
| auto missing_layer_count = required_overlay_layers - layer_pool_->size(); | ||
cbracken marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // Workaround for FLutterPlatformViewsTest | ||
| if ([[NSThread currentThread] isMainThread]) { | ||
| // Create Missing Layers | ||
cbracken marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| for (auto i = 0u; i < missing_layer_count; i++) { | ||
| CreateLayer(gr_context, // | ||
| ios_context, // | ||
| ((FlutterView*)flutter_view_.get()).pixelFormat // | ||
| ); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| // Present callbacks. | ||
| for (const auto& cb : callbacks) { | ||
| cb(); | ||
| auto latch = std::make_shared<fml::CountDownLatch>(1u); | ||
| platform_task_runner_->PostTask([&]() { | ||
| // Create Missing Layers | ||
| for (auto i = 0u; i < missing_layer_count; i++) { | ||
| CreateLayer(gr_context, // | ||
| ios_context, // | ||
| ((FlutterView*)flutter_view_.get()).pixelFormat // | ||
| ); | ||
| } | ||
| latch->CountDown(); | ||
| }); | ||
| latch->Wait(); | ||
| } | ||
|
|
||
| // Organize the layers by their z indexes. | ||
| auto active_composition_order = BringLayersIntoView(platform_view_layers, composition_order); | ||
| /// Update the buffers and mutate the platform views in CATransaction on the platform thread. | ||
| void FlutterPlatformViewsController::PerformSubmit( | ||
cbracken marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| LayersMap platform_view_layers, | ||
| std::vector<SurfaceFrame::DeferredSubmit> callbacks, | ||
| std::map<int64_t, EmbeddedViewParams> current_composition_params, | ||
| std::unordered_set<int64_t> views_to_recomposite, | ||
| std::vector<int64_t> composition_order, | ||
| std::vector<std::shared_ptr<FlutterPlatformViewLayer>> unused_layers, | ||
| std::vector<UIView*> views_to_dispose) { | ||
| TRACE_EVENT0("flutter", "FlutterPlatformViewsController::SubmitFrame::CATransaction"); | ||
|
||
|
|
||
| [CATransaction begin]; | ||
|
|
||
| // Configure Flutter overlay views. | ||
| for (const auto& [key, layers] : platform_view_layers) { | ||
| for (const auto& layer_data : layers) { | ||
| layer_data.layer->UpdateViewState(flutter_view_, // | ||
| layer_data.rect, // | ||
| layer_data.view_id, // | ||
| layer_data.overlay_id // | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| // If a layer was allocated in the previous frame, but it's not used in the current frame, | ||
| // then it can be removed from the scene. | ||
| RemoveUnusedLayers(unused_layers, composition_order, active_composition_order); | ||
| // Dispose unused Flutter Views. | ||
| for (auto& view : views_to_dispose) { | ||
| [view removeFromSuperview]; | ||
| } | ||
|
|
||
| // If the frame is submitted with embedded platform views, | ||
| // there should be a |[CATransaction begin]| call in this frame prior to all the drawing. | ||
| // If that case, we need to commit the transaction. | ||
| [CATransaction commit]; | ||
| }; | ||
| // Composite Platform Views. | ||
| for (int64_t view_id : views_to_recomposite) { | ||
| CompositeWithParams(view_id, current_composition_params[view_id]); | ||
| } | ||
|
|
||
| // Workaround for FlutterPlatformViewsTest.mm | ||
| if ([[NSThread currentThread] isMainThread]) { | ||
| task(); | ||
| } else { | ||
| platform_task_runner_->PostTask(task); | ||
| // Present callbacks. | ||
| for (const auto& cb : callbacks) { | ||
| cb(); | ||
| } | ||
|
|
||
| return did_submit; | ||
| // Organize the layers by their z indexes. | ||
| auto active_composition_order = BringLayersIntoView(platform_view_layers, composition_order); | ||
|
|
||
| // If a layer was allocated in the previous frame, but it's not used in the current frame, | ||
| // then it can be removed from the scene. | ||
| RemoveUnusedLayers(unused_layers, composition_order, active_composition_order); | ||
|
|
||
| // If the frame is submitted with embedded platform views, | ||
|
||
| // there should be a |[CATransaction begin]| call in this frame prior to all the drawing. | ||
| // If that case, we need to commit the transaction. | ||
| [CATransaction commit]; | ||
| } | ||
|
|
||
| std::vector<int64_t> FlutterPlatformViewsController::BringLayersIntoView( | ||
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -310,6 +310,22 @@ class FlutterPlatformViewsController { | |
|
|
||
| using LayersMap = std::map<int64_t, std::vector<LayerData>>; | ||
|
|
||
| /// Update the buffers and mutate the platform views in CATransaction on the platform thread. | ||
| void PerformSubmit(LayersMap platform_view_layers, | ||
| std::vector<SurfaceFrame::DeferredSubmit> callbacks, | ||
| std::map<int64_t, EmbeddedViewParams> current_composition_params, | ||
| std::unordered_set<int64_t> views_to_recomposite, | ||
| std::vector<int64_t> composition_order, | ||
| std::vector<std::shared_ptr<FlutterPlatformViewLayer>> unused_layers, | ||
| std::vector<UIView*> views_to_dispose); | ||
|
|
||
| /// @brief Populate any missing overlay layers. | ||
| /// | ||
| /// This requires posting a task to the platform thread and blocking on its completion. | ||
| void CreateMissingOverlays(GrDirectContext* gr_context, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if the map of layers can contain a nullopt for layers that should go into a specific spot but haven't been constructed yet. Then, in the call that currently reorders, you could inflate them to create the actual view before inserting it in the right spot. Just a suggestion.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is another approach we can do, but if we defer creating the overlay layers we also need to defer constructing encoding the raster work.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. longer term, we should be able to construct the backing layer on any thread (once we fully move away from CAMetalLayer), and so we could remove this hack |
||
| const std::shared_ptr<IOSContext>& ios_context, | ||
| size_t required_overlay_layers); | ||
|
|
||
| void OnCreate(FlutterMethodCall* call, FlutterResult result) __attribute__((cf_audited_transfer)); | ||
| void OnDispose(FlutterMethodCall* call, FlutterResult result) | ||
| __attribute__((cf_audited_transfer)); | ||
|
|
@@ -399,7 +415,7 @@ class FlutterPlatformViewsController { | |
| // A vector of visited platform view IDs. | ||
| std::vector<int64_t> visited_platform_views_; | ||
|
|
||
| // Only compoiste platform views in this set. | ||
| // Only composite platform views in this set. | ||
| std::unordered_set<int64_t> views_to_recomposite_; | ||
|
|
||
| // The FlutterPlatformViewGestureRecognizersBlockingPolicy for each type of platform view. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RunNowOrPostTaskinstead? Its hard to fathom what the workaround is for.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should update the comment, its for iOS simualtors with software backend. The trick to split across threads doesn't work there so I still need to merge threads.
Yeah, will switch to RunNowOrPostTask.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And elsewhere.