summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatric Stout <truebrain@openttd.org>2021-02-17 15:14:59 +0100
committerPatric Stout <github@truebrain.nl>2021-02-19 10:43:15 +0100
commitae7a2b9f02b4becdcc7cb96f79031c840198989f (patch)
tree34e9bf7ff63f932421a28449efe28fea95e62467
parentc81c6e5eb7a0e991039b7662868e87a8d2fe3415 (diff)
downloadopenttd-ae7a2b9f02b4becdcc7cb96f79031c840198989f.tar.xz
Change: allow video-drivers to miss deadlines slightly
Before, every next frame was calculated from the current time. If for some reason the current frame was drifting a bit, the next would too, and the next more, etc etc. This meant we rarely hit the targets we would like, like 33.33fps. Instead, allow video-drivers to drift slightly, and schedule the next frame based on the time the last should have happened. Only if the drift gets too much, that deadlines are missed for longer period of times, schedule the next frame based on the current time. This makes the FPS a lot smoother, as sleeps aren't as exact as you might think.
-rw-r--r--src/video/allegro_v.cpp12
-rw-r--r--src/video/cocoa/cocoa_v.mm12
-rw-r--r--src/video/dedicated_v.cpp12
-rw-r--r--src/video/sdl2_v.cpp12
-rw-r--r--src/video/sdl_v.cpp12
-rw-r--r--src/video/video_driver.hpp2
-rw-r--r--src/video/win32_v.cpp12
7 files changed, 61 insertions, 13 deletions
diff --git a/src/video/allegro_v.cpp b/src/video/allegro_v.cpp
index 7a51415c7..de329db9e 100644
--- a/src/video/allegro_v.cpp
+++ b/src/video/allegro_v.cpp
@@ -484,13 +484,21 @@ void VideoDriver_Allegro::MainLoop()
}
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) {
- next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ if (_fast_forward && !_pause_mode) {
+ next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ } else {
+ next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_game_tick getting behind more and more if it cannot keep up. */
+ if (next_game_tick < cur_ticks - std::chrono::milliseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_game_tick = cur_ticks;
+ }
GameLoop();
}
if (cur_ticks >= next_draw_tick) {
- next_draw_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
+ if (next_draw_tick < cur_ticks - std::chrono::microseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_draw_tick = cur_ticks;
bool old_ctrl_pressed = _ctrl_pressed;
diff --git a/src/video/cocoa/cocoa_v.mm b/src/video/cocoa/cocoa_v.mm
index d065630b7..20f3904ae 100644
--- a/src/video/cocoa/cocoa_v.mm
+++ b/src/video/cocoa/cocoa_v.mm
@@ -674,13 +674,21 @@ void VideoDriver_Cocoa::GameLoop()
}
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) {
- next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ if (_fast_forward && !_pause_mode) {
+ next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ } else {
+ next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_game_tick getting behind more and more if it cannot keep up. */
+ if (next_game_tick < cur_ticks - std::chrono::milliseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_game_tick = cur_ticks;
+ }
::GameLoop();
}
if (cur_ticks >= next_draw_tick) {
- next_draw_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
+ if (next_draw_tick < cur_ticks - std::chrono::microseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_draw_tick = cur_ticks;
bool old_ctrl_pressed = _ctrl_pressed;
diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp
index 057c0daa8..7b1abbadd 100644
--- a/src/video/dedicated_v.cpp
+++ b/src/video/dedicated_v.cpp
@@ -238,7 +238,7 @@ void VideoDriver_Dedicated::MainLoop()
{
auto cur_ticks = std::chrono::steady_clock::now();
auto last_realtime_tick = cur_ticks;
- auto next_tick = cur_ticks;
+ auto next_game_tick = cur_ticks;
/* Signal handlers */
#if defined(UNIX)
@@ -292,8 +292,14 @@ void VideoDriver_Dedicated::MainLoop()
last_realtime_tick += delta;
}
- if (cur_ticks >= next_tick || _ddc_fastforward) {
- next_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ if (cur_ticks >= next_game_tick || _ddc_fastforward) {
+ if (_ddc_fastforward) {
+ next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ } else {
+ next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_game_tick getting behind more and more if it cannot keep up. */
+ if (next_game_tick < cur_ticks - std::chrono::milliseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_game_tick = cur_ticks;
+ }
GameLoop();
InputLoop();
diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp
index 157ffcd64..a8d8fc3e1 100644
--- a/src/video/sdl2_v.cpp
+++ b/src/video/sdl2_v.cpp
@@ -777,7 +777,13 @@ void VideoDriver_SDL::LoopOnce()
}
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) {
- next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ if (_fast_forward && !_pause_mode) {
+ next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ } else {
+ next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_game_tick getting behind more and more if it cannot keep up. */
+ if (next_game_tick < cur_ticks - std::chrono::milliseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_game_tick = cur_ticks;
+ }
/* The gameloop is the part that can run asynchronously. The rest
* except sleeping can't. */
@@ -787,7 +793,9 @@ void VideoDriver_SDL::LoopOnce()
}
if (cur_ticks >= next_draw_tick) {
- next_draw_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
+ if (next_draw_tick < cur_ticks - std::chrono::microseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_draw_tick = cur_ticks;
bool old_ctrl_pressed = _ctrl_pressed;
diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp
index 1c88dfbcd..11da9c5a3 100644
--- a/src/video/sdl_v.cpp
+++ b/src/video/sdl_v.cpp
@@ -730,7 +730,13 @@ void VideoDriver_SDL::MainLoop()
}
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) {
- next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ if (_fast_forward && !_pause_mode) {
+ next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ } else {
+ next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_game_tick getting behind more and more if it cannot keep up. */
+ if (next_game_tick < cur_ticks - std::chrono::milliseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_game_tick = cur_ticks;
+ }
/* The gameloop is the part that can run asynchronously. The rest
* except sleeping can't. */
@@ -740,7 +746,9 @@ void VideoDriver_SDL::MainLoop()
}
if (cur_ticks >= next_draw_tick) {
- next_draw_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
+ if (next_draw_tick < cur_ticks - std::chrono::microseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_draw_tick = cur_ticks;
bool old_ctrl_pressed = _ctrl_pressed;
diff --git a/src/video/video_driver.hpp b/src/video/video_driver.hpp
index bc445d92d..94803db22 100644
--- a/src/video/video_driver.hpp
+++ b/src/video/video_driver.hpp
@@ -126,6 +126,8 @@ public:
}
protected:
+ const uint ALLOWED_DRIFT = 5; ///< How many times videodriver can miss deadlines without it being overly compensated.
+
/**
* Get the resolution of the main screen.
*/
diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp
index 8a80344c4..2fe5f67f0 100644
--- a/src/video/win32_v.cpp
+++ b/src/video/win32_v.cpp
@@ -1207,7 +1207,13 @@ void VideoDriver_Win32::MainLoop()
}
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) {
- next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ if (_fast_forward && !_pause_mode) {
+ next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ } else {
+ next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_game_tick getting behind more and more if it cannot keep up. */
+ if (next_game_tick < cur_ticks - std::chrono::milliseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_game_tick = cur_ticks;
+ }
/* Flush GDI buffer to ensure we don't conflict with the drawing thread. */
GdiFlush();
@@ -1220,7 +1226,9 @@ void VideoDriver_Win32::MainLoop()
}
if (cur_ticks >= next_draw_tick) {
- next_draw_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK);
+ /* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
+ if (next_draw_tick < cur_ticks - std::chrono::microseconds(ALLOWED_DRIFT * MILLISECONDS_PER_TICK)) next_draw_tick = cur_ticks;
bool old_ctrl_pressed = _ctrl_pressed;