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

[Windows] Allow adding/removing views #51923

Merged
merged 3 commits into from
Apr 11, 2024

Conversation

loic-sharma
Copy link
Member

@loic-sharma loic-sharma commented Apr 4, 2024

This enables the Windows embedder to render to multiple views using the new FlutterEngineAddView and FlutterEngineRemoveView embedder APIs. See: https://flutter.dev/go/multi-view-embedder-apis
 
Prepares for flutter/flutter#144810
Part of flutter/flutter#142845

Sync over async

Windows expects synchronous operations: windows are created, resized, and destroyed synchronously. However, Flutter native is asynchronous due to its threading model.

This change blocks the platform thread when a non-implicit view is added or removed. See: https://flutter.dev/go/multi-view-sync-over-async

Synchronization

The embedder and engine have separate view states that they synchronize asynchronously. The engine can present a view on the raster thread while the embedder is destroying that same view on the platform thread. This change introduces a mutex to protect against this:

  1. The platform thread acquires a shared lock whenever it needs to access the view.
  2. The platform thread acquires an exclusive lock to add a view to the embedder, before it notifies the engine of the view
  3. The platform thread acquires an exclusive lock to remove a view from the embedder, after the engine has acknowledged the view's removal but before the embedder destroys the view.
  4. The raster thread acquires a shared lock to present to a view. This lock is held for the entirety of the present operation, thereby blocking the platform thread from destroying the view.

The implicit view is an important corner case. The framework/engine believe the implicit view always exists, even if the app is in headless mode. The embedder does not notify the engine when it destroys the implicit view. In other words, the embedder must safely ignore presents to the implicit view when it does not exist.

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide and the C++, Objective-C, Java style guides.
  • I listed at least one issue that this PR fixes in the description above.
  • I added new tests to check the change I am making or feature I am adding, or the PR is test-exempt. See testing the engine for instructions on writing and running engine tests.
  • I updated/added relevant documentation (doc comments with ///).
  • I signed the CLA.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@loic-sharma loic-sharma changed the title [Windows] Move EGL surface creation [Windows] Allow adding/removing views Apr 4, 2024
@loic-sharma loic-sharma marked this pull request as draft April 4, 2024 22:45
@flutter-dashboard
Copy link

This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again.

@loic-sharma loic-sharma marked this pull request as ready for review April 5, 2024 15:29
@loic-sharma loic-sharma force-pushed the windows_add_remove_view branch from e7c50ad to 62833e5 Compare April 5, 2024 16:23
@loic-sharma loic-sharma force-pushed the windows_add_remove_view branch from 62833e5 to 1b91ac7 Compare April 5, 2024 21:06
Comment on lines 49 to 57
// Whether this view is the implicit view.
//
// The implicit view is a special view for backwards compatibility.
// The engine assumes it can always render to this view, even if the app has
// destroyed the window for this view. The embedder must ignore presents to
// this view after it is destroyed.
//
// The implicit view is the only view that can be created before the
// engine is launched.
Copy link
Contributor

@dkwingsmt dkwingsmt Apr 8, 2024

Choose a reason for hiding this comment

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

Suggested change
// Whether this view is the implicit view.
//
// The implicit view is a special view for backwards compatibility.
// The engine assumes it can always render to this view, even if the app has
// destroyed the window for this view. The embedder must ignore presents to
// this view after it is destroyed.
//
// The implicit view is the only view that can be created before the
// engine is launched.
// Whether this view is the implicit view.
//
// The implicit view is the first view created on an engine, and has some special
// properties in order to keep backwards compatibility.
// * The `FlutterWindowsView` for the implicit view can be created before the
// engine is launched.
// * Even before the `FlutterWindowsView` for the implicit view is created.
// the Dart app thinks the implicit view exists and may render into the view
// (with no effects).
// * Even after the `FlutterWindowsView` for the implicit view is removed, the Dart
// app still thinks the implicit view exists and may render into the view (with
// no effects).

Copy link
Member Author

Choose a reason for hiding this comment

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

Is there something you think is unclear or missing in the original comment? I currently prefer the original comment, but I'm happy to expand/reword anything in it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Nevermind, I just realized that this entire file is not for the end user but is internal.

Copy link
Contributor

@dkwingsmt dkwingsmt Apr 8, 2024

Choose a reason for hiding this comment

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

Still, I think we should add:

  • The implicit view is the first view created on the engine.
  • The engine assumes it can always render to this view, even before the app creates the FlutterWindowsView or after the app has destroyed the window for this view.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for expanding. This doc is not for end users, this doc is for Windows embedder developers. This method will never be called by an end user.

I'll clarify that the embedder must ignore presents to this view before it is created.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated!

Copy link
Contributor

@dkwingsmt dkwingsmt left a comment

Choose a reason for hiding this comment

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

LGTM

@loic-sharma
Copy link
Member Author

@yaakovschectman @cbracken This is ready for review :)

Comment on lines 516 to 520
struct Captures {
fml::AutoResetWaitableEvent latch;
bool added;
};
Captures captures;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should this struct be defined within the function, and if so, should the variable be declared separately like this?

Copy link
Member Author

@loic-sharma loic-sharma Apr 9, 2024

Choose a reason for hiding this comment

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

Yup, here's prior art in the Windows embedder:

struct Captures {
fml::closure callback;
};
auto captures = new Captures();
captures->callback = std::move(callback);
if (embedder_api_.PostRenderThreadTask(
engine_,
[](void* opaque) {
auto captures = reinterpret_cast<Captures*>(opaque);
captures->callback();
delete captures;
},
captures) == kSuccess) {
return true;
}
delete captures;

Slight difference: for adding/removing views we can stack allocate the captures, we don't need to heap allocate. (We block until the add/remove callback is invoked, guaranteeing the captures exist until the latch is signaled)

fml::AutoResetWaitableEvent latch;
bool added;
};
Captures captures;
Copy link
Member

@cbracken cbracken Apr 10, 2024

Choose a reason for hiding this comment

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

Here and elsewhere, consider zero-initialising this as:

Captures captures = {};

By default, locals are not zero-initialised so worth being on the safe side.

Copy link
Member Author

Choose a reason for hiding this comment

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

Updated!

Copy link
Member

@cbracken cbracken left a comment

Choose a reason for hiding this comment

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

lgtm with a teensy nit.

@loic-sharma loic-sharma added the autosubmit Merge PR when tree becomes green via auto submit App label Apr 11, 2024
@auto-submit auto-submit bot merged commit de89124 into flutter:main Apr 11, 2024
28 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 11, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Apr 11, 2024
auto-submit bot pushed a commit to flutter/flutter that referenced this pull request Apr 11, 2024
…146653)

flutter/engine@98a8ad1...0d36479

2024-04-11 [email protected] Roll Skia from 1dc3c2c1b550 to 112fff965f8b (2 revisions) (flutter/engine#52063)
2024-04-11 [email protected] [Windows] Allow adding/removing views (flutter/engine#51923)

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
gilnobrega pushed a commit to gilnobrega/flutter that referenced this pull request Apr 22, 2024
…lutter#146653)

flutter/engine@98a8ad1...0d36479

2024-04-11 [email protected] Roll Skia from 1dc3c2c1b550 to 112fff965f8b (2 revisions) (flutter/engine#52063)
2024-04-11 [email protected] [Windows] Allow adding/removing views (flutter/engine#51923)

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
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects: desktop autosubmit Merge PR when tree becomes green via auto submit App platform-windows
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants