1
0
Fork 0

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.
pull/8694/head
Patric Stout 2021-02-17 15:14:59 +01:00 committed by Patric Stout
parent c81c6e5eb7
commit ae7a2b9f02
7 changed files with 61 additions and 13 deletions

View File

@ -484,13 +484,21 @@ void VideoDriver_Allegro::MainLoop()
} }
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { 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(); GameLoop();
} }
if (cur_ticks >= next_draw_tick) { 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; bool old_ctrl_pressed = _ctrl_pressed;

View File

@ -674,13 +674,21 @@ void VideoDriver_Cocoa::GameLoop()
} }
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { 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(); ::GameLoop();
} }
if (cur_ticks >= next_draw_tick) { 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; bool old_ctrl_pressed = _ctrl_pressed;

View File

@ -238,7 +238,7 @@ void VideoDriver_Dedicated::MainLoop()
{ {
auto cur_ticks = std::chrono::steady_clock::now(); auto cur_ticks = std::chrono::steady_clock::now();
auto last_realtime_tick = cur_ticks; auto last_realtime_tick = cur_ticks;
auto next_tick = cur_ticks; auto next_game_tick = cur_ticks;
/* Signal handlers */ /* Signal handlers */
#if defined(UNIX) #if defined(UNIX)
@ -292,8 +292,14 @@ void VideoDriver_Dedicated::MainLoop()
last_realtime_tick += delta; last_realtime_tick += delta;
} }
if (cur_ticks >= next_tick || _ddc_fastforward) { if (cur_ticks >= next_game_tick || _ddc_fastforward) {
next_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK); 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(); GameLoop();
InputLoop(); InputLoop();

View File

@ -777,7 +777,13 @@ void VideoDriver_SDL::LoopOnce()
} }
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { 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 /* The gameloop is the part that can run asynchronously. The rest
* except sleeping can't. */ * except sleeping can't. */
@ -787,7 +793,9 @@ void VideoDriver_SDL::LoopOnce()
} }
if (cur_ticks >= next_draw_tick) { 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; bool old_ctrl_pressed = _ctrl_pressed;

View File

@ -730,7 +730,13 @@ void VideoDriver_SDL::MainLoop()
} }
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { 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 /* The gameloop is the part that can run asynchronously. The rest
* except sleeping can't. */ * except sleeping can't. */
@ -740,7 +746,9 @@ void VideoDriver_SDL::MainLoop()
} }
if (cur_ticks >= next_draw_tick) { 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; bool old_ctrl_pressed = _ctrl_pressed;

View File

@ -126,6 +126,8 @@ public:
} }
protected: 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. * Get the resolution of the main screen.
*/ */

View File

@ -1207,7 +1207,13 @@ void VideoDriver_Win32::MainLoop()
} }
if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { 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. */ /* Flush GDI buffer to ensure we don't conflict with the drawing thread. */
GdiFlush(); GdiFlush();
@ -1220,7 +1226,9 @@ void VideoDriver_Win32::MainLoop()
} }
if (cur_ticks >= next_draw_tick) { 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; bool old_ctrl_pressed = _ctrl_pressed;