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

Made a way to turn off the OpenGL operations on the IO thread for backgrounded apps - #13908

Merged
gaaclarke merged 30 commits into
flutter-team-archive:masterfrom
gaaclarke:turn-off-io-thread
Nov 22, 2019
Merged

gaaclarke merged 30 commits into
flutter-team-archive:masterfrom
gaaclarke:turn-off-io-thread

Conversation

@gaaclarke

@gaaclarke gaaclarke commented Nov 19, 2019 •

Copy link
Copy Markdown
Contributor

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.

@gaaclarke gaaclarke added the Work in progress (WIP) Not ready (yet) for review! label Nov 19, 2019
@gaaclarke

Copy link
Copy Markdown
Contributor Author

@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

@gaaclarke gaaclarke removed the Work in progress (WIP) Not ready (yet) for review! label Nov 19, 2019
@chinmaygarde

Copy link
Copy Markdown
Contributor

We already are.

@gaaclarke gaaclarke changed the title Implemented a way to turn off the io thread when the app is backgrounded Made a way to turn off the OpenGL operations on the IO thread for backgrounded apps Nov 19, 2019
Comment thread fml/memory/thread_checker.h Resolved
Comment thread fml/synchronization/sync_switch.h Resolved
Comment thread fml/BUILD.gn Resolved
Comment thread shell/common/engine.cc Outdated
state == "AppLifecycleState.detached") {
activity_running_ = false;
StopAnimator();
is_backgrounded_sync_switch_->SetSwitch(true);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Comment thread shell/common/engine.cc Resolved
@dnfield

dnfield commented Nov 20, 2019

Copy link
Copy Markdown
Contributor

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.

@gaaclarke

Copy link
Copy Markdown
Contributor Author

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 chinmaygarde left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Saw your comment in the middle of a review, just sending what I have. Will review again when ready.

Comment thread fml/memory/thread_checker.h Resolved
Comment thread fml/synchronization/sync_switch.h Resolved
Comment thread fml/synchronization/sync_switch.h Resolved
Comment thread fml/synchronization/sync_switch.h Resolved
Comment thread fml/synchronization/sync_switch.h Resolved
Comment thread fml/synchronization/sync_switch.cc Resolved
Comment thread fml/synchronization/sync_switch.cc Resolved
Comment thread fml/synchronization/sync_switch.cc Resolved
Comment thread fml/synchronization/sync_switch.cc Resolved
Comment thread fml/synchronization/sync_switch.h Resolved
- renamed the switch to talk about disabling the GPU instead of
  backgrounding
- Renamed SetTrue and SetFalse to SetIfTrue and SetIfFalse
SyncSwitch::SyncSwitch(bool value) : value_(value) {}

void SyncSwitch::Execute(const SyncSwitch::Handlers& handlers) {
std::scoped_lock guard(mutex_);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

Comment thread fml/synchronization/sync_switch.cc Outdated
}

void SyncSwitch::SetSwitch(bool value) {
{

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: You missed removed the extra scope here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done

Comment thread fml/synchronization/sync_switch.h Outdated
/// 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);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Still neither here not there, either use the pass by value if using the convention before #13975 lands or const refs if after.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

@gaaclarke
gaaclarke merged commit 97a23a8 into flutter-team-archive:master Nov 22, 2019
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 23, 2019
@buptwsg

buptwsg commented Jun 25, 2020

Copy link
Copy Markdown

hi, gaaclarke, does this PR provide a API to 'turn off the OpenGL operations on the IO thread for backgrounded apps'?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Development

Successfully merging this pull request may close these issues.

6 participants