diff --git a/rewind.c b/rewind.c index 8d6c5644c8..486b43253c 100644 --- a/rewind.c +++ b/rewind.c @@ -20,6 +20,7 @@ #include #include #include +#include //#include @@ -43,6 +44,7 @@ state_manager_t *state_manager_new(size_t state_size, size_t buffer_size, void * if (!state) return NULL; + assert(state_size % 4 == 0); // We need 4-byte aligned state_size to avoid having to enforce this with unneeded memcpy's! state->top_ptr = 1; state->state_size = (state_size + 3) >> 2; // Multiple of 4. state->buf_size = (buffer_size + 7) >> 3; // Multiple of 8. @@ -50,8 +52,6 @@ state_manager_t *state_manager_new(size_t state_size, size_t buffer_size, void * goto error; if (!(state->tmp_state = calloc(1, state->state_size * sizeof(uint32_t)))) goto error; - if (!(state->scratch_buf = calloc(1, state->state_size * sizeof(uint32_t)))) - goto error; memcpy(state->tmp_state, init_buffer, state_size); @@ -62,7 +62,6 @@ error: { free(state->buffer); free(state->tmp_state); - free(state->scratch_buf); free(state); } return NULL; @@ -72,7 +71,6 @@ void state_manager_free(state_manager_t *state) { free(state->buffer); free(state->tmp_state); - free(state->scratch_buf); free(state); } @@ -120,14 +118,12 @@ static void reassign_bottom(state_manager_t *state) state->bottom_ptr = (state->bottom_ptr + 1) % state->buf_size; } -static void generate_delta(state_manager_t *state, const void *data, bool aligned) +static void generate_delta(state_manager_t *state, const void *data) { - unsigned patch_size = 0; + //unsigned patch_size = 0; bool crossed = false; const uint32_t *old_state = state->tmp_state; - uint32_t *new_state = aligned ? (uint32_t*)data : state->scratch_buf; - if (!aligned) - memcpy(new_state, data, state->state_size * sizeof(uint32_t)); // If not guaranteed to be aligned, we need to make sure it is. + const uint32_t *new_state = data; state->buffer[state->top_ptr++] = 0; // For each separate delta, we have a 0 value sentinel in between. if (state->top_ptr == state->bottom_ptr) // Check if top_ptr and bottom_ptr crossed eachother, which means we need to delete old cruft. @@ -141,7 +137,7 @@ static void generate_delta(state_manager_t *state, const void *data, bool aligne // This, if states don't really differ much, we'll save lots of space :) Hopefully this will work really well with save states. if (xor) { - patch_size++; + //patch_size++; state->buffer[state->top_ptr] = (i << 32) | xor; state->top_ptr = (state->top_ptr + 1) % state->buf_size; @@ -156,9 +152,9 @@ static void generate_delta(state_manager_t *state, const void *data, bool aligne //fprintf(stderr, "DELTA SIZE: %u, ORIG SIZE: %u\n", (unsigned)patch_size << 3, (unsigned)state->state_size << 2); } -bool state_manager_push(state_manager_t *state, const void *data, bool aligned) +bool state_manager_push(state_manager_t *state, const void *data) { - generate_delta(state, data, aligned); + generate_delta(state, data); memcpy(state->tmp_state, data, state->state_size * sizeof(uint32_t)); return true; diff --git a/rewind.h b/rewind.h index cf71effeb9..900909a92c 100644 --- a/rewind.h +++ b/rewind.h @@ -23,9 +23,11 @@ typedef struct state_manager state_manager_t; +// Always pass in at least 4-byte aligned data and sizes! + state_manager_t *state_manager_new(size_t state_size, size_t buffer_size, void *init_buffer); void state_manager_free(state_manager_t *state); bool state_manager_pop(state_manager_t *state, void **data); -bool state_manager_push(state_manager_t *state, const void *data, bool aligned); +bool state_manager_push(state_manager_t *state, const void *data); #endif diff --git a/ssnes.c b/ssnes.c index b27ad6844a..8c4090be56 100644 --- a/ssnes.c +++ b/ssnes.c @@ -646,10 +646,10 @@ static void init_rewind(void) if (g_settings.rewind_enable) { size_t serial_size = snes_serialize_size(); - g_extern.state_buf = malloc(serial_size); + g_extern.state_buf = malloc((serial_size + 3) & ~3); // Make sure we allocate at least 4-byte multiple. snes_serialize(g_extern.state_buf, serial_size); SSNES_LOG("Initing rewind buffer with size: %u MB\n", (unsigned)g_settings.rewind_buffer_size / 1000000); - g_extern.state_manager = state_manager_new(serial_size, g_settings.rewind_buffer_size, g_extern.state_buf); + g_extern.state_manager = state_manager_new((serial_size + 3) & ~3, g_settings.rewind_buffer_size, g_extern.state_buf); if (!g_extern.state_manager) SSNES_WARN("Failed to init rewind buffer. Rewinding will be disabled!\n"); } @@ -811,6 +811,8 @@ static void check_rewind(void) void *buf; if (state_manager_pop(g_extern.state_manager, &buf)) { + msg_queue_clear(g_extern.msg_queue); + msg_queue_push(g_extern.msg_queue, "Rewinding!", 0, 30); snes_unserialize(buf, snes_serialize_size()); g_extern.frame_is_reverse = true; } @@ -818,7 +820,7 @@ static void check_rewind(void) else { snes_serialize(g_extern.state_buf, snes_serialize_size()); - state_manager_push(g_extern.state_manager, g_extern.state_buf, true); + state_manager_push(g_extern.state_manager, g_extern.state_buf); } }