From 351e098da1b01b2764dc2f53e433e7f1e6aadd57 Mon Sep 17 00:00:00 2001 From: Themaister Date: Mon, 31 Jan 2011 16:48:42 +0100 Subject: [PATCH] Basic rewind works! --- Makefile.win32 | 2 +- config.def.h | 1 + driver.h | 1 + general.h | 7 ++++++- rewind.c | 6 ++++++ ssnes.c | 38 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Makefile.win32 b/Makefile.win32 index 22f30ecf06..48e09e0066 100644 --- a/Makefile.win32 +++ b/Makefile.win32 @@ -1,6 +1,6 @@ TARGET = ssnes.exe JTARGET = ssnes-joyconfig.exe -OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o +OBJ = ssnes.o file.o driver.o conf/config_file.o settings.o dynamic.o message.o rewind.o JOBJ = conf/config_file.o tools/main-stub.o tools/ssnes-joyconfig.o CC = gcc diff --git a/config.def.h b/config.def.h index a8623bc6f6..a9089376c7 100644 --- a/config.def.h +++ b/config.def.h @@ -184,6 +184,7 @@ static const struct snes_keybind snes_keybinds_1[] = { { SSNES_STATE_SLOT_PLUS, SDLK_F7, NO_BTN, AXIS_NONE }, { SSNES_AUDIO_INPUT_RATE_PLUS, SDLK_KP_PLUS, NO_BTN, AXIS_NONE }, { SSNES_AUDIO_INPUT_RATE_MINUS, SDLK_KP_MINUS, NO_BTN, AXIS_NONE }, + { SSNES_REWIND, SDLK_r, NO_BTN, AXIS_NONE }, { -1 } }; diff --git a/driver.h b/driver.h index 0149ffb6ef..7bc8a364a8 100644 --- a/driver.h +++ b/driver.h @@ -36,6 +36,7 @@ enum SSNES_STATE_SLOT_MINUS, SSNES_AUDIO_INPUT_RATE_PLUS, SSNES_AUDIO_INPUT_RATE_MINUS, + SSNES_REWIND, }; struct snes_keybind diff --git a/general.h b/general.h index c60f237e9e..3116be1377 100644 --- a/general.h +++ b/general.h @@ -24,6 +24,7 @@ #include #include "record/ffemu.h" #include "message.h" +#include "rewind.h" #ifdef HAVE_CONFIG_H #include "config.h" @@ -35,7 +36,7 @@ #define MAX_PLAYERS 5 -#define MAX_BINDS 22 // Needs to be increased every time there are new binds added. +#define MAX_BINDS 23 // Needs to be increased every time there are new binds added. #define SSNES_NO_JOYPAD 0xFFFF struct settings { @@ -145,6 +146,10 @@ struct global msg_queue_t *msg_queue; + state_manager_t *state_manager; + void *state_buf; + bool rewind_enable; + #ifdef HAVE_FFMPEG ffemu_t *rec; char record_path[256]; diff --git a/rewind.c b/rewind.c index a4e4943b3d..8d6c5644c8 100644 --- a/rewind.c +++ b/rewind.c @@ -21,6 +21,8 @@ #include #include +//#include + struct state_manager { uint64_t *buffer; @@ -120,6 +122,7 @@ static void reassign_bottom(state_manager_t *state) static void generate_delta(state_manager_t *state, const void *data, bool aligned) { + 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; @@ -138,6 +141,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++; state->buffer[state->top_ptr] = (i << 32) | xor; state->top_ptr = (state->top_ptr + 1) % state->buf_size; @@ -148,6 +152,8 @@ static void generate_delta(state_manager_t *state, const void *data, bool aligne if (crossed) reassign_bottom(state); + + //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) diff --git a/ssnes.c b/ssnes.c index 717a36c3ee..fb78155adf 100644 --- a/ssnes.c +++ b/ssnes.c @@ -28,6 +28,7 @@ #include "general.h" #include "dynamic.h" #include "record/ffemu.h" +#include "rewind.h" #include #ifdef HAVE_SRC #include @@ -636,6 +637,22 @@ static void deinit_msg_queue(void) msg_queue_free(g_extern.msg_queue); } +static void init_rewind(void) +{ + size_t serial_size = snes_serialize_size(); + g_extern.state_buf = malloc(serial_size); + snes_serialize(g_extern.state_buf, serial_size); + g_extern.state_manager = state_manager_new(serial_size, 10 << 20, g_extern.state_buf); +} + +static void deinit_rewind(void) +{ + if (g_extern.state_manager) + state_manager_free(g_extern.state_manager); + if (g_extern.state_buf) + free(g_extern.state_buf); +} + static void fill_pathnames(void) { switch (g_extern.game_type) @@ -773,6 +790,24 @@ static void check_input_rate(void) } } +static void check_rewind(void) +{ + if (!g_extern.state_manager) + return; + + if (driver.input->key_pressed(driver.input_data, SSNES_REWIND)) + { + void *buf; + if (state_manager_pop(g_extern.state_manager, &buf)) + snes_unserialize(buf, snes_serialize_size()); + } + else + { + snes_serialize(g_extern.state_buf, snes_serialize_size()); + state_manager_push(g_extern.state_manager, g_extern.state_buf, true); + } +} + static void do_state_checks(void) { set_fast_forward_button(driver.input->key_pressed(driver.input_data, SSNES_FAST_FORWARD_KEY)); @@ -781,6 +816,7 @@ static void do_state_checks(void) check_savestates(); check_fullscreen(); check_input_rate(); + check_rewind(); } @@ -817,6 +853,7 @@ int main(int argc, char *argv[]) #endif init_msg_queue(); + init_rewind(); // Main loop for(;;) @@ -833,6 +870,7 @@ int main(int argc, char *argv[]) psnes_run(); } + deinit_rewind(); deinit_msg_queue(); #ifdef HAVE_FFMPEG deinit_recording();