summaryrefslogtreecommitdiff
path: root/libpcsxcore
diff options
context:
space:
mode:
authorSND\ckain_cp <SND\ckain_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2014-01-24 13:59:46 +0000
committerSND\ckain_cp <SND\ckain_cp@e17a0e51-4ae3-4d35-97c3-1a29b211df97>2014-01-24 13:59:46 +0000
commite1108dba69ad14fed7bc64f996ea09342c900a81 (patch)
treea3798c4031cce49eeb5964ec9ae49a9627bc5a91 /libpcsxcore
parent47b0777b946e413500bc0420d91298aa4e8f8301 (diff)
downloadpcsxr-e1108dba69ad14fed7bc64f996ea09342c900a81.tar.gz
Added rewind feature. Currently only supported via GTK and needs SHM. Rewind save state depth is configured via RewindCount config param. Recommended value is 200 or so -> uses less than 1G of memory
git-svn-id: https://pcsxr.svn.codeplex.com/svn/pcsxr@88433 e17a0e51-4ae3-4d35-97c3-1a29b211df97
Diffstat (limited to 'libpcsxcore')
-rwxr-xr-xlibpcsxcore/misc.c177
-rwxr-xr-xlibpcsxcore/misc.h8
-rwxr-xr-xlibpcsxcore/psxcommon.h1
3 files changed, 156 insertions, 30 deletions
diff --git a/libpcsxcore/misc.c b/libpcsxcore/misc.c
index 7918466a..34da0ed5 100755
--- a/libpcsxcore/misc.c
+++ b/libpcsxcore/misc.c
@@ -499,7 +499,8 @@ int Load(const char *ExePath) {
}
// STATES
-
+static const u8 PCSXR_HEADER_SZ = 10U;
+static const u32 SZ_GPUPIC = 128 * 96 * 3;
static const char PcsxrHeader[32] = "STv4 PCSXR v" PACKAGE_VERSION;
// Savestate Versioning!
@@ -508,23 +509,143 @@ static const u32 SaveVersion = 0x8b410008;
int SaveState(const char *file) {
gzFile f;
- GPUFreeze_t *gpufP;
+ long size;
+
+ f = gzopen(file, "wb9"); // Best ratio but slow
+ if (f == NULL) return -1;
+ return SaveStateGz(f, &size);
+}
+
+int LoadState(const char *file) {
+ gzFile f;
+
+ f = gzopen(file, "rb");
+ if (f == NULL) return -1;
+ return LoadStateGz(f);
+}
+
+u32 mem_cur_save_count=0, mem_last_save;
+boolean mem_wrapped=FALSE; // Whether we went past max count and restarted counting
+
+void CreateRewindState() {
+ SaveStateMem(mem_last_save=mem_cur_save_count++);
+
+ if (mem_cur_save_count > Config.RewindCount) {
+ mem_cur_save_count = 0;
+ mem_wrapped=TRUE;
+ }
+}
+
+void RewindState() {
+ mem_cur_save_count--;
+ if (mem_cur_save_count > Config.RewindCount && mem_wrapped) {
+ mem_cur_save_count = Config.RewindCount;
+ mem_wrapped = FALSE;
+ } else if (mem_cur_save_count > Config.RewindCount && !mem_wrapped) {
+ mem_cur_save_count++;
+ return;
+ } else if (mem_last_save == mem_cur_save_count-1) {
+ mem_cur_save_count = 0;
+ return;
+ }
+ LoadStateMem(mem_cur_save_count);
+}
+
+/*
+
+Pros of using SHM
++ No need to change SaveState interface (gzip OK)
++ Possibiliy to preserve saves after pcsxr crash
+
+Cons of using SHM
+- UNIX only
+- Possibility of leaving left over shm files
+- Possibly not the quickest way to allocate memory
+
+*/
+#ifndef NO_RT_SHM
+#include <sys/mman.h>
+#include <sys/stat.h> /* For mode constants */
+#include <fcntl.h> /* For O_* constants */
+#include <errno.h>
+
+#define SHM_SS_NAME_TEMPLATE "/pcsxrmemsavestate%.4u"
+
+int SaveStateMem(const u32 id) {
+ char name[32];
+ int ret = -1;
+
+ snprintf(name, 32, SHM_SS_NAME_TEMPLATE, id);
+ int fd = shm_open(name, O_CREAT | O_RDWR | O_TRUNC, 0666);
+
+ if (fd >= 0) {
+ gzFile f = gzdopen(fd, "wb0R"); // Fast and no compression
+ if (f != NULL) {
+ long size;
+ ret = SaveStateGz(f, &size);
+ //printf("Saved %s/%i (ID: %i SZ: %lik)\n", name, fd, id, size/1024);
+ } else {
+ SysMessage("GZ OPEN FAIL %i\n", errno );
+ }
+ } else {
+ SysMessage("FD OPEN FAIL %i\n", errno );
+ }
+ return ret;
+}
+
+int LoadStateMem(const u32 id) {
+ char name[32];
+ int ret = -1;
+
+ snprintf(name, 32, SHM_SS_NAME_TEMPLATE, id);
+ int fd = shm_open(name, O_RDONLY, 0444);
+
+ if (fd >= 0) {
+ gzFile f = gzdopen(fd, "rb");
+ if (f != NULL) {
+ ret = LoadStateGz(f);
+ //printf("Loaded %s/%i (ID: %i RET: %i)\n", name, fd, id, ret);
+ shm_unlink(name);
+ } else {
+ SysMessage("GZ OPEN FAIL %i\n", errno);
+ }
+ } else {
+ SysMessage("FD OPEN FAIL %i (%s)\n", errno, name);
+ }
+ return ret;
+}
+
+void CleanupMemSaveStates() {
+ char name[32];
+ u32 i;
+
+ for (i=0; i <= Config.RewindCount; i++) {
+ snprintf(name, sizeof(name), SHM_SS_NAME_TEMPLATE, i);
+ if (shm_unlink(name) != 0) {
+ //break;
+ }
+ }
+}
+#else
+int SaveStateMem(const u32 id) {return 0;}
+int LoadStateMem(const u32 id) {return 0;}
+void CleanupMemSaveStates() {}
+#endif
+
+int SaveStateGz(gzFile f, long* gzsize) {
+ GPUFreeze_t gpufP;
SPUFreeze_t *spufP;
int Size;
- unsigned char *pMem;
+ unsigned char pMemGpuPic[SZ_GPUPIC], pMemSpuT[16];
- f = gzopen(file, "wb");
if (f == NULL) return -1;
- gzwrite(f, (void *)PcsxrHeader, 32);
+ gzwrite(f, (void *)PcsxrHeader, sizeof(PcsxrHeader));
gzwrite(f, (void *)&SaveVersion, sizeof(u32));
gzwrite(f, (void *)&Config.HLE, sizeof(boolean));
- pMem = (unsigned char *)malloc(128 * 96 * 3);
- if (pMem == NULL) return -1;
- GPU_getScreenPic(pMem);
- gzwrite(f, pMem, 128 * 96 * 3);
- free(pMem);
+ GPU_getScreenPic(pMemGpuPic);
+ gzwrite(f, pMemGpuPic, SZ_GPUPIC);
if (Config.HLE)
psxBiosFreeze(1);
@@ -535,19 +656,16 @@ int SaveState(const char *file) {
gzwrite(f, (void *)&psxRegs, sizeof(psxRegs));
// gpu
- gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
- gpufP->ulFreezeVersion = 1;
- GPU_freeze(1, gpufP);
- gzwrite(f, gpufP, sizeof(GPUFreeze_t));
- free(gpufP);
+ gpufP.ulFreezeVersion = 1;
+ GPU_freeze(1, &gpufP);
+ gzwrite(f, &gpufP, sizeof(GPUFreeze_t));
// spu
- spufP = (SPUFreeze_t *) malloc(16); // only first 3 elements (up to Size)
+ spufP = (SPUFreeze_t *)pMemSpuT; // only first 3 elements (up to Size)
SPU_freeze(2, spufP);
Size = spufP->Size; gzwrite(f, &Size, 4);
if (Size <= 0)
return 1; // error
- free(spufP);
spufP = (SPUFreeze_t *) malloc(Size);
SPU_freeze(1, spufP);
gzwrite(f, spufP, Size);
@@ -559,34 +677,34 @@ int SaveState(const char *file) {
psxRcntFreeze(f, 1);
mdecFreeze(f, 1);
+ *gzsize = gztell(f);
gzclose(f);
return 0;
}
-int LoadState(const char *file) {
- gzFile f;
- GPUFreeze_t *gpufP;
+int LoadStateGz(gzFile f) {
+ GPUFreeze_t gpufP;
SPUFreeze_t *spufP;
int Size;
- char header[32];
+ char header[sizeof(PcsxrHeader)];
u32 version;
boolean hle;
- f = gzopen(file, "rb");
if (f == NULL) return -1;
gzread(f, header, sizeof(header));
gzread(f, &version, sizeof(u32));
gzread(f, &hle, sizeof(boolean));
- if (strncmp("STv4 PCSXR", header, 10) != 0 || version != SaveVersion || hle != Config.HLE) {
+ // Compare header only "STv4 PCSXR" part no version
+ if (strncmp(PcsxrHeader, header, PCSXR_HEADER_SZ) != 0 || version != SaveVersion || hle != Config.HLE) {
gzclose(f);
return -1;
}
psxCpu->Reset();
- gzseek(f, 128 * 96 * 3, SEEK_CUR);
+ gzseek(f, SZ_GPUPIC, SEEK_CUR);
gzread(f, psxM, 0x00200000);
gzread(f, psxR, 0x00080000);
@@ -597,10 +715,8 @@ int LoadState(const char *file) {
psxBiosFreeze(0);
// gpu
- gpufP = (GPUFreeze_t *)malloc(sizeof(GPUFreeze_t));
- gzread(f, gpufP, sizeof(GPUFreeze_t));
- GPU_freeze(0, gpufP);
- free(gpufP);
+ gzread(f, &gpufP, sizeof(GPUFreeze_t));
+ GPU_freeze(0, &gpufP);
// spu
gzread(f, &Size, 4);
@@ -622,7 +738,7 @@ int LoadState(const char *file) {
int CheckState(const char *file) {
gzFile f;
- char header[32];
+ char header[sizeof(PcsxrHeader)];
u32 version;
boolean hle;
@@ -635,7 +751,8 @@ int CheckState(const char *file) {
gzclose(f);
- if (strncmp("STv4 PCSXR", header, 10) != 0 || version != SaveVersion || hle != Config.HLE)
+ // Compare header only "STv4 PCSXR" part no version
+ if (strncmp(PcsxrHeader, header, PCSXR_HEADER_SZ) != 0 || version != SaveVersion || hle != Config.HLE)
return -1;
return 0;
diff --git a/libpcsxcore/misc.h b/libpcsxcore/misc.h
index 626cf5c5..860c1d29 100755
--- a/libpcsxcore/misc.h
+++ b/libpcsxcore/misc.h
@@ -62,12 +62,20 @@ int CheckCdrom();
int Load(const char *ExePath);
int SaveState(const char *file);
+int SaveStateMem(const u32 id);
+int SaveStateGz(gzFile f, long* gzsize);
int LoadState(const char *file);
+int LoadStateMem(const u32 id);
+int LoadStateGz(gzFile f);
int CheckState(const char *file);
int SendPcsxInfo();
int RecvPcsxInfo();
+void CreateRewindState(); // Creates save state and stores it to volatile memory
+void RewindState(); // Restores state previously created with CreateRewindState();
+void CleanupMemSaveStates(); // Removes all save states stored by memory funcs like CreateRewindState()
+
void trim(char *str);
u16 calcCrc(u8 *d, int len);
diff --git a/libpcsxcore/psxcommon.h b/libpcsxcore/psxcommon.h
index bd12ef51..16428115 100755
--- a/libpcsxcore/psxcommon.h
+++ b/libpcsxcore/psxcommon.h
@@ -157,6 +157,7 @@ typedef struct {
s32 WindowPos[2];
u8 Cpu; // CPU_DYNAREC or CPU_INTERPRETER
u8 PsxType; // PSX_TYPE_NTSC or PSX_TYPE_PAL
+ u32 RewindCount;
#ifdef _WIN32
char Lang[256];
#endif