Skip to content

Commit 65efa88

Browse files
libretro: refactor multiplayer frame synchronization logic
1 parent 4374338 commit 65efa88

2 files changed

Lines changed: 34 additions & 34 deletions

File tree

src/platform/libretro/libretro.c

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2124,17 +2124,6 @@ bool retro_load_game(const struct retro_game_info* game) {
21242124
controllers[i].core->setPeripheral(controllers[i].core, mPERIPH_ROTATION, &rotation);
21252125
}
21262126

2127-
if (numCores > 1) {
2128-
for (int i = 0; i < numCores; ++i) {
2129-
CoreControllerStart(&controllers[i]);
2130-
mCoreThreadPause(&controllers[i].threadContext);
2131-
struct mCoreSync* sync = &controllers[i].threadContext.impl->sync;
2132-
MutexLock(&sync->videoFrameMutex);
2133-
sync->videoFrameWait = (i == 0);
2134-
MutexUnlock(&sync->videoFrameMutex);
2135-
}
2136-
}
2137-
21382127
#ifdef M_CORE_GBA
21392128
/* GBA emulation produces a fairly regular number
21402129
* of audio samples per frame that is consistent
@@ -2266,6 +2255,23 @@ bool retro_load_game(const struct retro_game_info* game) {
22662255
}
22672256
#endif
22682257

2258+
if (numCores > 1) {
2259+
for (int i = 0; i < numCores; ++i) {
2260+
CoreControllerStart(&controllers[i]);
2261+
mCoreThreadPause(&controllers[i].threadContext);
2262+
struct mCoreSync* sync = &controllers[i].threadContext.impl->sync;
2263+
MutexLock(&sync->videoFrameMutex);
2264+
sync->videoFrameWait = false;
2265+
MutexUnlock(&sync->videoFrameMutex);
2266+
2267+
if (i > 0) {
2268+
MutexLock(&sync->audioBufferMutex);
2269+
sync->audioWait = false;
2270+
MutexUnlock(&sync->audioBufferMutex);
2271+
}
2272+
}
2273+
}
2274+
22692275
return true;
22702276
}
22712277

src/platform/libretro/multiplayer_controller.c

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,17 @@ void MultiplayerControllerDeinit(MultiplayerController* controller) {
4646
MutexDeinit(&controller->lockstepMutex);
4747
}
4848

49+
static void _onFrameDoneMult(struct mCoreThread* context) {
50+
mCoreThreadPauseFromThread(context);
51+
}
52+
4953
bool MultiplayerControllerAttachGame(MultiplayerController* controller, struct CoreController* game) {
5054
if (controller->attached >= MAX_PLAYERS) {
5155
return false;
5256
}
5357

5458
game->multiplayer = controller;
59+
game->threadContext.frameCallback = _onFrameDoneMult;
5560

5661
if (controller->platform == mPLATFORM_NONE) {
5762
controller->platform = game->core->platform(game->core);
@@ -137,34 +142,23 @@ void MultiplayerControllerRunFrame(MultiplayerController* controller) {
137142
struct CoreController* cc = controller->players[i];
138143
if (!cc) continue;
139144
struct mCoreThread* thread = &cc->threadContext;
140-
struct mCoreSync* sync = &thread->impl->sync;
141-
142-
if (mCoreThreadIsPaused(thread)) {
143-
mCoreThreadUnpause(thread);
144-
}
145-
146-
MutexLock(&sync->videoFrameMutex);
147-
sync->videoFramePending = 0;
148-
// Only the first core blocks at the end of its frame.
149-
// This avoids deadlocks during hardware link handshakes at the end of frames.
150-
sync->videoFrameWait = (i == 0);
151-
ConditionWake(&sync->videoFrameRequiredCond);
152-
MutexUnlock(&sync->videoFrameMutex);
145+
146+
mCoreThreadUnpause(thread);
153147
}
154148
}
155149

156150
void MultiplayerControllerWaitFrame(MultiplayerController* controller) {
157-
if (controller->attached == 0 || !controller->players[0]) return;
151+
if (controller->attached == 0) return;
158152

159-
// We only wait for the first player to finish its frame.
160-
// Lockstep will naturally throttle the others to its speed.
161-
struct CoreController* cc = controller->players[0];
162-
struct mCoreThread* thread = &cc->threadContext;
163-
struct mCoreSync* sync = &thread->impl->sync;
153+
for (int i = 0; i < controller->attached; ++i) {
154+
struct CoreController* cc = controller->players[i];
155+
if (!cc) continue;
156+
struct mCoreThread* thread = &cc->threadContext;
164157

165-
MutexLock(&sync->videoFrameMutex);
166-
while (sync->videoFramePending == 0 && mCoreThreadIsActive(thread)) {
167-
ConditionWait(&sync->videoFrameAvailableCond, &sync->videoFrameMutex);
158+
MutexLock(&thread->impl->stateMutex);
159+
while (thread->impl->state != mTHREAD_PAUSED && mCoreThreadIsActive(thread)) {
160+
ConditionWait(&thread->impl->stateOffThreadCond, &thread->impl->stateMutex);
161+
}
162+
MutexUnlock(&thread->impl->stateMutex);
168163
}
169-
MutexUnlock(&sync->videoFrameMutex);
170164
}

0 commit comments

Comments
 (0)