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

Conversation

@iskakaushik
Copy link
Contributor

This is then wired to the vsync waiter to provide the advisory display refresh rate. embedder_unittests have been amended to test this value both when set and not set.

///
/// 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;
Copy link
Member

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.

Copy link
Contributor Author

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);
Copy link
Member

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.

Copy link
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
Contributor

@liyuqian liyuqian left a 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);
Copy link
Contributor

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)?

Copy link
Contributor Author

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);
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

@iskakaushik
Copy link
Contributor Author

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.

platform_message_response_callback, //
vsync_callback, //
compute_platform_resolved_locale_callback, //
static_cast<float>(main_display_refresh_rate), //
Copy link
Contributor Author

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.

Copy link
Member

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

Copy link
Contributor Author

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;
Copy link
Contributor Author

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.

}

display_settings.displays =
new FlutterDisplay[display_settings.display_count];
Copy link
Member

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea!

// TODO(iskakaushik): Add support for multiple displays.
main_display_refresh_rate = display_settings.displays[0].refresh_rate;

delete display_settings.displays;
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used vector as recommended :-)

platform_message_response_callback, //
vsync_callback, //
compute_platform_resolved_locale_callback, //
static_cast<float>(main_display_refresh_rate), //
Copy link
Member

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.
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

/// unavaliable or unknown.
double refresh_rate;

} FlutterDisplay;
Copy link
Contributor

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.

Copy link
Contributor Author

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;
Copy link
Contributor

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.
Copy link
Contributor

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
Copy link
Contributor

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.

Copy link
Contributor Author

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)(
Copy link
Contributor

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;
Copy link
Contributor

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

Copy link
Contributor Author

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:

  1. Startup (when the app is launched)
  2. Adding new displays
  3. Removing existing displays
  4. Reconfigure an existing display (modify any display settings)

We might be able to use CGDisplayReconfigurationCallBack on macOS.

WDYT?

Copy link
Contributor

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.

Copy link
Contributor Author

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:

  1. Add Display: display-2
  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.

Copy link
Contributor

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.
@iskakaushik
Copy link
Contributor Author

This is superseded by #21355.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants