Skip to content
This repository has been archived by the owner on Feb 25, 2025. It is now read-only.

[engine] support combined UI/Platform thread for iOS/Android. #53656

Merged
merged 7 commits into from
Jul 9, 2024

Conversation

jonahwilliams
Copy link
Member

@jonahwilliams jonahwilliams commented Jun 30, 2024

Experimentally support merging UI and platform thread on Android/iOS. This works by changing the shell holder to set the UI thread to the platform thread. Several shell APIs that post messages from the platform to ui thread were changed to use RunNowOrPostTask to immediately call the UI task if the threads are the same.

Experimentally, this seems to work reasonably well if there are no platform views. On Android with TLHC it works fine either way, while iOS currently takes a big performance hit.

This can be opted into via a Plist:

	<key>FLTEnableMergedPlatformUIThread</key>
	<true/>

Or via AndroidManifest.xml:

 <meta-data
            android:name="io.flutter.embedding.android.EnableMergedPlatformUIThread"
            android:value="true" />

flutter/flutter#150525

@@ -1490,6 +1499,7 @@ void Shell::LoadDartDeferredLibrary(
intptr_t loading_unit_id,
std::unique_ptr<const fml::Mapping> snapshot_data,
std::unique_ptr<const fml::Mapping> snapshot_instructions) {
// TODO(jonahwilliams): what thread is this called from?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd check the headerdoc in platform_view.h to be sure. But I think this can be called on any thread by the embedder. I also don't think this is used at all on non-Fuchsia platforms. And even there, I think we moved away from deferred libraries split into units. But, the code to service such a path may still be there.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't say. This isn't for fuchsia, its for the android app bundle/deferred library support.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it looks like this is probably only called from the platform thread, but I'm not sure if we have any real tests here so I'll leave it as is.

@jonahwilliams jonahwilliams changed the title [engine] support merged UI/Platform thread. [engine] support combined UI/Platform thread. Jul 1, 2024
@jonahwilliams jonahwilliams changed the title [engine] support combined UI/Platform thread. [engine] support combined UI/Platform thread for iOS/Android. Jul 1, 2024
Copy link
Member

@chinmaygarde chinmaygarde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer we start with the tester shells first. It is easy to go merge the threads but there is no going back because of plugins.

This change itself LGTM.

@jonahwilliams
Copy link
Member Author

The tester shells are already running in a combined thead mode (unless run with --force-multithreading).

It is easy to go merge the threads but there is no going back because of plugins.

Adding an experimental option that we don't advertise is not a one way door. Anyone that ships code that depends on this behavior can be broken

@knopp
Copy link
Member

knopp commented Jul 1, 2024

I love this! I'll try to get this working on macOS with the resize synchronizer, but I'm not sure how much time I'm going to have this week (FlutterCon).

Btw. the io.flutter.1.ui thread still gets created, just sitting there empty.

@reidbaker reidbaker self-requested a review July 2, 2024 18:15
@knopp
Copy link
Member

knopp commented Jul 2, 2024

I have a very fragile and buggy but working macOS proof of concept working. The idea is to short-circuit macOS vsync waiter during resizing to fire immediately, and then to modify the vsync waiter machinery in the engine so that if the vsync callback is called from UI thread and frame_start_time is in past, it will trigger the frame immediately instead.

@jonahwilliams
Copy link
Member Author

Btw. the io.flutter.1.ui thread still gets created, just sitting there empty.

Should be fixed now.

@knopp
Copy link
Member

knopp commented Jul 7, 2024

I've a WIP PR for macos here. Some remaining open questions there, mostly regarding the microtask queue.

@jonahwilliams
Copy link
Member Author

@chinmaygarde do you intend to review this patch?

Copy link
Member

@knopp knopp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. I am a bit unsure though why is the fml::MessageLoop initialized on platform thread for both iOS and Android. This predates platform isolates so I'm wondering if the reason is raster thread merging?

Having fml::MessageLoop available for platform thread means that no changes are necessary to run Dart code on platform thread, but same thing will not work for embedder API based embedders, so I'm wondering if we could be more consistent here (does not need to happen in this PR).

Copy link
Member

@chinmaygarde chinmaygarde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding an experimental option that we don't advertise is not a one way door. Anyone that ships code that depends on this behavior can be broken.

Isn't it though? It will fracture the plugin ecosystem into plugins that assume calls are made directly on the platform thread (the stuff using FFI) vs those that post messages back and forth. There is kinda no going back if enough plugins start assuming this.

Flags end up getting used and we don't have an experiments mechanism like in Chrome that timeboxes and backs out experiments that don't pan out.

The mechanics of moving the UI thread to the platform are fairly straightforward. But my understanding was that while we were intending to do this, there were open questions around performance and we didn't know how much of a performance hit we were willing to tolerate in heavy applications alike the 1P apps and stuff like Wonderous with the platform views.

So, I think this should come after those questions are answered.

@jonahwilliams
Copy link
Member Author

I simply can't agree that an experimental flag presents an opportunity for ecosystem breakage. I agree that we should good answers for the question of performance before we make this the default behavior, but opting in for testing and experimentation is well within the realm of changes like platform isolates, wide gamut, impeller, et cetera.

Copy link
Member

@chinmaygarde chinmaygarde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair points.

I know this isn't possible now but my dream would be to have something like the origin trials in Chrome. We'd like to be able to safely gauge the impact of specific experiments while ensuring that users don't build their businesses on experimental stuff (perhaps unknowingly). The origin trials also have a way of backing out experiments that don't pan out (either because they are bad ideas or there weren't the resources to carry them to completion).

I'm absolutely not averse to adding additional experimental flags. Its just that this one is unique in that:

  • Perhaps unknowingly, a user may depend on a plugin that makes FFI calls on the platform thread. They might need to disable the flag say because of performance issues and now their app is thread-unsafe. There is no way for us to detect such races or offer support.
  • The stuff you mentioned (platform isolates, wide gamut, impeller, ...) can be backed out cleanly via the single flag and we either have fallbacks in place or clear error conditions. The notion that building plugins and toying with the flag "may introduce undefined behavior due to data races that we cannot detect easily" muddies the waters with this one.

But, I see your point. We need to be able to experiment with such things and we don't have a mechanism to do this cleanly. I'd highly appreciate buy in from from someone on the ecosystem side for this one. Just to calm my nerves about this one if nothing.

The mechanics of this patch LGTM.

@knopp
Copy link
Member

knopp commented Jul 9, 2024

If the plugin assumes merged UI and platform thread, it would mean that the plugin imposes the flag on the end user, which I don't really like. For example with super_drag_and_drop and super_clipboard, I make quite a few assumptions about threading (I routinely need to pause platform thread to while getting answer from UI thread). I plan to support merged threads as soon as it lands on all platforms, but as an addition to the default threading model, and not exclusively.

I think we need to communicate this clearly that if plugins make threading assumptions, they need to support both models for the time being, and never force the flag on end user.

@reidbaker
Copy link
Contributor

I am not sure you can force plugin authors to support both models. Exposing to plugins which model is being used then asking nicely might be your only option. If you let plugin authors detect the threading model and let the apps set the threading model then plugin authors can choose how to handle the difference. Plugins that dont care can Ignore the change, some will support both, some can throw exceptions or can use the thread model to enable or disable a subset of features.

@jonahwilliams
Copy link
Member Author

To be clear, this flag is for our own experimentation.

There is absoltely no plan to make this a configurable option for developers. Either we find a means to merge the platform and ui threads, in general, and make that the only default behavior, or we don't.

I'm not currently aware of any circumstances where moving from un merged to merged thread model will break any plugins, but this is something that I hope to discover this quarter. (I could certainly see the opposite breaking plugins, but that won't be a configurable option)

@jonahwilliams jonahwilliams added the autosubmit Merge PR when tree becomes green via auto submit App label Jul 9, 2024
@auto-submit auto-submit bot merged commit 67bf581 into flutter:main Jul 9, 2024
31 checks passed
@knopp
Copy link
Member

knopp commented Jul 9, 2024

This will absolutely cause super_drag_and_drop to deadlock, since it needs to respond to synchronous platform callbacks and it does it by carefully blocking the platform thread until it has response from UI thread. But I also think this is a very uncommon scenario.

@jonahwilliams
Copy link
Member Author

Assuming we had a solution to the other thread merging problems, I'd like us to handle that with some like "Starting from (Future) version 3.XX, threads will be merged, if you do X/Y/Z instead do A/B/C" instead of letting folks opt in or out.

engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 9, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Jul 9, 2024
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Jul 10, 2024
…151495)

flutter/engine@d3269d5...9d943eb

2024-07-09 [email protected] Avoid using a private GTest macro to skip tests. (flutter/engine#53782)
2024-07-09 [email protected] [Impeller] Use downsample shader for blur instead of mip levels. (flutter/engine#53760)
2024-07-09 [email protected] [engine] support combined UI/Platform thread for iOS/Android. (flutter/engine#53656)
2024-07-09 [email protected] [Impeller] Enable framebuffer fetch tests disabled on OpenGL ES. (flutter/engine#53766)
2024-07-09 [email protected] [Impeller] implement experimental canvas in snapshot controller. (flutter/engine#53750)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-engine-flutter-autoroll
Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human
is aware of the problem.

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
@jonahwilliams jonahwilliams deleted the clear_color_opt branch July 11, 2024 22:59
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
autosubmit Merge PR when tree becomes green via auto submit App platform-android platform-ios
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants