|
@@ -703,30 +703,29 @@ void VideoDriver_SDL::MainLoop()
|
|
|
auto next_game_tick = cur_ticks;
|
|
|
auto next_draw_tick = cur_ticks;
|
|
|
|
|
|
CheckPaletteAnim();
|
|
|
|
|
|
std::thread draw_thread;
|
|
|
std::unique_lock<std::recursive_mutex> draw_lock;
|
|
|
if (_draw_threaded) {
|
|
|
/* Initialise the mutex first, because that's the thing we *need*
|
|
|
* directly in the newly created thread. */
|
|
|
_draw_mutex = new std::recursive_mutex();
|
|
|
if (_draw_mutex == nullptr) {
|
|
|
_draw_threaded = false;
|
|
|
} else {
|
|
|
draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
|
|
|
this->draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
|
|
|
_draw_signal = new std::condition_variable_any();
|
|
|
_draw_continue = true;
|
|
|
|
|
|
_draw_threaded = StartNewThread(&draw_thread, "ottd:draw-sdl", &DrawSurfaceToScreenThread);
|
|
|
|
|
|
/* Free the mutex if we won't be able to use it. */
|
|
|
if (!_draw_threaded) {
|
|
|
draw_lock.unlock();
|
|
|
draw_lock.release();
|
|
|
this->draw_lock.unlock();
|
|
|
this->draw_lock.release();
|
|
|
delete _draw_mutex;
|
|
|
delete _draw_signal;
|
|
|
_draw_mutex = nullptr;
|
|
|
_draw_signal = nullptr;
|
|
|
} else {
|
|
|
/* Wait till the draw mutex has started itself. */
|
|
@@ -760,15 +759,15 @@ void VideoDriver_SDL::MainLoop()
|
|
|
/* Avoid next_game_tick getting behind more and more if it cannot keep up. */
|
|
|
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
|
|
|
* except sleeping can't. */
|
|
|
if (_draw_mutex != nullptr) draw_lock.unlock();
|
|
|
this->UnlockVideoBuffer();
|
|
|
GameLoop();
|
|
|
if (_draw_mutex != nullptr) draw_lock.lock();
|
|
|
this->LockVideoBuffer();
|
|
|
}
|
|
|
|
|
|
/* Prevent drawing when switching mode, as windows can be removed when they should still appear. */
|
|
|
if (cur_ticks >= next_draw_tick && (_switch_mode == SM_NONE || HasModalProgress())) {
|
|
|
next_draw_tick += this->GetDrawInterval();
|
|
|
/* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
|
|
@@ -791,26 +790,26 @@ void VideoDriver_SDL::MainLoop()
|
|
|
if (!_fast_forward || _pause_mode) {
|
|
|
/* See how much time there is till we have to process the next event, and try to hit that as close as possible. */
|
|
|
auto next_tick = std::min(next_draw_tick, next_game_tick);
|
|
|
auto now = std::chrono::steady_clock::now();
|
|
|
|
|
|
if (next_tick > now) {
|
|
|
if (_draw_mutex != nullptr) draw_lock.unlock();
|
|
|
this->UnlockVideoBuffer();
|
|
|
std::this_thread::sleep_for(next_tick - now);
|
|
|
if (_draw_mutex != nullptr) draw_lock.lock();
|
|
|
this->LockVideoBuffer();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (_draw_mutex != nullptr) {
|
|
|
_draw_continue = false;
|
|
|
/* Sending signal if there is no thread blocked
|
|
|
* is very valid and results in noop */
|
|
|
_draw_signal->notify_one();
|
|
|
if (draw_lock.owns_lock()) draw_lock.unlock();
|
|
|
draw_lock.release();
|
|
|
if (this->draw_lock.owns_lock()) this->draw_lock.unlock();
|
|
|
this->draw_lock.release();
|
|
|
draw_thread.join();
|
|
|
|
|
|
delete _draw_mutex;
|
|
|
delete _draw_signal;
|
|
|
|
|
|
_draw_mutex = nullptr;
|
|
@@ -855,7 +854,18 @@ void VideoDriver_SDL::AcquireBlitterLock
|
|
|
|
|
|
void VideoDriver_SDL::ReleaseBlitterLock()
|
|
|
{
|
|
|
if (_draw_mutex != nullptr) _draw_mutex->unlock();
|
|
|
}
|
|
|
|
|
|
bool VideoDriver_SDL::LockVideoBuffer()
|
|
|
{
|
|
|
if (_draw_threaded) this->draw_lock.lock();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void VideoDriver_SDL::UnlockVideoBuffer()
|
|
|
{
|
|
|
if (_draw_threaded) this->draw_lock.unlock();
|
|
|
}
|
|
|
|
|
|
#endif /* WITH_SDL */
|