Skip to content
This repository was archived by the owner on Sep 3, 2022. It is now read-only.

Commit 54dec44

Browse files
committed
Add screen_get_refresh_rate to DisplayServer
1 parent 203e261 commit 54dec44

19 files changed

+172
-0
lines changed

doc/classes/DisplayServer.xml

+8
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,14 @@
399399
<description>
400400
</description>
401401
</method>
402+
<method name="screen_get_refresh_rate" qualifiers="const">
403+
<return type="float" />
404+
<argument index="0" name="screen" type="int" default="-1" />
405+
<description>
406+
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.
407+
[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.
408+
</description>
409+
</method>
402410
<method name="screen_get_scale" qualifiers="const">
403411
<return type="float" />
404412
<argument index="0" name="screen" type="int" default="-1" />

platform/android/display_server_android.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,16 @@ int DisplayServerAndroid::screen_get_dpi(int p_screen) const {
161161
return godot_io_java->get_screen_dpi();
162162
}
163163

164+
float DisplayServerAndroid::screen_get_refresh_rate(int p_screen) const {
165+
GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
166+
if (!godot_io_java) {
167+
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
168+
return SCREEN_REFRESH_RATE_FALLBACK;
169+
}
170+
171+
return godot_io_java->get_screen_refresh_rate(SCREEN_REFRESH_RATE_FALLBACK);
172+
}
173+
164174
bool DisplayServerAndroid::screen_is_touchscreen(int p_screen) const {
165175
return true;
166176
}

platform/android/display_server_android.h

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class DisplayServerAndroid : public DisplayServer {
106106
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
107107
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
108108
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
109+
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
109110
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
110111

111112
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;

platform/android/java/lib/src/org/godotengine/godot/GodotIO.java

+8
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,14 @@ public int getScreenDPI() {
226226
return (int)(metrics.density * 160f);
227227
}
228228

229+
public double getScreenRefreshRate(double fallback) {
230+
Display display = activity.getWindowManager().getDefaultDisplay();
231+
if (display != null) {
232+
return display.getRefreshRate();
233+
}
234+
return fallback;
235+
}
236+
229237
public int[] screenGetUsableRect() {
230238
DisplayMetrics metrics = activity.getResources().getDisplayMetrics();
231239
Display display = activity.getWindowManager().getDefaultDisplay();

platform/android/java_godot_io_wrapper.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
5353
_get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;");
5454
_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
5555
_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
56+
_get_screen_refresh_rate = p_env->GetMethodID(cls, "getScreenRefreshRate", "(D)D");
5657
_screen_get_usable_rect = p_env->GetMethodID(cls, "screenGetUsableRect", "()[I"),
5758
_get_unique_id = p_env->GetMethodID(cls, "getUniqueID", "()Ljava/lang/String;");
5859
_show_keyboard = p_env->GetMethodID(cls, "showKeyboard", "(Ljava/lang/String;ZIII)V");
@@ -136,6 +137,19 @@ int GodotIOJavaWrapper::get_screen_dpi() {
136137
}
137138
}
138139

140+
float GodotIOJavaWrapper::get_screen_refresh_rate(float fallback) {
141+
if (_get_screen_refresh_rate) {
142+
JNIEnv *env = get_jni_env();
143+
if (env == nullptr) {
144+
ERR_PRINT("An error occured while trying to get screen refresh rate.");
145+
return fallback;
146+
}
147+
return (float)env->CallDoubleMethod(godot_io_instance, _get_screen_refresh_rate, (double)fallback);
148+
}
149+
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
150+
return fallback;
151+
}
152+
139153
void GodotIOJavaWrapper::screen_get_usable_rect(int (&p_rect_xywh)[4]) {
140154
if (_screen_get_usable_rect) {
141155
JNIEnv *env = get_jni_env();

platform/android/java_godot_io_wrapper.h

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class GodotIOJavaWrapper {
5151
jmethodID _get_locale = 0;
5252
jmethodID _get_model = 0;
5353
jmethodID _get_screen_DPI = 0;
54+
jmethodID _get_screen_refresh_rate = 0;
5455
jmethodID _screen_get_usable_rect = 0;
5556
jmethodID _get_unique_id = 0;
5657
jmethodID _show_keyboard = 0;
@@ -71,6 +72,7 @@ class GodotIOJavaWrapper {
7172
String get_locale();
7273
String get_model();
7374
int get_screen_dpi();
75+
float get_screen_refresh_rate(float fallback);
7476
void screen_get_usable_rect(int (&p_rect_xywh)[4]);
7577
String get_unique_id();
7678
bool has_vk();

platform/iphone/display_server_iphone.h

+1
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class DisplayServerIPhone : public DisplayServer {
129129
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
130130
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
131131
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
132+
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
132133

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

platform/iphone/display_server_iphone.mm

+4
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,10 @@
393393
}
394394
}
395395

396+
float DisplayServerIPhone::screen_get_refresh_rate(int p_screen) const {
397+
return [UIScreen mainScreen].maximumFramesPerSecond;
398+
}
399+
396400
float DisplayServerIPhone::screen_get_scale(int p_screen) const {
397401
return [UIScreen mainScreen].nativeScale;
398402
}

platform/javascript/display_server_javascript.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,10 @@ float DisplayServerJavaScript::screen_get_scale(int p_screen) const {
794794
return godot_js_display_pixel_ratio_get();
795795
}
796796

797+
float DisplayServerJavaScript::screen_get_refresh_rate(int p_screen) const {
798+
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.
799+
}
800+
797801
Vector<DisplayServer::WindowID> DisplayServerJavaScript::get_window_list() const {
798802
Vector<WindowID> ret;
799803
ret.push_back(MAIN_WINDOW_ID);

platform/javascript/display_server_javascript.h

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ class DisplayServerJavaScript : public DisplayServer {
139139
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
140140
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
141141
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
142+
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
142143

143144
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;
144145
virtual void virtual_keyboard_hide() override;

platform/linuxbsd/display_server_x11.cpp

+60
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,66 @@ int DisplayServerX11::screen_get_dpi(int p_screen) const {
10521052
return 96;
10531053
}
10541054

1055+
float DisplayServerX11::screen_get_refresh_rate(int p_screen) const {
1056+
_THREAD_SAFE_METHOD_
1057+
1058+
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
1059+
p_screen = window_get_current_screen();
1060+
}
1061+
1062+
//invalid screen?
1063+
ERR_FAIL_INDEX_V(p_screen, get_screen_count(), SCREEN_REFRESH_RATE_FALLBACK);
1064+
1065+
//Use xrandr to get screen refresh rate.
1066+
if (xrandr_ext_ok) {
1067+
XRRScreenResources *screen_info = XRRGetScreenResources(x11_display, windows[MAIN_WINDOW_ID].x11_window);
1068+
if (screen_info) {
1069+
RRMode current_mode = 0;
1070+
xrr_monitor_info *monitors = nullptr;
1071+
1072+
if (xrr_get_monitors) {
1073+
int count = 0;
1074+
monitors = xrr_get_monitors(x11_display, windows[MAIN_WINDOW_ID].x11_window, true, &count);
1075+
ERR_FAIL_INDEX_V(p_screen, count, SCREEN_REFRESH_RATE_FALLBACK);
1076+
} else {
1077+
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
1078+
return SCREEN_REFRESH_RATE_FALLBACK;
1079+
}
1080+
1081+
bool found_active_mode = false;
1082+
for (int crtc = 0; crtc < screen_info->ncrtc; crtc++) { // Loop through outputs to find which one is currently outputting.
1083+
XRRCrtcInfo *monitor_info = XRRGetCrtcInfo(x11_display, screen_info, screen_info->crtcs[crtc]);
1084+
if (monitor_info->x != monitors[p_screen].x || monitor_info->y != monitors[p_screen].y) { // If X and Y aren't the same as the monitor we're looking for, this isn't the right monitor. Continue.
1085+
continue;
1086+
}
1087+
1088+
if (monitor_info->mode != None) {
1089+
current_mode = monitor_info->mode;
1090+
found_active_mode = true;
1091+
break;
1092+
}
1093+
}
1094+
1095+
if (found_active_mode) {
1096+
for (int mode = 0; mode < screen_info->nmode; mode++) {
1097+
XRRModeInfo m_info = screen_info->modes[mode];
1098+
if (m_info.id == current_mode) {
1099+
return (float)m_info.dotClock / ((float)m_info.hTotal * (float)m_info.vTotal);
1100+
}
1101+
}
1102+
}
1103+
1104+
ERR_PRINT("An error occured while trying to get the screen refresh rate."); // We should have returned the refresh rate by now. An error must have occured.
1105+
return SCREEN_REFRESH_RATE_FALLBACK;
1106+
} else {
1107+
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
1108+
return SCREEN_REFRESH_RATE_FALLBACK;
1109+
}
1110+
}
1111+
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
1112+
return SCREEN_REFRESH_RATE_FALLBACK;
1113+
}
1114+
10551115
bool DisplayServerX11::screen_is_touchscreen(int p_screen) const {
10561116
_THREAD_SAFE_METHOD_
10571117

platform/linuxbsd/display_server_x11.h

+1
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ class DisplayServerX11 : public DisplayServer {
301301
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
302302
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
303303
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
304+
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
304305
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
305306

306307
#if defined(DBUS_ENABLED)

platform/osx/display_server_osx.h

+1
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ class DisplayServerOSX : public DisplayServer {
228228
virtual float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
229229
virtual float screen_get_max_scale() const override;
230230
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
231+
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
231232

232233
virtual Vector<int> get_window_list() const override;
233234

platform/osx/display_server_osx.mm

+18
Original file line numberDiff line numberDiff line change
@@ -2199,6 +2199,24 @@ static void displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplay
21992199
return Rect2i();
22002200
}
22012201

2202+
float DisplayServerOSX::screen_get_refresh_rate(int p_screen) const {
2203+
_THREAD_SAFE_METHOD_
2204+
2205+
if (p_screen == SCREEN_OF_MAIN_WINDOW) {
2206+
p_screen = window_get_current_screen();
2207+
}
2208+
2209+
NSArray *screenArray = [NSScreen screens];
2210+
if ((NSUInteger)p_screen < [screenArray count]) {
2211+
NSDictionary *description = [[screenArray objectAtIndex:p_screen] deviceDescription];
2212+
const CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode([[description objectForKey:@"NSScreenNumber"] unsignedIntValue]);
2213+
const double displayRefreshRate = CGDisplayModeGetRefreshRate(displayMode);
2214+
return (float)displayRefreshRate;
2215+
}
2216+
ERR_PRINT("An error occured while trying to get the screen refresh rate.");
2217+
return SCREEN_REFRESH_RATE_FALLBACK;
2218+
}
2219+
22022220
Vector<DisplayServer::WindowID> DisplayServerOSX::get_window_list() const {
22032221
_THREAD_SAFE_METHOD_
22042222

platform/windows/display_server_windows.cpp

+33
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,12 @@ typedef struct {
323323
Rect2i rect;
324324
} EnumRectData;
325325

326+
typedef struct {
327+
int count;
328+
int screen;
329+
float rate;
330+
} EnumRefreshRateData;
331+
326332
static BOOL CALLBACK _MonitorEnumProcSize(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
327333
EnumSizeData *data = (EnumSizeData *)dwData;
328334
if (data->count == data->screen) {
@@ -360,6 +366,26 @@ static BOOL CALLBACK _MonitorEnumProcUsableSize(HMONITOR hMonitor, HDC hdcMonito
360366
return TRUE;
361367
}
362368

369+
static BOOL CALLBACK _MonitorEnumProcRefreshRate(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
370+
EnumRefreshRateData *data = (EnumRefreshRateData *)dwData;
371+
if (data->count == data->screen) {
372+
MONITORINFOEXW minfo;
373+
memset(&minfo, 0, sizeof(minfo));
374+
minfo.cbSize = sizeof(minfo);
375+
GetMonitorInfoW(hMonitor, &minfo);
376+
377+
DEVMODEW dm;
378+
memset(&dm, 0, sizeof(dm));
379+
dm.dmSize = sizeof(dm);
380+
EnumDisplaySettingsW(minfo.szDevice, ENUM_CURRENT_SETTINGS, &dm);
381+
382+
data->rate = dm.dmDisplayFrequency;
383+
}
384+
385+
data->count++;
386+
return TRUE;
387+
}
388+
363389
Rect2i DisplayServerWindows::screen_get_usable_rect(int p_screen) const {
364390
_THREAD_SAFE_METHOD_
365391

@@ -443,6 +469,13 @@ int DisplayServerWindows::screen_get_dpi(int p_screen) const {
443469
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcDpi, (LPARAM)&data);
444470
return data.dpi;
445471
}
472+
float DisplayServerWindows::screen_get_refresh_rate(int p_screen) const {
473+
_THREAD_SAFE_METHOD_
474+
475+
EnumRefreshRateData data = { 0, p_screen == SCREEN_OF_MAIN_WINDOW ? window_get_current_screen() : p_screen, SCREEN_REFRESH_RATE_FALLBACK };
476+
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcRefreshRate, (LPARAM)&data);
477+
return data.rate;
478+
}
446479

447480
bool DisplayServerWindows::screen_is_touchscreen(int p_screen) const {
448481
#ifndef _MSC_VER

platform/windows/display_server_windows.h

+1
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ class DisplayServerWindows : public DisplayServer {
458458
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
459459
virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
460460
virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
461+
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
461462
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
462463

463464
virtual void screen_set_orientation(ScreenOrientation p_orientation, int p_screen = SCREEN_OF_MAIN_WINDOW) override;

servers/display_server.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ void DisplayServer::_bind_methods() {
375375
ClassDB::bind_method(D_METHOD("screen_get_scale", "screen"), &DisplayServer::screen_get_scale, DEFVAL(SCREEN_OF_MAIN_WINDOW));
376376
ClassDB::bind_method(D_METHOD("screen_is_touchscreen", "screen"), &DisplayServer::screen_is_touchscreen, DEFVAL(SCREEN_OF_MAIN_WINDOW));
377377
ClassDB::bind_method(D_METHOD("screen_get_max_scale"), &DisplayServer::screen_get_max_scale);
378+
ClassDB::bind_method(D_METHOD("screen_get_refresh_rate", "screen"), &DisplayServer::screen_get_refresh_rate, DEFVAL(SCREEN_OF_MAIN_WINDOW));
378379

379380
ClassDB::bind_method(D_METHOD("screen_set_orientation", "orientation", "screen"), &DisplayServer::screen_set_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));
380381
ClassDB::bind_method(D_METHOD("screen_get_orientation", "screen"), &DisplayServer::screen_get_orientation, DEFVAL(SCREEN_OF_MAIN_WINDOW));

servers/display_server.h

+3
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ class DisplayServer : public Object {
168168
SCREEN_OF_MAIN_WINDOW = -1
169169
};
170170

171+
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.
172+
171173
virtual int get_screen_count() const = 0;
172174
virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
173175
virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
@@ -182,6 +184,7 @@ class DisplayServer : public Object {
182184
}
183185
return scale;
184186
}
187+
virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const = 0;
185188
virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
186189

187190
// Keep the ScreenOrientation enum values in sync with the `display/window/handheld/orientation`

servers/display_server_headless.h

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class DisplayServerHeadless : public DisplayServer {
6262
int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 96; /* 0 might cause issues */ }
6363
float screen_get_scale(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return 1; }
6464
float screen_get_max_scale() const override { return 1; }
65+
float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override { return SCREEN_REFRESH_RATE_FALLBACK; }
6566

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

0 commit comments

Comments
 (0)