diff --git a/src/driver.cpp b/src/driver.cpp index 417bde7072..6064dd9654 100644 --- a/src/driver.cpp +++ b/src/driver.cpp @@ -15,9 +15,16 @@ #include "video/video_driver.hpp" #include "string_func.h" #include "table/strings.h" +#include "fileio_func.h" #include #include +#ifdef _WIN32 +# include +#else +# include +#endif /* _WIN32 */ + #include "safeguards.h" std::string _ini_videodriver; ///< The video driver a stored in the configuration file. @@ -32,6 +39,8 @@ std::string _ini_musicdriver; ///< The music driver a stored in the confi std::string _ini_blitter; ///< The blitter as stored in the configuration file. bool _blitter_autodetected; ///< Was the blitter autodetected or specified by the user? +static const std::string HWACCELERATION_TEST_FILE = "hwaccel.dat"; ///< Filename to test if we crashed last time we tried to use hardware acceleration. + /** * Get a string parameter the list of parameters. * @param parm The parameters. @@ -115,6 +124,27 @@ bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type t if (type == Driver::DT_VIDEO && !_video_hw_accel && d->UsesHardwareAcceleration()) continue; + if (type == Driver::DT_VIDEO && _video_hw_accel && d->UsesHardwareAcceleration()) { + /* Check if we have already tried this driver in last run. + * If it is here, it most likely means we crashed. So skip + * hardware acceleration. */ + auto filename = FioFindFullPath(BASE_DIR, HWACCELERATION_TEST_FILE.c_str()); + if (!filename.empty()) { + unlink(filename.c_str()); + + Debug(driver, 1, "Probing {} driver '{}' skipped due to earlier crash", GetDriverTypeName(type), d->name); + + _video_hw_accel = false; + ErrorMessageData msg(STR_VIDEO_DRIVER_ERROR, STR_VIDEO_DRIVER_ERROR_HARDWARE_ACCELERATION_CRASH, true); + ScheduleErrorMessage(msg); + continue; + } + + /* Write empty file to note we are attempting hardware acceleration. */ + auto f = FioFOpenFile(HWACCELERATION_TEST_FILE.c_str(), "w", BASE_DIR); + FioFCloseFile(f); + } + Driver *oldd = *GetActiveDriver(type); Driver *newd = d->CreateInstance(); *GetActiveDriver(type) = newd; @@ -132,7 +162,7 @@ bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type t if (type == Driver::DT_VIDEO && _video_hw_accel && d->UsesHardwareAcceleration()) { _video_hw_accel = false; - ErrorMessageData msg(STR_VIDEO_DRIVER_ERROR, STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION); + ErrorMessageData msg(STR_VIDEO_DRIVER_ERROR, STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION, true); ScheduleErrorMessage(msg); } } @@ -179,6 +209,18 @@ bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type t } } +/** + * Mark the current video driver as operational. + */ +void DriverFactoryBase::MarkVideoDriverOperational() +{ + /* As part of the detection whether the GPU driver crashes the game, + * and as we are operational now, remove the hardware acceleration + * test-file. */ + auto filename = FioFindFullPath(BASE_DIR, HWACCELERATION_TEST_FILE.c_str()); + if (!filename.empty()) unlink(filename.c_str()); +} + /** * Build a human readable list of available drivers, grouped by type. * @param p The buffer to write to. diff --git a/src/driver.h b/src/driver.h index 93aaf61550..56f7d19b5e 100644 --- a/src/driver.h +++ b/src/driver.h @@ -102,6 +102,8 @@ private: static bool SelectDriverImpl(const std::string &name, Driver::Type type); + static void MarkVideoDriverOperational(); + protected: DriverFactoryBase(Driver::Type type, int priority, const char *name, const char *description); diff --git a/src/lang/english.txt b/src/lang/english.txt index 34964f5d21..0e21f0aa9c 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -2056,6 +2056,7 @@ STR_CONFIG_ERROR_SPRITECACHE_TOO_BIG :{WHITE}Allocati # Video initalization errors STR_VIDEO_DRIVER_ERROR :{WHITE}Error with video settings... STR_VIDEO_DRIVER_ERROR_NO_HARDWARE_ACCELERATION :{WHITE}... no compatible GPU found. Hardware acceleration disabled +STR_VIDEO_DRIVER_ERROR_HARDWARE_ACCELERATION_CRASH :{WHITE}... GPU driver crashed the game. Hardware acceleration disabled # Intro window STR_INTRO_CAPTION :{WHITE}OpenTTD {REV} diff --git a/src/video/video_driver.cpp b/src/video/video_driver.cpp index 8fe582760f..ad1c8fb808 100644 --- a/src/video/video_driver.cpp +++ b/src/video/video_driver.cpp @@ -12,6 +12,7 @@ #include "../network/network.h" #include "../blitter/factory.hpp" #include "../debug.h" +#include "../driver.h" #include "../fontcache.h" #include "../gfx_func.h" #include "../gfxinit.h" @@ -156,6 +157,13 @@ void VideoDriver::Tick() this->Paint(); this->UnlockVideoBuffer(); + + /* Wait till the first successful drawing tick before marking the driver as operational. */ + static bool first_draw_tick = true; + if (first_draw_tick) { + first_draw_tick = false; + DriverFactoryBase::MarkVideoDriverOperational(); + } } }