Simple rewind buffer

This commit is contained in:
Jeffrey Pfau 2014-01-26 02:50:28 -08:00
parent b1a648e46e
commit 705b6e9b13
6 changed files with 72 additions and 1 deletions

View File

@ -2,6 +2,7 @@
#include "gba-audio.h"
#include "gba-io.h"
#include "gba-thread.h"
#include "memory.h"
#include <fcntl.h>
@ -101,10 +102,41 @@ struct GBASerializedState* GBAMapState(int fd) {
return fileMemoryMap(fd, sizeof(struct GBASerializedState), MEMORY_WRITE);
}
struct GBASerializedState* GBAAloocateState(void) {
struct GBASerializedState* GBAAllocateState(void) {
return anonymousMemoryMap(sizeof(struct GBASerializedState));
}
void GBADeallocateState(struct GBASerializedState* state) {
mappedMemoryFree(state, sizeof(struct GBASerializedState));
}
void GBARecordFrame(struct GBAThread* thread) {
int offset = thread->rewindBufferWriteOffset;
struct GBASerializedState* state = thread->rewindBuffer[offset];
if (!state) {
state = GBAAllocateState();
thread->rewindBuffer[offset] = state;
}
GBASerialize(thread->gba, state);
thread->rewindBufferSize = thread->rewindBufferSize == thread->rewindBufferCapacity ? thread->rewindBufferCapacity : thread->rewindBufferSize + 1;
thread->rewindBufferWriteOffset = (offset + 1) % thread->rewindBufferSize;
}
void GBARewind(struct GBAThread* thread, int nStates) {
if (nStates > thread->rewindBufferSize || nStates < 0) {
nStates = thread->rewindBufferSize;
}
if (nStates == 0) {
return;
}
int offset = thread->rewindBufferWriteOffset - nStates;
if (offset < 0) {
offset += thread->rewindBufferSize;
}
struct GBASerializedState* state = thread->rewindBuffer[offset];
if (!state) {
return;
}
thread->rewindBufferSize -= nStates;
GBADeserialize(thread->gba, state);
}

View File

@ -233,4 +233,8 @@ struct GBASerializedState* GBAMapState(int fd);
struct GBASerializedState* GBAAllocateState(void);
void GBADeallocateState(struct GBASerializedState* state);
struct GBAThread;
void GBARecordFrame(struct GBAThread* thread);
void GBARewind(struct GBAThread* thread, int nStates);
#endif

View File

@ -3,6 +3,7 @@
#include "arm.h"
#include "debugger.h"
#include "gba.h"
#include "gba-serialize.h"
#include <stdlib.h>
#include <signal.h>
@ -157,6 +158,12 @@ int GBAThreadStart(struct GBAThread* threadContext) {
threadContext->sync.videoFrameOn = 1;
threadContext->sync.videoFrameSkip = 0;
threadContext->rewindBufferNext = threadContext->rewindBufferInterval;
threadContext->rewindBufferSize = 0;
if (threadContext->rewindBufferCapacity) {
threadContext->rewindBuffer = calloc(threadContext->rewindBufferCapacity, sizeof(void*));
}
MutexInit(&threadContext->stateMutex);
ConditionInit(&threadContext->stateCond);
@ -204,6 +211,14 @@ void GBAThreadJoin(struct GBAThread* threadContext) {
ConditionWake(&threadContext->sync.audioRequiredCond);
ConditionDeinit(&threadContext->sync.audioRequiredCond);
MutexDeinit(&threadContext->sync.audioBufferMutex);
int i;
for (i = 0; i < threadContext->rewindBufferCapacity; ++i) {
if (threadContext->rewindBuffer[i]) {
GBADeallocateState(threadContext->rewindBuffer[i]);
}
}
free(threadContext->rewindBuffer);
}
void GBAThreadPause(struct GBAThread* threadContext) {
@ -293,6 +308,13 @@ void GBASyncPostFrame(struct GBASync* sync) {
MutexUnlock(&sync->videoFrameMutex);
struct GBAThread* thread = GBAThreadGetContext();
if (thread->rewindBuffer) {
--thread->rewindBufferNext;
if (thread->rewindBufferNext <= 0) {
thread->rewindBufferNext = thread->rewindBufferInterval;
GBARecordFrame(thread);
}
}
if (thread->frameCallback) {
thread->frameCallback(thread);
}

View File

@ -52,6 +52,13 @@ struct GBAThread {
Condition audioRequiredCond;
Mutex audioBufferMutex;
} sync;
int rewindBufferSize;
int rewindBufferCapacity;
int rewindBufferInterval;
int rewindBufferNext;
struct GBASerializedState** rewindBuffer;
int rewindBufferWriteOffset;
};
int GBAThreadStart(struct GBAThread* threadContext);

View File

@ -80,6 +80,8 @@ int main(int argc, char** argv) {
context.cleanCallback = _GBASDLClean;
context.frameCallback = 0;
context.userData = &renderer;
context.rewindBufferCapacity = 10;
context.rewindBufferInterval = 30;
GBAThreadStart(&context);
_GBASDLRunloop(&context, &renderer);

View File

@ -68,6 +68,10 @@ static void _GBASDLHandleKeypress(struct GBAThread* context, const struct SDL_Ke
case SDLK_TAB:
context->sync.audioWait = event->type != SDL_KEYDOWN;
return;
case SDLK_LEFTBRACKET:
GBAThreadPause(context);
GBARewind(context, 10);
GBAThreadUnpause(context);
default:
if (event->type == SDL_KEYDOWN) {
if (event->keysym.mod & KMOD_CTRL) {