Repository navigation
Made a way to turn off the OpenGL operations on the IO thread for backgrounded apps - #13908
Conversation
between threads.
|
@chinmaygarde Do you think we should drain the unref queue before backgrounding since I'm ignoring most draining when we are backgrounded? I didn't protect the one here: https://github.com/gaaclarke/engine/blob/4e52914a937d1acfb22d0d17989e2074d1a00bc1/flow/skia_gpu_object.cc#L27:L27 |
| state == "AppLifecycleState.detached") { | ||
| activity_running_ = false; | ||
| StopAnimator(); | ||
| is_backgrounded_sync_switch_->SetSwitch(true); |
There was a problem hiding this comment.
I don't think this is right, even for iOS. We shouldn't be using .detached here and even .paused can give us a false signal on iOS (if we just lost the VC but haven't actually gone to background). It seems like we have a bug where only the FlutterViewController is subscribing to the app lifecycle events but not the FlutterEngine. I think what we really want is to move some of that logic into FlutterEngine. /cc @xster who recently did work on that and might know something I'm missing.
I would find it clearer to name this something like is_gpu_access_allowed_switch. We could then expose a way to set that for the embedders, so that an individual embedder can decide to set it to false when needed (on iOS, only when the app is definitely going to background, as opposed to just losing the VC; on other platforms, status quo for now).
I believe this would also still cause the crash in the following scenario:
- Create engine with no VC
- Have engine run Dart code that asks to decode an image after some delay e.g.:
Future<void> main async {
await Future<void>.delayed(const Duration(seconds: 5));
// code to decode an image
}- Before that delay, background the app after the engine has had time to start the Dart code but before the image decoding reaches a GL call
- I don't believe this code path will have executed at all, and the switch has been defaulted to false (right?).
So I think for this patch we really should have the FlutterEngine listening for applicationWillResignActive and applicationBecameActive. and then it could set the value of this switch specifically in those cases.
There was a problem hiding this comment.
That sounds fine. I just realized this morning that I wasn't activating the switch on the platform thread so moving the logic up the stack will get both what you want and get me back on the platform thread.
There was a problem hiding this comment.
Yes, good point from @dnfield (and the new implementation looks reasonable too).
This reasons the framework (currently the engine) wanting to stop scheduling a frame (flutter/flutter#45131) is indeed not a 1:1 match with the reasons the engine wanting to block an outgoing frame.
|
I think this approach is overall safer than locking the IO queue, although you are right that we will have to take care to guard any potential GL calls on iOS with it. |
|
This is not quite right yet. The turning off of the switch is happening on the UI thread. We need to turn it off on the platform thread to avoid synchronizing between the UI and the Platform threads. |
chinmaygarde
left a comment
There was a problem hiding this comment.
Saw your comment in the middle of a review, just sending what I have. Will review again when ready.
- renamed the switch to talk about disabling the GPU instead of backgrounding - Renamed SetTrue and SetFalse to SetIfTrue and SetIfFalse
image decompression.
| SyncSwitch::SyncSwitch(bool value) : value_(value) {} | ||
|
|
||
| void SyncSwitch::Execute(const SyncSwitch::Handlers& handlers) { | ||
| std::scoped_lock guard(mutex_); |
There was a problem hiding this comment.
I don't know why GitHub ate my comment about the mutex, so adding it back in:
Please use the shared exclusive mutex in //flutter/fml/synchronization/shared_mutex.h with a SharedLock here and UniqueLock in SetSwitch.
There was a problem hiding this comment.
Discussed offline, scoped_lock makes sense. It avoids the overhead of a read-write lock when we don't need it and the overhead of a virtual function.
| } | ||
|
|
||
| void SyncSwitch::SetSwitch(bool value) { | ||
| { |
There was a problem hiding this comment.
Nit: You missed removed the extra scope here.
| /// Represents the 2 code paths available when calling |SyncSwitch::Execute|. | ||
| struct Handlers { | ||
| /// Sets the handler that will be executed if the |SyncSwitch| is true. | ||
| Handlers& SetIfTrue(std::function<void()>&& handler); |
There was a problem hiding this comment.
Still neither here not there, either use the pass by value if using the convention before #13975 lands or const refs if after.
There was a problem hiding this comment.
Discussed offline. I was working under the false idea that you had to explicitly create rvalues and that this would force users to pass in rvalues. I moved this over to const ref to match the other code.
… for backgrounded apps (flutter-team-archive/engine#13908)
|
hi, gaaclarke, does this PR provide a API to 'turn off the OpenGL operations on the IO thread for backgrounded apps'? |
Related issue: flutter/flutter#26366
As apposed to previous PRs, this PR doesn't pause the thread, it attempts to guard usages of OpenGL that may happen while the app is backgrounded.