diff --git a/config.def.h b/config.def.h index a9089376c7..5b13d609ea 100644 --- a/config.def.h +++ b/config.def.h @@ -146,6 +146,13 @@ static const bool audio_sync = true; // Defines the quality (and cpu reqirements) of samplerate conversion. #define SAMPLERATE_QUALITY SRC_LINEAR +// Enables use of rewind. This will incur some memory footprint depending on the save state buffer. +// This rewind only works when using bSNES core atm. +static const bool rewind_enable = false; + +// The buffer size for the rewind buffer. This needs to be about 15-20MB per minute. Very game dependant. +static const unsigned rewind_buffer_size = 20 << 20; // 20MiB + diff --git a/general.h b/general.h index 57aeae83eb..e6d9cbbaa7 100644 --- a/general.h +++ b/general.h @@ -85,6 +85,9 @@ struct settings } input; char libsnes[256]; + + bool rewind_enable; + unsigned rewind_buffer_size; }; enum ssnes_game_type diff --git a/settings.c b/settings.c index e2b7c444a9..0601a88c3e 100644 --- a/settings.c +++ b/settings.c @@ -124,6 +124,9 @@ static void set_defaults(void) g_settings.audio.sync = audio_sync; g_settings.audio.src_quality = SAMPLERATE_QUALITY; + g_settings.rewind_enable = rewind_enable; + g_settings.rewind_buffer_size = rewind_buffer_size; + assert(sizeof(g_settings.input.binds[0]) >= sizeof(snes_keybinds_1)); assert(sizeof(g_settings.input.binds[1]) >= sizeof(snes_keybinds_2)); assert(sizeof(g_settings.input.binds[2]) >= sizeof(snes_keybinds_3)); @@ -372,6 +375,12 @@ static void parse_config_file(void) free(tmp_str); } + if (config_get_bool(conf, "rewind_enable", &tmp_bool)) + g_settings.rewind_enable = true; + + if (config_get_int(conf, "rewind_buffer_size", &tmp_int)) + g_settings.rewind_buffer_size = tmp_int * 1000000; + read_keybinds(conf); config_file_free(conf); @@ -411,6 +420,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY) DECLARE_BIND(rate_step_up, SSNES_AUDIO_INPUT_RATE_PLUS) DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS) + DECLARE_BIND(rewind, SSNES_REWIND) }, { DECLARE_BIND(player2_a, SNES_DEVICE_ID_JOYPAD_A) @@ -434,6 +444,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY) DECLARE_BIND(rate_step_up, SSNES_AUDIO_INPUT_RATE_PLUS) DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS) + DECLARE_BIND(rewind, SSNES_REWIND) }, { DECLARE_BIND(player3_a, SNES_DEVICE_ID_JOYPAD_A) @@ -457,6 +468,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY) DECLARE_BIND(rate_step_up, SSNES_AUDIO_INPUT_RATE_PLUS) DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS) + DECLARE_BIND(rewind, SSNES_REWIND) }, { DECLARE_BIND(player4_a, SNES_DEVICE_ID_JOYPAD_A) @@ -480,6 +492,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY) DECLARE_BIND(rate_step_up, SSNES_AUDIO_INPUT_RATE_PLUS) DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS) + DECLARE_BIND(rewind, SSNES_REWIND) }, { DECLARE_BIND(player5_a, SNES_DEVICE_ID_JOYPAD_A) @@ -503,6 +516,7 @@ static const struct bind_map bind_maps[MAX_PLAYERS][MAX_BINDS - 1] = { DECLARE_BIND(toggle_fullscreen, SSNES_FULLSCREEN_TOGGLE_KEY) DECLARE_BIND(rate_step_up, SSNES_AUDIO_INPUT_RATE_PLUS) DECLARE_BIND(rate_step_down, SSNES_AUDIO_INPUT_RATE_MINUS) + DECLARE_BIND(rewind, SSNES_REWIND) }, }; diff --git a/ssnes.c b/ssnes.c index 79a2e56bc4..b27ad6844a 100644 --- a/ssnes.c +++ b/ssnes.c @@ -643,10 +643,16 @@ static void deinit_msg_queue(void) 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); + if (g_settings.rewind_enable) + { + size_t serial_size = snes_serialize_size(); + g_extern.state_buf = malloc(serial_size); + 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); + if (!g_extern.state_manager) + SSNES_WARN("Failed to init rewind buffer. Rewinding will be disabled!\n"); + } } static void deinit_rewind(void) diff --git a/ssnes.cfg b/ssnes.cfg index 1155336b69..d74ffb4c70 100644 --- a/ssnes.cfg +++ b/ssnes.cfg @@ -190,3 +190,15 @@ # Decrease/increase input sample rate on the fly. Amount to decrease/increase is defined by audio_rate_step. # input_rate_step_up = kp_plus # input_rate_step_down = kp_minus + +# Enable rewinding. This will take a performance hit when playing, so it is disabled by default. +# Do note that rewinding will only work properly when using bSNES libsnes core atm. +# rewind_enable = false + +# Rewinding buffer size in megabytes. Bigger rewinding buffer means you can rewind longer. +# The buffer should be approx. 20MB per minute of buffer time. +# rewind_buffer_size = 20 + +# Hold button down to rewind. Rewinding must be enabled. +# input_rewind = r +