OpenTTD Source  20241108-master-g80f628063a
driver.cpp
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 #include "stdafx.h"
11 #include "debug.h"
12 #include "error.h"
13 #include "error_func.h"
14 #include "sound/sound_driver.hpp"
15 #include "music/music_driver.hpp"
16 #include "video/video_driver.hpp"
17 #include "string_func.h"
18 #include "table/strings.h"
19 #include "fileio_func.h"
20 #include <sstream>
21 
22 #include "safeguards.h"
23 
24 std::string _ini_videodriver;
25 std::vector<Dimension> _resolutions;
28 
29 std::string _ini_sounddriver;
30 
31 std::string _ini_musicdriver;
32 
33 std::string _ini_blitter;
35 
36 static const std::string HWACCELERATION_TEST_FILE = "hwaccel.dat";
37 
44 const char *GetDriverParam(const StringList &parm, const char *name)
45 {
46  if (parm.empty()) return nullptr;
47 
48  size_t len = strlen(name);
49  for (auto &p : parm) {
50  if (p.compare(0, len, name) == 0) {
51  if (p.length() == len) return "";
52  if (p[len] == '=') return p.c_str() + len + 1;
53  }
54  }
55  return nullptr;
56 }
57 
64 bool GetDriverParamBool(const StringList &parm, const char *name)
65 {
66  return GetDriverParam(parm, name) != nullptr;
67 }
68 
76 int GetDriverParamInt(const StringList &parm, const char *name, int def)
77 {
78  const char *p = GetDriverParam(parm, name);
79  return p != nullptr ? atoi(p) : def;
80 }
81 
88 void DriverFactoryBase::SelectDriver(const std::string &name, Driver::Type type)
89 {
91  name.empty() ?
92  UserError("Failed to autoprobe {} driver", GetDriverTypeName(type)) :
93  UserError("Failed to select requested {} driver '{}'", GetDriverTypeName(type), name);
94  }
95 }
96 
104 bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type type)
105 {
106  if (GetDrivers().empty()) return false;
107 
108  if (name.empty()) {
109  /* Probe for this driver, but do not fall back to dedicated/null! */
110  for (int priority = 10; priority > 0; priority--) {
111  for (auto &it : GetDrivers()) {
112  DriverFactoryBase *d = it.second;
113 
114  /* Check driver type */
115  if (d->type != type) continue;
116  if (d->priority != priority) continue;
117 
118  if (type == Driver::DT_VIDEO && !_video_hw_accel && d->UsesHardwareAcceleration()) continue;
119 
121  /* Check if we have already tried this driver in last run.
122  * If it is here, it most likely means we crashed. So skip
123  * hardware acceleration. */
125  if (!filename.empty()) {
126  FioRemove(filename);
127 
128  Debug(driver, 1, "Probing {} driver '{}' skipped due to earlier crash", GetDriverTypeName(type), d->name);
129 
130  _video_hw_accel = false;
131  ErrorMessageData msg(STR_VIDEO_DRIVER_ERROR, STR_VIDEO_DRIVER_ERROR_HARDWARE_ACCELERATION_CRASH, true);
133  continue;
134  }
135 
136  /* Write empty file to note we are attempting hardware acceleration. */
138  }
139 
140  Driver *oldd = *GetActiveDriver(type);
141  Driver *newd = d->CreateInstance();
142  *GetActiveDriver(type) = newd;
143 
144  auto err = newd->Start({});
145  if (!err) {
146  Debug(driver, 1, "Successfully probed {} driver '{}'", GetDriverTypeName(type), d->name);
147  delete oldd;
148  return true;
149  }
150 
151  *GetActiveDriver(type) = oldd;
152  Debug(driver, 1, "Probing {} driver '{}' failed with error: {}", GetDriverTypeName(type), d->name, *err);
153  delete newd;
154 
156  _video_hw_accel = false;
157  ErrorMessageData msg(STR_VIDEO_DRIVER_ERROR, STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION, true);
159  }
160  }
161  }
162  UserError("Couldn't find any suitable {} driver", GetDriverTypeName(type));
163  } else {
164  /* Extract the driver name and put parameter list in parm */
165  std::istringstream buffer(name);
166  std::string dname;
167  std::getline(buffer, dname, ':');
168 
169  std::string param;
170  std::vector<std::string> parms;
171  while (std::getline(buffer, param, ',')) {
172  parms.push_back(param);
173  }
174 
175  /* Find this driver */
176  for (auto &it : GetDrivers()) {
177  DriverFactoryBase *d = it.second;
178 
179  /* Check driver type */
180  if (d->type != type) continue;
181 
182  /* Check driver name */
183  if (!StrEqualsIgnoreCase(dname, d->name)) continue;
184 
185  /* Found our driver, let's try it */
186  Driver *newd = d->CreateInstance();
187 
188  auto err = newd->Start(parms);
189  if (err) {
190  delete newd;
191  UserError("Unable to load driver '{}'. The error was: {}", d->name, *err);
192  }
193 
194  Debug(driver, 1, "Successfully loaded {} driver '{}'", GetDriverTypeName(type), d->name);
195  delete *GetActiveDriver(type);
196  *GetActiveDriver(type) = newd;
197  return true;
198  }
199  UserError("No such {} driver: {}\n", GetDriverTypeName(type), dname);
200  }
201 }
202 
207 {
208  /* As part of the detection whether the GPU driver crashes the game,
209  * and as we are operational now, remove the hardware acceleration
210  * test-file. */
212  if (!filename.empty()) FioRemove(filename);
213 }
214 
219 void DriverFactoryBase::GetDriversInfo(std::back_insert_iterator<std::string> &output_iterator)
220 {
222  fmt::format_to(output_iterator, "List of {} drivers:\n", GetDriverTypeName(type));
223 
224  for (int priority = 10; priority >= 0; priority--) {
225  for (auto &it : GetDrivers()) {
226  DriverFactoryBase *d = it.second;
227  if (d->type != type) continue;
228  if (d->priority != priority) continue;
229  fmt::format_to(output_iterator, "{:>18}: {}\n", d->name, d->GetDescription());
230  }
231  }
232 
233  fmt::format_to(output_iterator, "\n");
234  }
235 }
236 
244 DriverFactoryBase::DriverFactoryBase(Driver::Type type, int priority, const char *name, const char *description) :
245  type(type), priority(priority), name(name), description(description)
246 {
247  /* Prefix the name with driver type to make it unique */
248  std::string typed_name = fmt::format("{}{}", GetDriverTypeName(type), name);
249 
250  Drivers &drivers = GetDrivers();
251  assert(drivers.find(typed_name) == drivers.end());
252  drivers.insert(Drivers::value_type(typed_name, this));
253 }
254 
259 {
260  /* Prefix the name with driver type to make it unique */
261  std::string typed_name = fmt::format("{}{}", GetDriverTypeName(type), name);
262 
263  Drivers::iterator it = GetDrivers().find(typed_name);
264  assert(it != GetDrivers().end());
265 
266  GetDrivers().erase(it);
267  if (GetDrivers().empty()) delete &GetDrivers();
268 }
Base for all driver factories.
Definition: driver.h:57
static void MarkVideoDriverOperational()
Mark the current video driver as operational.
Definition: driver.cpp:206
std::string_view name
The name of the drivers of this factory.
Definition: driver.h:65
std::string_view GetDescription() const
Get a nice description of the driver-class.
Definition: driver.h:138
std::map< std::string, DriverFactoryBase * > Drivers
Type for a map of drivers.
Definition: driver.h:68
virtual bool UsesHardwareAcceleration() const
Does the driver use hardware acceleration (video-drivers only).
Definition: driver.h:114
virtual Driver * CreateInstance() const =0
Create an instance of this driver-class.
static void SelectDriver(const std::string &name, Driver::Type type)
Find the requested driver and return its class.
Definition: driver.cpp:88
static std::string_view GetDriverTypeName(Driver::Type type)
Get the driver type name.
Definition: driver.h:95
static bool SelectDriverImpl(const std::string &name, Driver::Type type)
Find the requested driver and return its class.
Definition: driver.cpp:104
static Drivers & GetDrivers()
Get the map with drivers.
Definition: driver.h:73
DriverFactoryBase(Driver::Type type, int priority, const char *name, const char *description)
Construct a new DriverFactory.
Definition: driver.cpp:244
static void GetDriversInfo(std::back_insert_iterator< std::string > &output_iterator)
Build a human readable list of available drivers, grouped by type.
Definition: driver.cpp:219
Driver::Type type
The type of driver.
Definition: driver.h:63
static Driver ** GetActiveDriver(Driver::Type type)
Get the active driver for the given type.
Definition: driver.h:84
virtual ~DriverFactoryBase()
Frees memory used for this->name.
Definition: driver.cpp:258
int priority
The priority of this factory.
Definition: driver.h:64
A driver for communicating with the user.
Definition: driver.h:21
virtual std::optional< std::string_view > Start(const StringList &parm)=0
Start this driver.
Type
The type of driver.
Definition: driver.h:38
@ DT_END
Helper for iteration.
Definition: driver.h:43
@ DT_VIDEO
A video driver.
Definition: driver.h:42
@ DT_BEGIN
Helper for iteration.
Definition: driver.h:39
The data of the error message.
Definition: error.h:31
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition: debug.h:37
const char * GetDriverParam(const StringList &parm, const char *name)
Get a string parameter the list of parameters.
Definition: driver.cpp:44
bool _blitter_autodetected
Was the blitter autodetected or specified by the user?
Definition: driver.cpp:34
std::string _ini_videodriver
The video driver a stored in the configuration file.
Definition: driver.cpp:24
int GetDriverParamInt(const StringList &parm, const char *name, int def)
Get an integer parameter the list of parameters.
Definition: driver.cpp:76
std::string _ini_musicdriver
The music driver a stored in the configuration file.
Definition: driver.cpp:31
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::string _ini_blitter
The blitter as stored in the configuration file.
Definition: driver.cpp:33
bool GetDriverParamBool(const StringList &parm, const char *name)
Get a boolean parameter the list of parameters.
Definition: driver.cpp:64
std::string _ini_sounddriver
The sound driver a stored in the configuration file.
Definition: driver.cpp:29
static const std::string HWACCELERATION_TEST_FILE
Filename to test if we crashed last time we tried to use hardware acceleration.
Definition: driver.cpp:36
Functions related to errors.
void ScheduleErrorMessage(ErrorList &datas)
Schedule a list of errors.
Definition: error_gui.cpp:452
Error reporting related functions.
std::string FioFindFullPath(Subdirectory subdir, const std::string &filename)
Find a path to the filename in one of the search directories.
Definition: fileio.cpp:144
bool FioRemove(const std::string &filename)
Remove a file.
Definition: fileio.cpp:328
std::optional< FileHandle > FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
Definition: fileio.cpp:242
Functions for Standard In/Out file operations.
@ BASE_DIR
Base directory for all subdirectories.
Definition: fileio_type.h:116
Base for all music playback.
A number of safeguards to prevent using unsafe methods.
Base for all sound drivers.
Definition of base types and functions in a cross-platform compatible way.
bool StrEqualsIgnoreCase(const std::string_view str1, const std::string_view str2)
Compares two string( view)s for equality, while ignoring the case of the characters.
Definition: string.cpp:347
Functions related to low-level strings.
std::vector< std::string > StringList
Type for a list of strings.
Definition: string_type.h:60
Dimensions (a width and height) of a rectangle in 2D.
bool _video_hw_accel
Whether to consider hardware accelerated video drivers on startup.
Base of all video drivers.