From 599cb2485855daa003c214722d653d6d8aa75174 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Wed, 17 Feb 2021 15:31:09 +0100 Subject: [PATCH] Feature: configurable refresh-rate and change default to 60fps Most modern games run on 60 fps, and for good reason. This gives a much smoother experiences. As some people have monitors that can do 144Hz or even 240Hz, allow people to configure the refresh rate. Of course, the higher you set the value, the more time the game spends on drawing pixels instead of simulating the game, which has an effect on simulation speed. The simulation will still always run at 33.33 fps, and is not influences by this setting. --- src/framerate_gui.cpp | 4 ++-- src/settings_type.h | 1 + src/table/settings.ini | 9 +++++++++ src/video/allegro_v.cpp | 10 +++++----- src/video/cocoa/cocoa_v.mm | 10 +++++----- src/video/dedicated_v.cpp | 6 +++--- src/video/sdl2_v.cpp | 4 ++-- src/video/sdl_v.cpp | 10 +++++----- src/video/video_driver.hpp | 14 ++++++++++++++ src/video/win32_v.cpp | 10 +++++----- 10 files changed, 51 insertions(+), 27 deletions(-) diff --git a/src/framerate_gui.cpp b/src/framerate_gui.cpp index 0afb533f6aa1f..26a40c4516016 100644 --- a/src/framerate_gui.cpp +++ b/src/framerate_gui.cpp @@ -189,7 +189,7 @@ namespace { PerformanceData(1), // PFE_ACC_GL_AIRCRAFT PerformanceData(1), // PFE_GL_LANDSCAPE PerformanceData(1), // PFE_GL_LINKGRAPH - PerformanceData(GL_RATE), // PFE_DRAWING + PerformanceData(1000.0 / 30), // PFE_DRAWING PerformanceData(1), // PFE_ACC_DRAWWORLD PerformanceData(60.0), // PFE_VIDEO PerformanceData(1000.0 * 8192 / 44100), // PFE_SOUND @@ -468,7 +468,7 @@ struct FramerateWindow : Window { this->speed_gameloop.SetRate(gl_rate / _pf_data[PFE_GAMELOOP].expected_rate, 1.0); if (this->small) return; // in small mode, this is everything needed - this->rate_drawing.SetRate(_pf_data[PFE_DRAWING].GetRate(), _pf_data[PFE_DRAWING].expected_rate); + this->rate_drawing.SetRate(_pf_data[PFE_DRAWING].GetRate(), _settings_client.gui.refresh_rate); int new_active = 0; for (PerformanceElement e = PFE_FIRST; e < PFE_MAX; e++) { diff --git a/src/settings_type.h b/src/settings_type.h index 3c325a0cc0310..11298cfa70561 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -147,6 +147,7 @@ struct GUISettings { byte starting_colour; ///< default color scheme for the company to start a new game with bool show_newgrf_name; ///< Show the name of the NewGRF in the build vehicle window bool auto_remove_signals; ///< automatically remove signals when in the way during rail construction + uint16 refresh_rate; ///< How often we refresh the screen (time between draw-ticks). uint16 console_backlog_timeout; ///< the minimum amount of time items should be in the console backlog before they will be removed in ~3 seconds granularity. uint16 console_backlog_length; ///< the minimum amount of items in the console backlog before items will be removed. diff --git a/src/table/settings.ini b/src/table/settings.ini index 7dd9da2559ebc..75897dee12a7b 100644 --- a/src/table/settings.ini +++ b/src/table/settings.ini @@ -3324,6 +3324,15 @@ def = 100 min = 10 max = 65500 +[SDTC_VAR] +var = gui.refresh_rate +type = SLE_UINT16 +flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC +def = 60 +min = 10 +max = 1000 +cat = SC_EXPERT + [SDTC_BOOL] var = sound.news_ticker flags = SLF_NOT_IN_SAVE | SLF_NO_NETWORK_SYNC diff --git a/src/video/allegro_v.cpp b/src/video/allegro_v.cpp index 800cce40cc58f..29db2f1daf6bb 100644 --- a/src/video/allegro_v.cpp +++ b/src/video/allegro_v.cpp @@ -485,20 +485,20 @@ void VideoDriver_Allegro::MainLoop() if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { if (_fast_forward && !_pause_mode) { - next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick = cur_ticks + this->GetGameInterval(); } else { - next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick += this->GetGameInterval(); /* 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; + if (next_game_tick < cur_ticks - ALLOWED_DRIFT * this->GetGameInterval()) next_game_tick = cur_ticks; } GameLoop(); } if (cur_ticks >= next_draw_tick) { - next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_draw_tick += this->GetDrawInterval(); /* 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; + if (next_draw_tick < cur_ticks - ALLOWED_DRIFT * this->GetDrawInterval()) 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 7c8981f617557..31bad36dc1615 100644 --- a/src/video/cocoa/cocoa_v.mm +++ b/src/video/cocoa/cocoa_v.mm @@ -675,20 +675,20 @@ static void ClearWindowBuffer(uint32 *buffer, uint32 pitch, uint32 height) if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { if (_fast_forward && !_pause_mode) { - next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick = cur_ticks + this->GetGameInterval(); } else { - next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick += this->GetGameInterval(); /* 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; + if (next_game_tick < cur_ticks - ALLOWED_DRIFT * this->GetGameInterval()) next_game_tick = cur_ticks; } ::GameLoop(); } if (cur_ticks >= next_draw_tick) { - next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_draw_tick += this->GetDrawInterval(); /* 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; + if (next_draw_tick < cur_ticks - ALLOWED_DRIFT * this->GetDrawInterval()) 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 845b0bf8cf2fd..53351458a19dd 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -294,11 +294,11 @@ void VideoDriver_Dedicated::MainLoop() if (cur_ticks >= next_game_tick || _ddc_fastforward) { if (_ddc_fastforward) { - next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick = cur_ticks + this->GetGameInterval(); } else { - next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick += this->GetGameInterval(); /* 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; + if (next_game_tick < cur_ticks - ALLOWED_DRIFT * this->GetGameInterval()) next_game_tick = cur_ticks; } GameLoop(); diff --git a/src/video/sdl2_v.cpp b/src/video/sdl2_v.cpp index 74d9faee5b342..82288a282291e 100644 --- a/src/video/sdl2_v.cpp +++ b/src/video/sdl2_v.cpp @@ -807,9 +807,9 @@ void VideoDriver_SDL::LoopOnce() } if (cur_ticks >= next_draw_tick) { - next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_draw_tick += this->GetDrawInterval(); /* 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; + if (next_draw_tick < cur_ticks - ALLOWED_DRIFT * this->GetDrawInterval()) 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 1c257cb2cac1e..851e116cc64b7 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -730,11 +730,11 @@ void VideoDriver_SDL::MainLoop() if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { if (_fast_forward && !_pause_mode) { - next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick = cur_ticks + this->GetGameInterval(); } else { - next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick += this->GetGameInterval(); /* 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; + if (next_game_tick < cur_ticks - ALLOWED_DRIFT * this->GetGameInterval()) next_game_tick = cur_ticks; } /* The gameloop is the part that can run asynchronously. The rest @@ -745,9 +745,9 @@ void VideoDriver_SDL::MainLoop() } if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { - next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_draw_tick += this->GetDrawInterval(); /* 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; + if (next_draw_tick < cur_ticks - ALLOWED_DRIFT * this->GetDrawInterval()) 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 94803db224b67..f566ba30e56db 100644 --- a/src/video/video_driver.hpp +++ b/src/video/video_driver.hpp @@ -13,7 +13,9 @@ #include "../driver.h" #include "../core/geometry_type.hpp" #include "../core/math_func.hpp" +#include "../settings_type.h" #include "../zoom_type.h" +#include #include extern std::string _ini_videodriver; @@ -153,6 +155,18 @@ class VideoDriver : public Driver { _cur_resolution.height = ClampU(res.height * 3 / 4, DEFAULT_WINDOW_HEIGHT, UINT16_MAX / 2); } } + + std::chrono::steady_clock::duration GetGameInterval() + { + return std::chrono::milliseconds(MILLISECONDS_PER_TICK); + } + + std::chrono::steady_clock::duration GetDrawInterval() + { + /* TODO -- If michi_cc' patch lands for startup flag, possibly this can be removed. */ + uint8 refresh_rate = _settings_client.gui.refresh_rate != 0 ? _settings_client.gui.refresh_rate : 30; + return std::chrono::microseconds(1000000 / refresh_rate); + } }; #endif /* VIDEO_VIDEO_DRIVER_HPP */ diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 8f39fe90c9193..78983b9269a13 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -1207,11 +1207,11 @@ void VideoDriver_Win32::MainLoop() if (cur_ticks >= next_game_tick || (_fast_forward && !_pause_mode)) { if (_fast_forward && !_pause_mode) { - next_game_tick = cur_ticks + std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick = cur_ticks + this->GetGameInterval(); } else { - next_game_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_game_tick += this->GetGameInterval(); /* 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; + if (next_game_tick < cur_ticks - ALLOWED_DRIFT * this->GetGameInterval()) next_game_tick = cur_ticks; } /* Flush GDI buffer to ensure we don't conflict with the drawing thread. */ @@ -1225,9 +1225,9 @@ void VideoDriver_Win32::MainLoop() } if (cur_ticks >= next_draw_tick) { - next_draw_tick += std::chrono::milliseconds(MILLISECONDS_PER_TICK); + next_draw_tick += this->GetDrawInterval(); /* 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; + if (next_draw_tick < cur_ticks - ALLOWED_DRIFT * this->GetDrawInterval()) next_draw_tick = cur_ticks; bool old_ctrl_pressed = _ctrl_pressed;