Skip to content

Commit

Permalink
Fixes for SaveStates
Browse files Browse the repository at this point in the history
Backported from beetle-psx, using new api callback instead of RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE
libretro/beetle-psx-libretro@32fc5d3

RE:
* Savestate Performance Fix - no longer does giant memory allocations and copies
* Loadstate Performance Fix - no longer does N^2 string comparisons
* Fast Savestates (excludes text labels from the savestates, 20% speedup)
* Minor Savestate Performance Fix, no longer uses snprintf when strncpy will do.  Only applies to the text labels, no effect on fast savestates.
  • Loading branch information
negativeExponent committed Sep 15, 2024
1 parent b3308b5 commit a50c249
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 18 deletions.
17 changes: 16 additions & 1 deletion libretro.c
Original file line number Diff line number Diff line change
Expand Up @@ -1656,6 +1656,15 @@ int StateAction(StateMem *sm, int load, int data_only)
return ret;
}

static bool UsingFastSavestates(void)
{
int flags;
if (environ_cb(RETRO_ENVIRONMENT_GET_SAVESTATE_CONTEXT, &flags))
return ((flags == RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_INSTANCE) ||
((flags == RETRO_SAVESTATE_CONTEXT_RUNAHEAD_SAME_BINARY)));
return false;
}

size_t retro_serialize_size(void)
{
StateMem st;
Expand All @@ -1665,6 +1674,7 @@ size_t retro_serialize_size(void)
st.len = 0;
st.malloced = 0;
st.initial_malloc = 0;
st.fastsavestates = 0;

if (!PX68KSS_SaveSM(&st, 0, 0, NULL, NULL, NULL))
return 0;
Expand All @@ -1688,6 +1698,7 @@ bool retro_serialize(void *data, size_t size)
st.len = 0;
st.malloced = size;
st.initial_malloc = 0;
st.fastsavestates = UsingFastSavestates();

ret = PX68KSS_SaveSM(&st, 0, 0, NULL, NULL, NULL);

Expand All @@ -1700,14 +1711,18 @@ bool retro_serialize(void *data, size_t size)
bool retro_unserialize(const void *data, size_t size)
{
StateMem st;
bool ret = false;

st.data = (uint8_t*)data;
st.loc = 0;
st.len = size;
st.malloced = 0;
st.initial_malloc = 0;
st.fastsavestates = UsingFastSavestates();

ret = PX68KSS_LoadSM(&st, 0, 0);

return PX68KSS_LoadSM(&st, 0, 0);
return ret;
}

/* TODO/FIXME - implement cheats */
Expand Down
63 changes: 46 additions & 17 deletions libretro/state.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@ static bool SubWrite(StateMem *st, SFORMAT *sf)
while(sf->size || sf->name)
{
int32_t bytesize;
char nameo[1 + 256];

if(!sf->size || !sf->v)
{
Expand All @@ -228,9 +227,18 @@ static bool SubWrite(StateMem *st, SFORMAT *sf)
}

bytesize = sf->size;
nameo[0] = strlcpy(nameo + 1, sf->name, 256);

smem_write(st, nameo, 1 + nameo[0]);
/* exclude text labels from fast savestates */
if (!st->fastsavestates)
{
char nameo[1 + 256];
int slen = strlcpy(nameo + 1, sf->name, 255);
nameo[256] = 0;
nameo[0] = slen;

smem_write(st, nameo, 1 + nameo[0]);
}

smem_write32le(st, bytesize);

#ifdef MSB_FIRST
Expand Down Expand Up @@ -295,7 +303,8 @@ static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf)

smem_write(st, sname_tmp, 32);

smem_write32le(st, 0); // We'll come back and write this later.
/* We'll come back and write this later. */
smem_write32le(st, 0);

data_start_pos = st->loc;

Expand All @@ -311,7 +320,7 @@ static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf)
return(end_pos - data_start_pos);
}

static SFORMAT *FindSF(const char *name, SFORMAT *sf)
static SFORMAT *FindSF(const char *name, SFORMAT *sf, bool FastSaveStates)
{
/* Size can sometimes be zero, so also check for the text name.
* These two should both be zero only at the end of a struct. */
Expand All @@ -326,12 +335,18 @@ static SFORMAT *FindSF(const char *name, SFORMAT *sf)
/* Link to another SFORMAT structure. */
if (sf->size == (uint32_t)~0)
{
SFORMAT *temp_sf = FindSF(name, (SFORMAT*)sf->v);
SFORMAT *temp_sf = FindSF(name, (SFORMAT*)sf->v, FastSaveStates);
if (temp_sf)
return temp_sf;
}
else
{
/* for fast savestates, we no longer have the
* text label in the state, and need to assume
* that it is the correct one. */
if (FastSaveStates)
return sf;

if (!strcmp(sf->name, name))
return sf;
}
Expand All @@ -346,25 +361,39 @@ static int ReadStateChunk(StateMem *st, SFORMAT *sf, int size)
{
int temp = st->loc;

uint32_t recorded_size; /* In bytes */
uint8_t toa[1 + 256]; /* Don't change to char unless
cast toa[0] to unsigned to
smem_read() and other places. */
toa[0] = 0;
toa[1] = 0;

while (st->loc < (temp + size))
{
/* Don't change to char unless cast
* toa[0] to unsigned to smem_read()
* and other places. */
uint8_t toa[1 + 256];
uint32_t recorded_size = 0; /* In bytes */
SFORMAT *tmp = NULL;

if(smem_read(st, toa, 1) != 1)
return(0);
/* exclude text labels from fast savestates */
if (!st->fastsavestates)
{

if(smem_read(st, toa, 1) != 1)
return(0);

if(smem_read(st, toa + 1, toa[0]) != toa[0])
return 0;
if(smem_read(st, toa + 1, toa[0]) != toa[0])
return 0;

toa[1 + toa[0]] = 0;
toa[1 + toa[0]] = 0;
}

smem_read32le(st, &recorded_size);
tmp = FindSF((char*)toa + 1, sf);

tmp = FindSF((char*)toa + 1, sf, st->fastsavestates);

/* Fix for unnecessary name checks, when we find
* it in the first slot, don't recheck that slot again.
* Also necessary for fast savestates to work. */
if (tmp == sf)
sf++;

if(tmp)
{
Expand Down
5 changes: 5 additions & 0 deletions libretro/state.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ typedef struct
uint32_t len;
uint32_t malloced;
uint32_t initial_malloc; /* A setting! */

/* Fast Save States exclude string labels from variables in the savestate, and are at least 20% faster.
* Only used for internal savestates which will not be written to a file.
*/
bool fastsavestates;
} StateMem;

#ifdef __cplusplus
Expand Down

0 comments on commit a50c249

Please sign in to comment.