diff --git a/src/driver.cpp b/src/driver.cpp index 38265d9f65..e3fef51dda 100644 --- a/src/driver.cpp +++ b/src/driver.cpp @@ -9,15 +9,23 @@ #include "stdafx.h" #include "debug.h" +#include "debug_fmt.h" #include "error.h" #include "sound/sound_driver.hpp" #include "music/music_driver.hpp" #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 +40,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. @@ -114,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); + 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, "w", BASE_DIR); + FioFCloseFile(f); + } + Driver *oldd = *GetActiveDriver(type); Driver *newd = d->CreateInstance(); *GetActiveDriver(type) = newd; @@ -131,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); } } @@ -177,6 +208,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); + 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 4caf825c88..abb8d35efb 100644 --- a/src/driver.h +++ b/src/driver.h @@ -101,6 +101,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/video/video_driver.cpp b/src/video/video_driver.cpp index aa044630da..8b70d53376 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" @@ -176,6 +177,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(); + } } }