Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an OS method to retrieve a screen's refresh rate #1284

Closed
Calinou opened this issue Jul 31, 2020 · 8 comments · Fixed by godotengine/godot#57335
Closed

Add an OS method to retrieve a screen's refresh rate #1284

Calinou opened this issue Jul 31, 2020 · 8 comments · Fixed by godotengine/godot#57335

Comments

@Calinou
Copy link
Member

Calinou commented Jul 31, 2020

Related to godotengine/godot#21486, #236 and #1283.

Describe the project you are working on:

The Godot editor 🙂

Describe the problem or limitation you are having in your project:

It is currently impossible to retrieve a screen's refresh rate.

Describe the feature / enhancement and how it helps to overcome the problem or limitation:

A method to get the monitor's refresh rate can be helpful in several ways:

  • The returned value can be used to adjust the physics FPS to match the monitor's refresh rate. This can be used to provide smooth, reactive physics without incurring additional CPU costs and stuttering to those on lower refresh rate displays.
  • The returned value can be used to lock the FPS to the monitor's refresh rate without relying on V-Sync. This can be important when power savings are desired, but the latency added by V-Sync is unacceptable.
    • We can add this to the Project Settings with an additional boolean setting, such as "Force Fps Match Monitor Hz". Alternatively, it can be done by the user in a script in _ready(). Care should be taken about setups that have monitors with different refresh rates.
    • We can use the fastest monitor's refresh rate to adjust the low-processor mode sleep duration in the Godot editor.

With high-refresh rate displays becoming more and more popular (including on mobile devices), providing the best possible experience on such displays is getting more important.

Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:

This feature has to be implemented in an OS-specific manner. It should preferably return a floating-point value in Hz, although returning an integer value in Hz is also acceptable. If the engine fails to retrieve the monitor refresh rate for any reason, it should return 60 as a fallback since this is the most common refresh rate.

I tried to implement this for X11 based on the SDL2 code, but it's easier said than done 🙂

If this enhancement will not be used often, can it be worked around with a few lines of script?:

It might be possible to do this on Linux by calling xrandr, but it's not particularly user-friendly. On other platforms (especially mobile platforms), this may not be possible at all.

Is there a reason why this should be core and not an add-on in the asset library?:

This might be feasible using a GDNative-based add-on. However, since high refresh rate displays will probably be the norm in a few years' time, it's probably better to support this as a core feature.

@aaronfranke
Copy link
Member

Related to GodotVR/godot_openvr_fps#6

@name-here
Copy link

  • The returned value can be used to lock the FPS to the monitor's refresh rate without relying on V-Sync. This can be important when power savings are desired, but the latency added by V-Sync is unacceptable.
    • We can add this to the Project Settings with an additional boolean setting, such as "Force Fps Match Monitor Hz". Alternatively, it can be done by the user in a script in _ready(). Care should be taken about setups that have monitors with different refresh rates.
    • We can use the fastest monitor's refresh rate to adjust the low-processor mode sleep duration in the Godot editor.

Does Vulkan support this? The comments in this issue seem to suggest it doesn't yet provide a way to sync up with the monitor without using V-Sync. (I'm not familiar with the Vulkan API, though, so maybe I'm misinterpreting things?)

Also, we'll need to account for variable refresh rate monitors somehow.

@Calinou
Copy link
Member Author

Calinou commented Dec 11, 2020

Does Vulkan support this? The comments in this issue seem to suggest it doesn't yet provide a way to sync up with the monitor without using V-Sync. (I'm not familiar with the Vulkan API, though, so maybe I'm misinterpreting things?)

In my experience, limiting FPS to $monitor_refresh_rate + 1 often works well enough if you don't mind having some tearing but find the V-Sync latency unacceptable.

Also, we'll need to account for variable refresh rate monitors somehow.

In this case, you need to return the highest supported frequency supported by the VRR monitor. It might be worth checking if SDL has anything specific for this in place.

@NetroScript
Copy link

Hey, I know this is merged already (after all I am coming here from the alpha 2 blog post), but I wonder if it really makes sense to return 60 as a fallback,

After all if you call the function, you want to know the monitor frame rate. If the engine is unable to determine this for some reason, I think it would make more sense to also communicate that (by returning -1 for example).

Then it is left for the user to do what he wants with the returned value (for example on -1, assume 60). If it always returns 60 otherwise, the user cannot know if that truly is the monitor refresh rate, or calling the function "failed".

@Calinou
Copy link
Member Author

Calinou commented Feb 9, 2022

cc @jordigcs

I personally don't mind returning -1.0 as a fallback value, as long as the documentation mentions how to handle this value (typically by treating it as if it was 60.0 in your code).

The check in the documentation should use if is_equal_approx(OS.screen_get_refresh_rate(), -1.0), since floating-point equality can suffer from precision issues.

@jordi-star
Copy link

cc @jordigcs

I personally don't mind returning -1.0 as a fallback value, as long as the documentation mentions how to handle this value (typically by treating it as if it was 60.0 in your code).

I think this would be a better way to handle failure as well. I'll get started on that.

@jordi-star
Copy link

jordi-star commented Feb 10, 2022

Opened at godotengine/godot#57938

@Calinou Calinou modified the milestones: 4.0, 3.x Mar 11, 2022
@Calinou
Copy link
Member Author

Calinou commented Mar 11, 2022

This feature was also implemented in 3.x thanks to godotengine/godot#58812 (will be in 3.5beta2).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
6 participants