OpenTTD Source  20241108-master-g80f628063a
video_driver.hpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
10 #ifndef VIDEO_VIDEO_DRIVER_HPP
11 #define VIDEO_VIDEO_DRIVER_HPP
12 
13 #include "../driver.h"
14 #include "../core/geometry_type.hpp"
15 #include "../core/math_func.hpp"
16 #include "../gfx_func.h"
17 #include "../settings_type.h"
18 #include "../zoom_type.h"
19 #include "../network/network_func.h"
20 #include <atomic>
21 #include <chrono>
22 #include <condition_variable>
23 #include <mutex>
24 #include <thread>
25 
26 extern std::string _ini_videodriver;
27 extern std::vector<Dimension> _resolutions;
29 extern bool _rightclick_emulate;
30 extern bool _video_hw_accel;
31 extern bool _video_vsync;
32 
34 class VideoDriver : public Driver {
35  const uint DEFAULT_WINDOW_WIDTH = 640u;
36  const uint DEFAULT_WINDOW_HEIGHT = 480u;
37 
38 public:
39  VideoDriver(bool uses_hardware_acceleration = false) : fast_forward_key_pressed(false), fast_forward_via_key(false), is_game_threaded(true), uses_hardware_acceleration(uses_hardware_acceleration) {}
40 
48  virtual void MakeDirty(int left, int top, int width, int height) = 0;
49 
53  virtual void MainLoop() = 0;
54 
61  virtual bool ChangeResolution(int w, int h) = 0;
62 
68  virtual bool ToggleFullscreen(bool fullscreen) = 0;
69 
74  virtual void ToggleVsync([[maybe_unused]] bool vsync) {}
75 
80  virtual bool AfterBlitterChange()
81  {
82  return true;
83  }
84 
85  virtual bool ClaimMousePointer()
86  {
87  return true;
88  }
89 
94  virtual bool UseSystemCursor()
95  {
96  return false;
97  }
98 
102  virtual void PopulateSystemSprites() {}
103 
107  virtual void ClearSystemSprites() {}
108 
117  virtual bool HasGUI() const
118  {
119  return true;
120  }
121 
126  virtual bool HasEfficient8Bpp() const
127  {
128  return false;
129  }
130 
135  virtual bool HasAnimBuffer()
136  {
137  return false;
138  }
139 
144  virtual uint8_t *GetAnimBuffer()
145  {
146  return nullptr;
147  }
148 
152  virtual void EditBoxLostFocus() {}
153 
157  virtual void EditBoxGainedFocus() {}
158 
163  virtual std::vector<int> GetListOfMonitorRefreshRates()
164  {
165  return {};
166  }
167 
171  virtual int GetSuggestedUIScale()
172  {
173  float dpi_scale = this->GetDPIScale();
174 
175  return Clamp(dpi_scale * 100, MIN_INTERFACE_SCALE, MAX_INTERFACE_SCALE);
176  }
177 
178  virtual std::string_view GetInfoString() const
179  {
180  return this->GetName();
181  }
182 
189  void QueueOnMainThread(std::function<void()> &&func)
190  {
191  std::lock_guard<std::mutex> lock(this->cmd_queue_mutex);
192 
193  this->cmd_queue.emplace_back(std::forward<std::function<void()>>(func));
194  }
195 
196  void GameLoopPause();
197 
202  {
204  }
205 
206  static std::string GetCaption();
207 
214  {
216  }
217 
219  {
221  }
222 
223  private:
224  bool unlock;
225  };
226 
227 protected:
228  const uint ALLOWED_DRIFT = 5;
229 
234 
239  virtual float GetDPIScale() { return 1.0f; }
240 
245  {
246  if (_cur_resolution.width == 0 || _cur_resolution.height == 0) {
247  /* Auto-detect a good resolution. We aim for 75% of the screen size.
248  * Limit width times height times bytes per pixel to fit a 32 bit
249  * integer, This way all internal drawing routines work correctly. */
250  Dimension res = this->GetScreenSize();
251  _cur_resolution.width = ClampU(res.width * 3 / 4, DEFAULT_WINDOW_WIDTH, UINT16_MAX / 2);
252  _cur_resolution.height = ClampU(res.height * 3 / 4, DEFAULT_WINDOW_HEIGHT, UINT16_MAX / 2);
253  }
254  }
255 
259  virtual void InputLoop() {}
260 
265  virtual bool LockVideoBuffer()
266  {
267  return false;
268  }
269 
273  virtual void UnlockVideoBuffer() {}
274 
278  virtual void Paint() {}
279 
283  virtual void CheckPaletteAnim() {}
284 
289  virtual bool PollEvent() { return false; };
290 
294  void StartGameThread();
295 
299  void StopGameThread();
300 
306  void Tick();
307 
311  void SleepTillNextTick();
312 
313  std::chrono::steady_clock::duration GetGameInterval()
314  {
315 #ifdef DEBUG_DUMP_COMMANDS
316  /* When replaying, run as fast as we can. */
317  extern bool _ddc_fastforward;
318  if (_ddc_fastforward) return std::chrono::microseconds(0);
319 #endif /* DEBUG_DUMP_COMMANDS */
320 
321  /* If we are paused, run on normal speed. */
322  if (_pause_mode) return std::chrono::milliseconds(MILLISECONDS_PER_TICK);
323  /* Infinite speed, as quickly as you can. */
324  if (_game_speed == 0) return std::chrono::microseconds(0);
325 
326  return std::chrono::microseconds(MILLISECONDS_PER_TICK * 1000 * 100 / _game_speed);
327  }
328 
329  std::chrono::steady_clock::duration GetDrawInterval()
330  {
331  /* If vsync, draw interval is decided by the display driver */
332  if (_video_vsync && this->uses_hardware_acceleration) return std::chrono::microseconds(0);
333  return std::chrono::microseconds(1000000 / _settings_client.gui.refresh_rate);
334  }
335 
338  {
339  std::vector<std::function<void()>> cmds{};
340 
341  {
342  /* Exchange queue with an empty one to limit the time we
343  * hold the mutex. This also ensures that queued functions can
344  * add new functions to the queue without everything blocking. */
345  std::lock_guard<std::mutex> lock(this->cmd_queue_mutex);
346  cmds.swap(this->cmd_queue);
347  }
348 
349  for (auto &f : cmds) {
350  f();
351  }
352  }
353 
354  std::chrono::steady_clock::time_point next_game_tick;
355  std::chrono::steady_clock::time_point next_draw_tick;
356 
359 
360  bool is_game_threaded;
361  std::thread game_thread;
362  std::mutex game_state_mutex;
363  std::mutex game_thread_wait_mutex;
364 
365  bool uses_hardware_acceleration;
366 
367  static void GameThreadThunk(VideoDriver *drv);
368 
369 private:
370  std::mutex cmd_queue_mutex;
371  std::vector<std::function<void()>> cmd_queue;
372 
373  void GameLoop();
374  void GameThread();
375 };
376 
377 #endif /* VIDEO_VIDEO_DRIVER_HPP */
static Driver ** GetActiveDriver(Driver::Type type)
Get the active driver for the given type.
Definition: driver.h:84
A driver for communicating with the user.
Definition: driver.h:21
virtual std::string_view GetName() const =0
Get the name of this driver.
@ DT_VIDEO
A video driver.
Definition: driver.h:42
The base of all video drivers.
virtual void InputLoop()
Handle input logic, is CTRL pressed, should we fast-forward, etc.
virtual bool ToggleFullscreen(bool fullscreen)=0
Change the full screen setting.
virtual Dimension GetScreenSize() const
Get the resolution of the main screen.
virtual void PopulateSystemSprites()
Populate all sprites in cache.
void QueueOnMainThread(std::function< void()> &&func)
Queue a function to be called on the main thread with game state lock held and video buffer locked.
const uint DEFAULT_WINDOW_WIDTH
Default window width.
virtual int GetSuggestedUIScale()
Get a suggested default GUI scale taking screen DPI into account.
bool fast_forward_key_pressed
The fast-forward key is being pressed.
virtual void ClearSystemSprites()
Clear all cached sprites.
virtual bool UseSystemCursor()
Get whether the mouse cursor is drawn by the video driver.
void Tick()
Give the video-driver a tick.
const uint DEFAULT_WINDOW_HEIGHT
Default window height.
virtual void MakeDirty(int left, int top, int width, int height)=0
Mark a particular area dirty.
void SleepTillNextTick()
Sleep till the next tick is about to happen.
void StartGameThread()
Start the loop for game-tick.
virtual std::vector< int > GetListOfMonitorRefreshRates()
Get a list of refresh rates of each available monitor.
virtual void EditBoxLostFocus()
An edit box lost the input focus.
virtual bool HasAnimBuffer()
Does this video driver support a separate animation buffer in addition to the colour buffer?
virtual bool ChangeResolution(int w, int h)=0
Change the resolution of the window.
virtual bool HasGUI() const
Whether the driver has a graphical user interface with the end user.
static std::string GetCaption()
Get the caption to use for the game's title bar.
virtual bool AfterBlitterChange()
Callback invoked after the blitter was changed.
void StopGameThread()
Stop the loop for the game-tick.
virtual void ToggleVsync([[maybe_unused]] bool vsync)
Change the vsync setting.
const uint ALLOWED_DRIFT
How many times videodriver can miss deadlines without it being overly compensated.
virtual void MainLoop()=0
Perform the actual drawing.
virtual void EditBoxGainedFocus()
An edit box gained the input focus.
virtual bool PollEvent()
Process a single system event.
virtual bool HasEfficient8Bpp() const
Has this video driver an efficient code path for palette animated 8-bpp sprites?
virtual void Paint()
Paint the window.
virtual void UnlockVideoBuffer()
Unlock a previously locked video buffer.
bool fast_forward_via_key
The fast-forward was enabled by key press.
virtual float GetDPIScale()
Get DPI scaling factor of the screen OTTD is displayed on.
virtual void CheckPaletteAnim()
Process any pending palette animation.
virtual bool LockVideoBuffer()
Make sure the video buffer is ready for drawing.
void GameLoopPause()
Pause the game-loop for a bit, releasing the game-state lock.
void DrainCommandQueue()
Execute all queued commands.
void UpdateAutoResolution()
Apply resolution auto-detection and clamp to sensible defaults.
static VideoDriver * GetInstance()
Get the currently active instance of the video driver.
virtual uint8_t * GetAnimBuffer()
Get a pointer to the animation buffer of the video back-end.
PauseMode _pause_mode
The current pause mode.
Definition: gfx.cpp:50
uint16_t _game_speed
Current game-speed; 100 is 1x, 0 is infinite.
Definition: gfx.cpp:40
static const uint MILLISECONDS_PER_TICK
The number of milliseconds per game tick.
Definition: gfx_type.h:325
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition: math_func.hpp:79
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
Definition: math_func.hpp:150
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
GUISettings gui
settings related to the GUI
Dimensions (a width and height) of a rectangle in 2D.
uint16_t refresh_rate
How often we refresh the screen (time between draw-ticks).
Helper struct to ensure the video buffer is locked and ready for drawing.
bool unlock
Stores if the lock did anything that has to be undone.
bool _video_vsync
Whether we should use vsync (only if active video driver supports HW acceleration).
bool _video_hw_accel
Whether to consider hardware accelerated video drivers on startup.
std::string _ini_videodriver
The video driver a stored in the configuration file.
Definition: driver.cpp:24
std::vector< Dimension > _resolutions
List of resolutions.
Definition: driver.cpp:25
Dimension _cur_resolution
The current resolution.
Definition: driver.cpp:26
bool _rightclick_emulate
Whether right clicking is emulated.
Definition: driver.cpp:27
std::mutex lock
synchronization for playback status fields
Definition: win32_m.cpp:35