diff --git a/src/gba/sio/lockstep.c b/src/gba/sio/lockstep.c index d9ffc783b..601236916 100644 --- a/src/gba/sio/lockstep.c +++ b/src/gba/sio/lockstep.c @@ -129,11 +129,7 @@ bool GBASIOLockstepNodeUnload(struct GBASIODriver* driver) { default: break; } - if (node->id) { - node->p->signal(node->p, 1 << node->id); - } else { - node->p->addCycles(node->p, 0, node->eventDiff); - } + node->p->unload(node->p, node->id); return true; } diff --git a/src/gba/sio/lockstep.h b/src/gba/sio/lockstep.h index e6e678982..797bb5859 100644 --- a/src/gba/sio/lockstep.h +++ b/src/gba/sio/lockstep.h @@ -31,6 +31,7 @@ struct GBASIOLockstep { bool (*wait)(struct GBASIOLockstep*, unsigned mask); void (*addCycles)(struct GBASIOLockstep*, int id, int32_t cycles); int32_t (*useCycles)(struct GBASIOLockstep*, int id, int32_t cycles); + void (*unload)(struct GBASIOLockstep*, int id); void* context; #ifndef NDEBUG int transferId; diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 833a3ce9a..f809093aa 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -50,6 +50,7 @@ GameController::GameController(QObject* parent) , m_audioThread(new QThread(this)) , m_audioProcessor(AudioProcessor::create()) , m_pauseAfterFrame(false) + , m_sync(true) , m_videoSync(VIDEO_SYNC) , m_audioSync(AUDIO_SYNC) , m_fpsTarget(-1) @@ -938,10 +939,13 @@ void GameController::setTurbo(bool set, bool forced) { if (m_turboForced && !forced) { return; } - if (m_turbo == set && m_turboForced == forced) { + if (m_turbo == set && m_turboForced == (set && forced)) { // Don't interrupt the thread if we don't need to return; } + if (!m_sync) { + return; + } m_turbo = set; m_turboForced = set && forced; enableTurbo(); @@ -954,25 +958,41 @@ void GameController::setTurboSpeed(float ratio) { void GameController::enableTurbo() { threadInterrupt(); + bool shouldRedoSamples = false; if (!m_turbo) { + shouldRedoSamples = m_threadContext.sync.fpsTarget != m_fpsTarget; m_threadContext.sync.fpsTarget = m_fpsTarget; m_threadContext.sync.audioWait = m_audioSync; m_threadContext.sync.videoFrameWait = m_videoSync; } else if (m_turboSpeed <= 0) { + shouldRedoSamples = m_threadContext.sync.fpsTarget != m_fpsTarget; m_threadContext.sync.fpsTarget = m_fpsTarget; m_threadContext.sync.audioWait = false; m_threadContext.sync.videoFrameWait = false; } else { + shouldRedoSamples = m_threadContext.sync.fpsTarget != m_fpsTarget * m_turboSpeed; m_threadContext.sync.fpsTarget = m_fpsTarget * m_turboSpeed; m_threadContext.sync.audioWait = true; m_threadContext.sync.videoFrameWait = false; } - if (m_audioProcessor) { + if (m_audioProcessor && shouldRedoSamples) { redoSamples(m_audioProcessor->getBufferSamples()); } threadContinue(); } +void GameController::setSync(bool enable) { + m_turbo = false; + m_turboForced = false; + if (!enable) { + m_threadContext.sync.audioWait = false; + m_threadContext.sync.videoFrameWait = false; + } else { + m_threadContext.sync.audioWait = m_audioSync; + m_threadContext.sync.videoFrameWait = m_videoSync; + } + m_sync = enable; +} void GameController::setAVStream(mAVStream* stream) { threadInterrupt(); m_stream = stream; diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index c7e1fff7d..91d733e24 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -135,7 +135,8 @@ public slots: void loadBackupState(); void saveBackupState(); void setTurbo(bool, bool forced = true); - void setTurboSpeed(float ratio = -1); + void setTurboSpeed(float ratio); + void setSync(bool); void setAVStream(mAVStream*); void clearAVStream(); void reloadAudioDriver(); @@ -197,6 +198,7 @@ private: QAtomicInt m_pauseAfterFrame; QList> m_resetActions; + bool m_sync; bool m_videoSync; bool m_audioSync; float m_fpsTarget; diff --git a/src/platform/qt/MultiplayerController.cpp b/src/platform/qt/MultiplayerController.cpp index 13a761539..91ec4beb5 100644 --- a/src/platform/qt/MultiplayerController.cpp +++ b/src/platform/qt/MultiplayerController.cpp @@ -56,9 +56,11 @@ MultiplayerController::MultiplayerController() { if (!id) { for (int i = 1; i < controller->m_players.count(); ++i) { Player* player = &controller->m_players[i]; - if (player->node->mode != controller->m_players[0].node->mode) { + if (player->node->d.p->mode != controller->m_players[0].node->d.p->mode) { + player->controller->setSync(true); continue; } + player->controller->setSync(false); player->cyclesPosted += cycles; if (player->awake < 1) { player->node->nextEvent += player->cyclesPosted; @@ -67,6 +69,7 @@ MultiplayerController::MultiplayerController() { } } } else { + controller->m_players[id].controller->setSync(true); controller->m_players[id].cyclesPosted += cycles; } controller->m_lock.unlock(); @@ -84,6 +87,31 @@ MultiplayerController::MultiplayerController() { controller->m_lock.unlock(); return cycles; }; + m_lockstep.unload = [](GBASIOLockstep* lockstep, int id) { + MultiplayerController* controller = static_cast(lockstep->context); + controller->m_lock.lock(); + Player* player = &controller->m_players[id]; + if (id) { + player->controller->setSync(true); + player->waitMask &= ~(1 << id); + if (!player->waitMask && player->awake < 1) { + mCoreThreadStopWaiting(player->controller->thread()); + player->awake = 1; + } + } else { + for (int i = 1; i < controller->m_players.count(); ++i) { + Player* player = &controller->m_players[i]; + player->controller->setSync(true); + player->cyclesPosted += lockstep->players[0]->eventDiff; + if (player->awake < 1) { + player->node->nextEvent += player->cyclesPosted; + mCoreThreadStopWaiting(player->controller->thread()); + player->awake = 1; + } + } + } + controller->m_lock.unlock(); + }; } MultiplayerController::~MultiplayerController() {