Skip to content

Commit

Permalink
Add screen_get_refresh_rate to DisplayServer
Browse files Browse the repository at this point in the history
  • Loading branch information
jordi-star committed Feb 2, 2022
1 parent a743bce commit 5f2dae8
Show file tree
Hide file tree
Showing 19 changed files with 136 additions and 0 deletions.
8 changes: 8 additions & 0 deletions doc/classes/DisplayServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,14 @@
<description>
</description>
</method>
<method name="screen_get_refresh_rate" qualifiers="const">
<return type="float" />
<argument index="0" name="screen" type="int" default="-1" />
<description>
Returns the current refresh rate of the specified screen. If [code]screen[/code] is [code]SCREEN_OF_MAIN_WINDOW[/code] (the default value), a screen with the main window will be used.
[b]Note:[/b] Returns [code]60.0[/code] if the DisplayServer fails to find the refresh rate for the specified screen. On HTML5, [method screen_get_refresh_rate] will always return [code]60.0[/code] as there is no way to retrieve the refresh rate on that platform.
</description>
</method>
<method name="screen_get_scale" qualifiers="const">
<return type="float" />
<argument index="0" name="screen" type="int" default="-1" />
Expand Down
10 changes: 10 additions & 0 deletions platform/android/display_server_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,16 @@ int DisplayServerAndroid::screen_get_dpi(int p_screen) const {
return godot_io_java->get_screen_dpi();
}

float DisplayServerAndroid::screen_get_refresh_rate(int p_screen) const {
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
if (!godot_io_java) {
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
return SCREEN_REFRESH_RATE_FALLBACK;
}

return godot_io_java->get_screen_refresh_rate(SCREEN_REFRESH_RATE_FALLBACK);
}

bool DisplayServerAndroid::screen_is_touchscreen(int p_screen) const {
return true;
}
Expand Down
1 change: 1 addition & 0 deletions platform/android/display_server_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class DisplayServerAndroid : public DisplayServer {
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;

virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,14 @@ public int getScreenDPI() {
return (int)(metrics.density * 160f);
}

public double getScreenRefreshRate(double fallback) {
Display display = activity.getWindowManager().getDefaultDisplay();
if (display != null) {
return display.getRefreshRate();
}
return fallback;
}

public int[] screenGetUsableRect() {
DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
Display display = activity.getWindowManager().getDefaultDisplay();
Expand Down
14 changes: 14 additions & 0 deletions platform/android/java_godot_io_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
_get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;");
_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
_get_screen_refresh_rate = p_env->GetMethodID(cls, "getScreenRefreshRate", "(D)D");
_screen_get_usable_rect = p_env->GetMethodID(cls, "screenGetUsableRect", "()[I"),
_get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;ZIII)V");
Expand Down Expand Up @@ -136,6 +137,19 @@ int GodotIOJavaWrapper::get_screen_dpi() {
}
}

float GodotIOJavaWrapper::get_screen_refresh_rate(float fallback) {
if (_get_screen_refresh_rate) {
JNIEnv *env = get_jni_env();
if (env == nullptr) {
ERR_PRINT("An error occured while trying to get screen refresh rate.");
return fallback;
}
return (float)env->CallDoubleMethod(godot_io_instance, _get_screen_refresh_rate, (double)fallback);
}
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
return fallback;
}

void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) {
if (_screen_get_usable_rect) {
JNIEnv *env = get_jni_env();
Expand Down
2 changes: 2 additions & 0 deletions platform/android/java_godot_io_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class GodotIOJavaWrapper {
jmethodID _get_locale = 0;
jmethodID _get_model = 0;
jmethodID _get_screen_DPI = 0;
jmethodID _get_screen_refresh_rate = 0;
jmethodID _screen_get_usable_rect = 0;
jmethodID _get_unique_id = 0;
jmethodID _show_keyboard = 0;
Expand All @@ -71,6 +72,7 @@ class GodotIOJavaWrapper {
String get_locale();
String get_model();
int get_screen_dpi();
float get_screen_refresh_rate(float fallback);
void screen_get_usable_rect(int (&p_rect_xywh)[4]);
String get_unique_id();
bool has_vk();
Expand Down
1 change: 1 addition & 0 deletions platform/iphone/display_server_iphone.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ class DisplayServerIPhone : public DisplayServer {
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;

virtual Vector<DisplayServer::WindowID> get_window_list() const override;

Expand Down
4 changes: 4 additions & 0 deletions platform/iphone/display_server_iphone.mm
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,10 @@
}
}

float DisplayServerIPhone::screen_get_refresh_rate(int p_screen) const {
return [UIScreen mainScreen].maximumFramesPerSecond;
}

float DisplayServerIPhone::screen_get_scale(int p_screen) const {
return [UIScreen mainScreen].nativeScale;
}
Expand Down
4 changes: 4 additions & 0 deletions platform/javascript/display_server_javascript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,10 @@ float DisplayServerJavaScript::screen_get_scale(int p_screen) const {
return godot_js_display_pixel_ratio_get();
}

float DisplayServerJavaScript::screen_get_refresh_rate(int p_screen) const {
return SCREEN_REFRESH_RATE_FALLBACK; // Javascript doesn't have much of a need for the screen refresh rate, and there's no native way to do so.
}

Vector<DisplayServer::WindowID> DisplayServerJavaScript::get_window_list() const {
Vector<WindowID> ret;
ret.push_back(MAIN_WINDOW_ID);
Expand Down
1 change: 1 addition & 0 deletions platform/javascript/display_server_javascript.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ class DisplayServerJavaScript : public DisplayServer {
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;

virtual void virtual_keyboard_show(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2(), bool p_multiline = false, int p_max_input_length = -1, int p_cursor_start = -1, int p_cursor_end = -1) override;
virtual void virtual_keyboard_hide() override;
Expand Down
24 changes: 24 additions & 0 deletions platform/linuxbsd/display_server_x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,30 @@ int DisplayServerX11::screen_get_dpi(int p_screen) const {
return 96;
}

float DisplayServerX11::screen_get_refresh_rate(int p_screen) const {
_THREAD_SAFE_METHOD_

if (p_screen == SCREEN_OF_MAIN_WINDOW) {
p_screen = window_get_current_screen();
}

//invalid screen?
ERR_FAIL_INDEX_V(p_screen, get_screen_count(), SCREEN_REFRESH_RATE_FALLBACK);

//Use xrandr to get screen refresh rate.
if (xrandr_ext_ok) {
XRRScreenConfiguration *config = XRRGetScreenInfo(x11_display, RootWindow(x11_display, 0));
if (config) {
return (float)XRRConfigCurrentRate(config);
} else {
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
return SCREEN_REFRESH_RATE_FALLBACK;
}
}
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
return SCREEN_REFRESH_RATE_FALLBACK;
}

bool DisplayServerX11::screen_is_touchscreen(int p_screen) const {
_THREAD_SAFE_METHOD_

Expand Down
1 change: 1 addition & 0 deletions platform/linuxbsd/display_server_x11.h
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ class DisplayServerX11 : public DisplayServer {
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;

#if defined(DBUS_ENABLED)
Expand Down
1 change: 1 addition & 0 deletions platform/osx/display_server_osx.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class DisplayServerOSX : public DisplayServer {
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_max_scale() const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;

virtual Vector<int> get_window_list() const override;

Expand Down
18 changes: 18 additions & 0 deletions platform/osx/display_server_osx.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2199,6 +2199,24 @@ static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplay
return Rect2i();
}

float DisplayServerOSX::screen_get_refresh_rate(int p_screen) const {
_THREAD_SAFE_METHOD_

if (p_screen == SCREEN_OF_MAIN_WINDOW) {
p_screen = window_get_current_screen();
}

NSArray *screenArray = [NSScreen screens];
if ((NSUInteger)p_screen < [screenArray count]) {
NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription];
const CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode([[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);
const double displayRefreshRate = CGDisplayModeGetRefreshRate(displayMode);
return (float)displayRefreshRate;
}
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
return SCREEN_REFRESH_RATE_FALLBACK;
}

Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const {
_THREAD_SAFE_METHOD_

Expand Down
33 changes: 33 additions & 0 deletions platform/windows/display_server_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,12 @@ typedef struct {
Rect2i rect;
} EnumRectData;

typedef struct {
int count;
int screen;
float rate;
} EnumRefreshRateData;

static BOOL CALLBACK _MonitorEnumProcSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
EnumSizeData *data = (EnumSizeData *)dwData;
if (data->count == data->screen) {
Expand Down Expand Up @@ -360,6 +366,26 @@ static BOOL CALLBACK _MonitorEnumProcUsableSize(HMONITOR hMonitor, HDC hdcMonito
return TRUE;
}

static BOOL CALLBACK _MonitorEnumProcRefreshRate(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
EnumRefreshRateData *data = (EnumRefreshRateData *)dwData;
if (data->count == data->screen) {
MONITORINFOEXW minfo;
memset(&minfo, 0, sizeof(minfo));
minfo.cbSize = sizeof(minfo);
GetMonitorInfoW(hMonitor, &minfo);

DEVMODEW dm;
memset(&dm, 0, sizeof(dm));
dm.dmSize = sizeof(dm);
EnumDisplaySettingsW(minfo.szDevice, ENUM_CURRENT_SETTINGS, &dm);

data->rate = dm.dmDisplayFrequency;
}

data->count++;
return TRUE;
}

Rect2i DisplayServerWindows::screen_get_usable_rect(int p_screen) const {
_THREAD_SAFE_METHOD_

Expand Down Expand Up @@ -443,6 +469,13 @@ int DisplayServerWindows::screen_get_dpi(int p_screen) const {
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcDpi, (LPARAM)&data);
return data.dpi;
}
float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const {
_THREAD_SAFE_METHOD_

EnumRefreshRateData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, SCREEN_REFRESH_RATE_FALLBACK };
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcRefreshRate, (LPARAM)&data);
return data.rate;
}

bool DisplayServerWindows::screen_is_touchscreen(int p_screen) const {
#ifndef _MSC_VER
Expand Down
1 change: 1 addition & 0 deletions platform/windows/display_server_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ class DisplayServerWindows : public DisplayServer {
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;

virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW) override;
Expand Down
1 change: 1 addition & 0 deletions servers/display_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("screen_get_scale", "screen"), &DisplayServer::screen_get_scale, DEFVAL(SCREEN_OF_MAIN_WINDOW));
ClassDB::bind_method(D_METHOD("screen_is_touchscreen", "screen"), &DisplayServer::screen_is_touchscreen, DEFVAL(SCREEN_OF_MAIN_WINDOW));
ClassDB::bind_method(D_METHOD("screen_get_max_scale"), &DisplayServer::screen_get_max_scale);
ClassDB::bind_method(D_METHOD("screen_get_refresh_rate", "screen"), &DisplayServer::screen_get_refresh_rate, DEFVAL(SCREEN_OF_MAIN_WINDOW));

ClassDB::bind_method(D_METHOD("screen_set_orientation", "orientation", "screen"), &DisplayServer::screen_set_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
ClassDB::bind_method(D_METHOD("screen_get_orientation", "screen"), &DisplayServer::screen_get_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
Expand Down
3 changes: 3 additions & 0 deletions servers/display_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ class DisplayServer : public Object {
SCREEN_OF_MAIN_WINDOW = -1
};

const float SCREEN_REFRESH_RATE_FALLBACK = 60.0; // Returned by screen_get_refresh_rate if the method fails. Most screens are 60hz as of 2022.

virtual int get_screen_count() const = 0;
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
Expand All @@ -188,6 +190,7 @@ class DisplayServer : public Object {
}
return scale;
}
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;

// Keep the ScreenOrientation enum values in sync with the `display/window/handheld/orientation`
Expand Down
1 change: 1 addition & 0 deletions servers/display_server_headless.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ class DisplayServerHeadless : public DisplayServer {
int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 96; /* 0 might cause issues */ }
float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 1; }
float screen_get_max_scale() const override { return 1; }
float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return SCREEN_REFRESH_RATE_FALLBACK; }

Vector<DisplayServer::WindowID> get_window_list() const override { return Vector<DisplayServer::WindowID>(); }

Expand Down

0 comments on commit 5f2dae8

Please sign in to comment.