diff --git a/CHANGES b/CHANGES index 7c64d7631..aa802fc34 100644 --- a/CHANGES +++ b/CHANGES @@ -170,6 +170,7 @@ Bugfixes: - GB Audio: Fix incorrect channel 4 iteration - GB Audio: Fix zombie mode bit masking - GBA Timer: Fix count-up timing overflowing timer 3 + - Core: Fix rewinding getting out of sync (fixes mgba.io/i/791) Misc: - Qt: Add language selector - GBA Timer: Improve accuracy of timers diff --git a/include/mgba/core/rewind.h b/include/mgba/core/rewind.h index e839209fc..052f2f45e 100644 --- a/include/mgba/core/rewind.h +++ b/include/mgba/core/rewind.h @@ -31,6 +31,7 @@ struct mCoreRewindContext { Thread thread; Condition cond; Mutex mutex; + bool ready; #endif }; diff --git a/src/core/rewind.c b/src/core/rewind.c index 15ac69a95..850d0723d 100644 --- a/src/core/rewind.c +++ b/src/core/rewind.c @@ -30,6 +30,7 @@ void mCoreRewindContextInit(struct mCoreRewindContext* context, size_t entries, context->stateFlags = SAVESTATE_SAVEDATA; #ifndef DISABLE_THREADING context->onThread = onThread; + context->ready = false; if (onThread) { MutexInit(&context->mutex); ConditionInit(&context->cond); @@ -73,6 +74,7 @@ void mCoreRewindAppend(struct mCoreRewindContext* context, struct mCore* core) { context->currentState = nextState; #ifndef DISABLE_THREADING if (context->onThread) { + context->ready = true; ConditionWake(&context->cond); MutexUnlock(&context->mutex); return; @@ -121,6 +123,12 @@ bool mCoreRewindRestore(struct mCoreRewindContext* context, struct mCore* core) } --context->size; + mCoreLoadStateNamed(core, context->previousState, context->stateFlags); + if (context->current == 0) { + context->current = mCoreRewindPatchesSize(&context->patchMemory); + } + --context->current; + struct PatchFast* patch = mCoreRewindPatchesGetPointer(&context->patchMemory, context->current); size_t size2 = context->previousState->size(context->previousState); size_t size = context->currentState->size(context->currentState); @@ -129,18 +137,12 @@ bool mCoreRewindRestore(struct mCoreRewindContext* context, struct mCore* core) } void* current = context->currentState->map(context->currentState, size, MAP_READ); void* previous = context->previousState->map(context->previousState, size, MAP_WRITE); - patch->d.applyPatch(&patch->d, current, size, previous, size); + patch->d.applyPatch(&patch->d, previous, size, current, size); context->currentState->unmap(context->currentState, current, size); context->previousState->unmap(context->previousState, previous, size); - mCoreLoadStateNamed(core, context->previousState, context->stateFlags); struct VFile* nextState = context->previousState; context->previousState = context->currentState; context->currentState = nextState; - - if (context->current == 0) { - context->current = mCoreRewindPatchesSize(&context->patchMemory); - } - --context->current; #ifndef DISABLE_THREADING if (context->onThread) { MutexUnlock(&context->mutex); @@ -154,13 +156,12 @@ THREAD_ENTRY _rewindThread(void* context) { struct mCoreRewindContext* rewindContext = context; ThreadSetName("Rewind Diff Thread"); MutexLock(&rewindContext->mutex); - struct VFile* state = rewindContext->currentState; while (rewindContext->onThread) { - if (rewindContext->currentState != state) { - _rewindDiff(rewindContext); - state = rewindContext->currentState; + while (!rewindContext->ready) { + ConditionWait(&rewindContext->cond, &rewindContext->mutex); } - ConditionWait(&rewindContext->cond, &rewindContext->mutex); + _rewindDiff(rewindContext); + rewindContext->ready = false; } MutexUnlock(&rewindContext->mutex); return 0;