From 1b6e3458b24836c362ac245ddeec627207dd2981 Mon Sep 17 00:00:00 2001 From: Fabio Alessandrelli Date: Mon, 29 Jun 2020 20:46:21 +0200 Subject: [PATCH] Move frame delaying functions from Main to OS. Will allow specific platforms to override it and avoid blocking on the main/GUI thread. --- core/os/os.cpp | 36 ++++++++++++++++++++++++++++++++++++ core/os/os.h | 3 +++ main/main.cpp | 34 +--------------------------------- main/main.h | 1 - 4 files changed, 40 insertions(+), 34 deletions(-) diff --git a/core/os/os.cpp b/core/os/os.cpp index c842be333c3..231069fcfb9 100644 --- a/core/os/os.cpp +++ b/core/os/os.cpp @@ -41,6 +41,7 @@ #include OS *OS::singleton = nullptr; +uint64_t OS::target_ticks = 0; OS *OS::get_singleton() { return singleton; @@ -468,6 +469,41 @@ void OS::close_midi_inputs() { } } +void OS::add_frame_delay(bool p_can_draw) { + const uint32_t frame_delay = Engine::get_singleton()->get_frame_delay(); + if (frame_delay) { + // Add fixed frame delay to decrease CPU/GPU usage. This doesn't take + // the actual frame time into account. + // Due to the high fluctuation of the actual sleep duration, it's not recommended + // to use this as a FPS limiter. + delay_usec(frame_delay * 1000); + } + + // Add a dynamic frame delay to decrease CPU/GPU usage. This takes the + // previous frame time into account for a smoother result. + uint64_t dynamic_delay = 0; + if (is_in_low_processor_usage_mode() || !p_can_draw) { + dynamic_delay = get_low_processor_usage_mode_sleep_usec(); + } + const int target_fps = Engine::get_singleton()->get_target_fps(); + if (target_fps > 0 && !Engine::get_singleton()->is_editor_hint()) { + // Override the low processor usage mode sleep delay if the target FPS is lower. + dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / target_fps)); + } + + if (dynamic_delay > 0) { + target_ticks += dynamic_delay; + uint64_t current_ticks = get_ticks_usec(); + + if (current_ticks < target_ticks) { + delay_usec(target_ticks - current_ticks); + } + + current_ticks = get_ticks_usec(); + target_ticks = MIN(MAX(target_ticks, current_ticks - dynamic_delay), current_ticks + dynamic_delay); + } +} + OS::OS() { void *volatile stack_bottom; diff --git a/core/os/os.h b/core/os/os.h index 04e10518dc2..f21c0d4df75 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -43,6 +43,7 @@ class OS { static OS *singleton; + static uint64_t target_ticks; String _execpath; List _cmdline; bool _keep_screen_on = true; // set default value to true, because this had been true before godot 2.0. @@ -212,6 +213,8 @@ public: virtual double get_unix_time() const; virtual void delay_usec(uint32_t p_usec) const = 0; + virtual void add_frame_delay(bool p_can_draw); + virtual uint64_t get_ticks_usec() const = 0; uint32_t get_ticks_msec() const; uint64_t get_splash_tick_msec() const; diff --git a/main/main.cpp b/main/main.cpp index 00760b39b0d..0cccccdab39 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -2115,7 +2115,6 @@ bool Main::start() { */ uint64_t Main::last_ticks = 0; -uint64_t Main::target_ticks = 0; uint32_t Main::frames = 0; uint32_t Main::frame = 0; bool Main::force_redraw_requested = false; @@ -2266,38 +2265,7 @@ bool Main::iteration() { return exit; } - const uint32_t frame_delay = Engine::get_singleton()->get_frame_delay(); - if (frame_delay) { - // Add fixed frame delay to decrease CPU/GPU usage. This doesn't take - // the actual frame time into account. - // Due to the high fluctuation of the actual sleep duration, it's not recommended - // to use this as a FPS limiter. - OS::get_singleton()->delay_usec(frame_delay * 1000); - } - - // Add a dynamic frame delay to decrease CPU/GPU usage. This takes the - // previous frame time into account for a smoother result. - uint64_t dynamic_delay = 0; - if (OS::get_singleton()->is_in_low_processor_usage_mode() || !DisplayServer::get_singleton()->window_can_draw()) { - dynamic_delay = OS::get_singleton()->get_low_processor_usage_mode_sleep_usec(); - } - const int target_fps = Engine::get_singleton()->get_target_fps(); - if (target_fps > 0 && !Engine::get_singleton()->is_editor_hint()) { - // Override the low processor usage mode sleep delay if the target FPS is lower. - dynamic_delay = MAX(dynamic_delay, (uint64_t)(1000000 / target_fps)); - } - - if (dynamic_delay > 0) { - target_ticks += dynamic_delay; - uint64_t current_ticks = OS::get_singleton()->get_ticks_usec(); - - if (current_ticks < target_ticks) { - OS::get_singleton()->delay_usec(target_ticks - current_ticks); - } - - current_ticks = OS::get_singleton()->get_ticks_usec(); - target_ticks = MIN(MAX(target_ticks, current_ticks - dynamic_delay), current_ticks + dynamic_delay); - } + OS::get_singleton()->add_frame_delay(DisplayServer::get_singleton()->window_can_draw()); #ifdef TOOLS_ENABLED if (auto_build_solutions) { diff --git a/main/main.h b/main/main.h index ab6917a65cd..308128735cd 100644 --- a/main/main.h +++ b/main/main.h @@ -38,7 +38,6 @@ class Main { static void print_help(const char *p_binary); static uint64_t last_ticks; - static uint64_t target_ticks; static uint32_t frames; static uint32_t frame; static bool force_redraw_requested;