-
Notifications
You must be signed in to change notification settings - Fork 6k
[embedder] Project Arg to specify the display refresh rate #21094
Conversation
shell/platform/embedder/embedder.h
Outdated
| /// | ||
| /// This information is purely advisory and is not used by any component. It | ||
| /// is only used by the tooling to visualize frame performance. | ||
| float display_refresh_rate; |
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.
Not that we're likely to make full use of double-precision, but any particular reason for going with float rather than double here? I'd imagine from a struct-packing perspective, other fields are likely to be 64-bit aligned anyway.
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.
Done.
| public: | ||
| VsyncWaiterFallback(TaskRunners task_runners); | ||
|
|
||
| VsyncWaiterFallback(TaskRunners task_runners, float display_refresh_rate); |
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.
Update the class doc comment to cover this ctor.
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.
Done
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.
Mostly looks good. I'm curious where this will be used. Desktop embedder maybe?
| auto vsync_waiter = shell.GetPlatformView()->CreateVSyncWaiter(); | ||
|
|
||
| const float embedder_refresh_rate = vsync_waiter->GetDisplayRefreshRate(); | ||
| ASSERT_FLOAT_EQ(refresh_rate, embedder_refresh_rate); |
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.
Nit: is it better to be ASSERT_FLOAT_EQ(embedder_refresh_rate, refresh_rate); as ASSERT_FLOAT_EQ(actual, expected)?
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.
good call, done
|
|
||
| const float embedder_refresh_rate = vsync_waiter->GetDisplayRefreshRate(); | ||
| ASSERT_FLOAT_EQ(flutter::VsyncWaiter::kUnknownRefreshRateFPS, | ||
| embedder_refresh_rate); |
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.
ditto.
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.
done
|
This PR was made for the needs of http://github.com/flutter/engine/pull/21095. The API likely needs to be revised based on the outcome of that PR. Stashing this PR until the comments there are resolved. |
b0ff8d4 to
4439679
Compare
shell/platform/embedder/embedder.cc
Outdated
| platform_message_response_callback, // | ||
| vsync_callback, // | ||
| compute_platform_resolved_locale_callback, // | ||
| static_cast<float>(main_display_refresh_rate), // |
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.
Down casting here as this is an internal api and we can change it later if we decide to use the full double precision.
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.
nit: update this to double
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.
Done!
| VsyncWaiterEmbedder::VsyncCallback vsync_callback; // optional | ||
| ComputePlatformResolvedLocaleCallback | ||
| compute_platform_resolved_locale_callback; | ||
| float display_refresh_rate; |
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.
I decided not to plumb the callback all the way through to vsync waiter as currently GetDisplayRefreshRate is const and none of the platforms currently need to dynamically return the refresh rate of the display.
Though I believe we will need that at some point in the future.
shell/platform/embedder/embedder.cc
Outdated
| } | ||
|
|
||
| display_settings.displays = | ||
| new FlutterDisplay[display_settings.display_count]; |
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.
Could we allocate this as a std::vector then hand the callback displays.data() instead to avoid dealing with new/delete?
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.
Good idea!
shell/platform/embedder/embedder.cc
Outdated
| // TODO(iskakaushik): Add support for multiple displays. | ||
| main_display_refresh_rate = display_settings.displays[0].refresh_rate; | ||
|
|
||
| delete display_settings.displays; |
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.
nit: this should be delete[] display_settings.displays; if for some reason using a vector isn't workable.
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.
Used vector as recommended :-)
shell/platform/embedder/embedder.cc
Outdated
| platform_message_response_callback, // | ||
| vsync_callback, // | ||
| compute_platform_resolved_locale_callback, // | ||
| static_cast<float>(main_display_refresh_rate), // |
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.
nit: update this to double
|
|
||
| /// Display refers to a graphics hardware system consisting of a framebuffer, | ||
| /// typically a monitor or a screen. This ID is unique per display and is | ||
| /// stable until the Flutter application restarts. |
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.
How would an embedding enforce this? NSScreen doesn't have an ID, for instance, AFAICT.
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.
This was the display ID I was planning on using: https://developer.apple.com/documentation/coregraphics/cgdirectdisplayid?language=objc.
| /// unavaliable or unknown. | ||
| double refresh_rate; | ||
|
|
||
| } FlutterDisplay; |
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.
We should use FlutterEngine as the prefix for new types; I've already had to add a macro to solve one collision problem with macOS, and I'd rather we not introduce more potential collision points.
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.
Will do.
| /// active displays. | ||
| FlutterDisplay* displays; | ||
|
|
||
| } FlutterDisplaySettings; |
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.
Same note about prefix.
| /// This size of this struct. Must be sizeof(FlutterDisplaySettings). | ||
| size_t struct_size; | ||
|
|
||
| /// Contains the actual number of displays returned in the displays array. |
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.
s/actual number/number/
s/returned// (since this isn't part of a function, so nothing is being returned)
|
|
||
| /// A pointer to storage provided by the caller for an array of | ||
| /// FlutterDisplays. On return, the array contains a list of active displays. | ||
| /// If you pass NULL, on return the display_count contains the total number of |
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.
Again, this seems to be describing a function, but it's the comment for a struct element.
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, agreed, I will go over the docs and make sure they align with structs and functions.
|
|
||
| } FlutterDisplaySettings; | ||
|
|
||
| typedef void (*FlutterDisplaySettingsCallback)( |
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.
Please document.
| /// 1. The frame buffer hardware is connected. | ||
| /// 2. The display is drawable, e.g. it isn't being mirrored from another | ||
| /// connected display or sleeping. | ||
| FlutterDisplaySettingsCallback display_settings_callback; |
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.
I'm confused as to how this API would work; how would the engine know when the display list has changed and it needs to call this again? Since the embedder, not the engine, knows when the display list changes, I would expect a method called by the embedder to push information into the engine.
Even if for some reason that's not necessary now, it certainly will be when we're actually exposing display information in Dart, and we shouldn't have two different ways of providing the same information. /cc @gspencergoog
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.
Good point, currently this change isn't accounting for cases where the display configuration changes while the app is running. I'm thinking of modifying the API to notify the engine on display reconfiguration, with 4 modes:
- Startup (when the app is launched)
- Adding new displays
- Removing existing displays
- Reconfigure an existing display (modify any display settings)
We might be able to use CGDisplayReconfigurationCallBack on macOS.
WDYT?
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.
Yes, I think we will need those events, and they will have to come from the embedder and notify the engine.
One other thing to note is that some platforms won't be able to provide all of the information. For instance, on UWP and web it's not possible to find out what screens are connected, or their resolutions, if the current view isn't on that screen. And it doesn't provide the information for more than one screen if you span screens.
The screen configuration doesn't even have to change, though. You can just drag the window to another screen (or even just adjust it's position so more than half of it is on another screen on some platforms) and that will change these values for that app.
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.
One other thing to note is that some platforms won't be able to provide all of the information. For instance, on UWP and web it's not possible to find out what screens are connected, or their resolutions, if the current view isn't on that screen. And it doesn't provide the information for more than one screen if you span screens.
I will document that this is best effort, with the only guarantee that embedder MUST provide at least one display setting which will correspond to the main screen (where the app window is active).
The screen configuration doesn't even have to change, though. You can just drag the window to another screen (or even just adjust it's position so more than half of it is on another screen on some platforms) and that will change these values for that app.
I am envisioning that this will result in 2 events being invoked by the embedder:
- Add Display: display-2
- Remove Display: display-1
Though there is some additional checks that are needed to be done by the embedders to ensure that the engine is aware of at least one display at any given time (i.e, no remove before add), I think it's ok to have 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.
I will document that this is best effort, with the only guarantee that embedder MUST provide at least one display setting which will correspond to the main screen (where the app window is active).
Well, but when we have multiple windows, there will be multiple display settings that apply (one or more for each window). Not that you need to solve multi-window here, but maybe the requirement should be that it provide screen settings corresponding to each window displayed.
The api currently supports mutliple displays, but the implementation only wires in the first display we get as the main display refresh rate.
5ae1aed to
eadc005
Compare
|
This is superseded by #21355. |
This is then wired to the vsync waiter to provide the advisory display refresh rate.
embedder_unittestshave been amended to test this value both when set and not set.