-
Notifications
You must be signed in to change notification settings - Fork 6k
[Windows] Allow adding/removing views #51923
[Windows] Allow adding/removing views #51923
Conversation
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. |
e7c50ad
to
62833e5
Compare
62833e5
to
1b91ac7
Compare
// 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. |
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.
// 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). |
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.
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.
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.
Nevermind, I just realized that this entire file is not for the end user but is internal.
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.
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.
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.
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.
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.
Updated!
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.
LGTM
@yaakovschectman @cbracken This is ready for review :) |
struct Captures { | ||
fml::AutoResetWaitableEvent latch; | ||
bool added; | ||
}; | ||
Captures captures; |
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.
Should this struct be defined within the function, and if so, should the variable be declared separately like this?
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.
Yup, here's prior art in the Windows embedder:
engine/shell/platform/windows/flutter_windows_engine.cc
Lines 752 to 767 in e4e2748
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; |
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.
Here and elsewhere, consider zero-initialising this as:
Captures captures = {};
By default, locals are not zero-initialised so worth being on the safe side.
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.
Updated!
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.
lgtm with a teensy nit.
…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
…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
This enables the Windows embedder to render to multiple views using the new
FlutterEngineAddView
andFlutterEngineRemoveView
embedder APIs. See: https://flutter.dev/go/multi-view-embedder-apisPrepares 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:
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
///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.