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 get_screen_refresh_rate() to OS #58812

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/bind/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,10 @@ float _OS::get_screen_max_scale() const {
return OS::get_singleton()->get_screen_max_scale();
}

float _OS::get_screen_refresh_rate(int p_screen) const {
return OS::get_singleton()->get_screen_refresh_rate();
}

Point2 _OS::get_window_position() const {
return OS::get_singleton()->get_window_position();
}
Expand Down Expand Up @@ -1267,6 +1271,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_screen_dpi", "screen"), &_OS::get_screen_dpi, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_screen_scale", "screen"), &_OS::get_screen_scale, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_screen_max_scale"), &_OS::get_screen_max_scale);
ClassDB::bind_method(D_METHOD("get_screen_refresh_rate", "screen"), &_OS::get_screen_refresh_rate, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_window_position"), &_OS::get_window_position);
ClassDB::bind_method(D_METHOD("set_window_position", "position"), &_OS::set_window_position);
ClassDB::bind_method(D_METHOD("get_window_size"), &_OS::get_window_size);
Expand Down
1 change: 1 addition & 0 deletions core/bind/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ class _OS : public Object {
virtual int get_screen_dpi(int p_screen = -1) const;
virtual float get_screen_scale(int p_screen = -1) const;
virtual float get_screen_max_scale() const;
virtual float get_screen_refresh_rate(int p_screen = -1) const;
virtual Point2 get_window_position() const;
virtual void set_window_position(const Point2 &p_position);
virtual Size2 get_max_window_size() const;
Expand Down
4 changes: 4 additions & 0 deletions core/os/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ class OS {
virtual void open_midi_inputs();
virtual void close_midi_inputs();

// Returned by get_screen_refresh_rate if the method fails.
const float SCREEN_REFRESH_RATE_FALLBACK = -1.0;

virtual int get_screen_count() const { return 1; }
virtual int get_current_screen() const { return 0; }
virtual void set_current_screen(int p_screen) {}
Expand All @@ -217,6 +220,7 @@ class OS {
virtual int get_screen_dpi(int p_screen = -1) const { return 72; }
virtual float get_screen_scale(int p_screen = -1) const { return 1.0; }
virtual float get_screen_max_scale() const { return 1.0; };
virtual float get_screen_refresh_rate(int p_screen = -1) const { return SCREEN_REFRESH_RATE_FALLBACK; };
virtual Point2 get_window_position() const { return Vector2(); }
virtual void set_window_position(const Point2 &p_position) {}
virtual Size2 get_max_window_size() const { return Size2(); };
Expand Down
14 changes: 14 additions & 0 deletions doc/classes/OS.xml
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,20 @@
Returns the position of the specified screen by index. If [code]screen[/code] is [code]-1[/code] (the default value), the current screen will be used.
</description>
</method>
<method name="get_screen_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]-1[/code] (the default value), the current screen will be used.
[b]Note:[/b] Returns [code]-1.0[/code] if Godot fails to find the refresh rate for the specified screen. On HTML5, [method get_screen_refresh_rate] will always return [code]-1.0[/code] as there is no way to retrieve the refresh rate on that platform.
To fallback to a default refresh rate if the method fails, try:
[codeblock]
var refresh_rate = OS.get_screen_refresh_rate()
if refresh_rate &lt; 0:
refresh_rate = 60.0
[/codeblock]
</description>
</method>
<method name="get_screen_scale" qualifiers="const">
<return type="float" />
<argument index="0" name="screen" type="int" default="-1" />
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[] getWindowSafeArea() {
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");
Calinou marked this conversation as resolved.
Show resolved Hide resolved
_get_window_safe_area = p_env->GetMethodID(cls, "getWindowSafeArea", "()[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 p_fallback) {
if (_get_screen_refresh_rate) {
JNIEnv *env = get_jni_env();
if (env == nullptr) {
ERR_PRINT("An error occurred while trying to get screen refresh rate.");
return p_fallback;
}
return (float)env->CallDoubleMethod(godot_io_instance, _get_screen_refresh_rate, (double)p_fallback);
}
ERR_PRINT("An error occurred while trying to get the screen refresh rate.");
return p_fallback;
}

void GodotIOJavaWrapper::get_window_safe_area(int (&p_rect_xywh)[4]) {
if (_get_window_safe_area) {
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 _get_window_safe_area = 0;
jmethodID _get_unique_id = 0;
jmethodID _show_keyboard = 0;
Expand All @@ -72,6 +73,7 @@ class GodotIOJavaWrapper {
String get_model();
int get_screen_dpi();
void get_window_safe_area(int (&p_rect_xywh)[4]);
float get_screen_refresh_rate(float p_fallback);
String get_unique_id();
bool has_vk();
void show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end);
Expand Down
4 changes: 4 additions & 0 deletions platform/android/os_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,10 @@ int OS_Android::get_screen_dpi(int p_screen) const {
return godot_io_java->get_screen_dpi();
}

float OS_Android::get_screen_refresh_rate(int p_screen) const {
return godot_io_java->get_screen_refresh_rate(OS::get_singleton()->SCREEN_REFRESH_RATE_FALLBACK);
}

String OS_Android::get_data_path() const {
return get_user_data_dir();
}
Expand Down
1 change: 1 addition & 0 deletions platform/android/os_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ class OS_Android : public OS_Unix {
virtual bool has_clipboard() const;
virtual String get_model_name() const;
virtual int get_screen_dpi(int p_screen = 0) const;
virtual float get_screen_refresh_rate(int p_screen = 0) const;

virtual bool get_window_per_pixel_transparency_enabled() const { return transparency_enabled; }
virtual void set_window_per_pixel_transparency_enabled(bool p_enabled) { ERR_FAIL_MSG("Setting per-pixel transparency is not supported at runtime, please set it in project settings instead."); }
Expand Down
1 change: 1 addition & 0 deletions platform/iphone/os_iphone.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class OSIPhone : public OS_Unix {
virtual bool _check_internal_feature_support(const String &p_feature);

virtual int get_screen_dpi(int p_screen = -1) const;
virtual float get_screen_refresh_rate(int p_screen = -1) const;

void pencil_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick);
void touch_press(int p_idx, int p_x, int p_y, bool p_pressed, bool p_doubleclick);
Expand Down
4 changes: 4 additions & 0 deletions platform/iphone/os_iphone.mm
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,10 @@ void register_dynamic_symbol(char *name, void *address) {
}
}

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

Rect2 OSIPhone::get_window_safe_area() const {
if (@available(iOS 11, *)) {
UIEdgeInsets insets = UIEdgeInsetsZero;
Expand Down
1 change: 1 addition & 0 deletions platform/osx/os_osx.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ class OS_OSX : public OS_Unix {
virtual int get_screen_dpi(int p_screen = -1) const;
virtual float get_screen_scale(int p_screen = -1) const;
virtual float get_screen_max_scale() const;
virtual float get_screen_refresh_rate(int p_screen = -1) const;

virtual Point2 get_window_position() const;
virtual void set_window_position(const Point2 &p_position);
Expand Down
16 changes: 16 additions & 0 deletions platform/osx/os_osx.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2564,6 +2564,22 @@ static int get_screen_index(NSScreen *screen) {
return 72;
}

float OS_OSX::get_screen_refresh_rate(int p_screen) const {
if (p_screen < 0) {
p_screen = 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 occurred while trying to get the screen refresh rate.");
return OS::get_singleton()->SCREEN_REFRESH_RATE_FALLBACK;
}

Size2 OS_OSX::get_screen_size(int p_screen) const {
if (p_screen < 0) {
p_screen = get_current_screen();
Expand Down
42 changes: 41 additions & 1 deletion platform/windows/os_windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,12 @@ typedef struct {
int dpi;
} EnumDpiData;

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

static BOOL CALLBACK _MonitorEnumProcDpi(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
EnumDpiData *data = (EnumDpiData *)dwData;
if (data->count == data->screen) {
Expand All @@ -1964,12 +1970,46 @@ static BOOL CALLBACK _MonitorEnumProcDpi(HMONITOR hMonitor, HDC hdcMonitor, LPRE
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;
}

int OS_Windows::get_screen_dpi(int p_screen) const {
EnumDpiData data = { 0, p_screen == -1 ? get_current_screen() : p_screen, 72 };
EnumDpiData data = {
0,
p_screen == -1 ? get_current_screen() : p_screen,
72,
};
EnumDisplayMonitors(NULL, NULL, _MonitorEnumProcDpi, (LPARAM)&data);
return data.dpi;
}

float OS_Windows::get_screen_refresh_rate(int p_screen) const {
EnumRefreshRateData data = {
0,
p_screen == -1 ? get_current_screen() : p_screen,
OS::get_singleton()->SCREEN_REFRESH_RATE_FALLBACK,
};
EnumDisplayMonitors(nullptr, nullptr, _MonitorEnumProcRefreshRate, (LPARAM)&data);
return data.rate;
}

Point2 OS_Windows::get_window_position() const {
if (minimized) {
return last_pos;
Expand Down
1 change: 1 addition & 0 deletions platform/windows/os_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,7 @@ class OS_Windows : public OS {
virtual Point2 get_screen_position(int p_screen = -1) const;
virtual Size2 get_screen_size(int p_screen = -1) const;
virtual int get_screen_dpi(int p_screen = -1) const;
virtual float get_screen_refresh_rate(int p_screen = -1) const;

virtual Point2 get_window_position() const;
virtual void set_window_position(const Point2 &p_position);
Expand Down
59 changes: 59 additions & 0 deletions platform/x11/os_x11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,65 @@ int OS_X11::get_screen_dpi(int p_screen) const {
return 96;
}

float OS_X11::get_screen_refresh_rate(int p_screen) const {
if (p_screen == -1) {
p_screen = get_current_screen();
}

//invalid screen?
ERR_FAIL_INDEX_V(p_screen, get_screen_count(), OS::get_singleton()->SCREEN_REFRESH_RATE_FALLBACK);

//Use xrandr to get screen refresh rate.
if (xrandr_ext_ok) {
XRRScreenResources *screen_info = XRRGetScreenResources(x11_display, x11_window);
if (screen_info) {
RRMode current_mode = 0;
xrr_monitor_info *monitors = nullptr;

if (xrr_get_monitors) {
int count = 0;
monitors = xrr_get_monitors(x11_display, x11_window, true, &count);
ERR_FAIL_INDEX_V(p_screen, count, OS::get_singleton()->SCREEN_REFRESH_RATE_FALLBACK);
} else {
ERR_PRINT("An error occurred while trying to get the screen refresh rate.");
return OS::get_singleton()->SCREEN_REFRESH_RATE_FALLBACK;
}

bool found_active_mode = false;
for (int crtc = 0; crtc < screen_info->ncrtc; crtc++) { // Loop through outputs to find which one is currently outputting.
XRRCrtcInfo *monitor_info = XRRGetCrtcInfo(x11_display, screen_info, screen_info->crtcs[crtc]);
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.
continue;
}

if (monitor_info->mode != None) {
current_mode = monitor_info->mode;
found_active_mode = true;
break;
}
}

if (found_active_mode) {
for (int mode = 0; mode < screen_info->nmode; mode++) {
XRRModeInfo m_info = screen_info->modes[mode];
if (m_info.id == current_mode) {
// Snap to nearest 0.01 to stay consistent with other platforms.
return Math::stepify((float)m_info.dotClock / ((float)m_info.hTotal * (float)m_info.vTotal), 0.01);
}
}
}

ERR_PRINT("An error occurred while trying to get the screen refresh rate."); // We should have returned the refresh rate by now. An error must have occurred.
return OS::get_singleton()->SCREEN_REFRESH_RATE_FALLBACK;
} else {
ERR_PRINT("An error occurred while trying to get the screen refresh rate.");
return OS::get_singleton()->SCREEN_REFRESH_RATE_FALLBACK;
}
}
ERR_PRINT("An error occurred while trying to get the screen refresh rate.");
return OS::get_singleton()->SCREEN_REFRESH_RATE_FALLBACK;
}

Point2 OS_X11::get_window_position() const {
int x, y;
Window child;
Expand Down
1 change: 1 addition & 0 deletions platform/x11/os_x11.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ class OS_X11 : public OS_Unix {
virtual Point2 get_screen_position(int p_screen = -1) const;
virtual Size2 get_screen_size(int p_screen = -1) const;
virtual int get_screen_dpi(int p_screen = -1) const;
virtual float get_screen_refresh_rate(int p_screen = -1) const;
virtual Point2 get_window_position() const;
virtual void set_window_position(const Point2 &p_position);
virtual Size2 get_window_size() const;
Expand Down