diff --git a/file.c b/file.c index aca4b595b8..b59735ba63 100644 --- a/file.c +++ b/file.c @@ -413,11 +413,14 @@ bool save_state(const char *path) } SSNES_LOG("State size: %d bytes.\n", (int)size); - psnes_serialize((uint8_t*)data, size); - bool ret = dump_to_file(path, data, size); - free(data); + bool ret = psnes_serialize((uint8_t*)data, size); + if (ret) + ret = dump_to_file(path, data, size); + if (!ret) SSNES_ERR("Failed to save state to \"%s\".\n", path); + + free(data); return ret; } @@ -426,86 +429,86 @@ bool load_state(const char *path) SSNES_LOG("Loading state: \"%s\".\n", path); void *buf = NULL; ssize_t size = read_file(path, &buf); + if (size < 0) { SSNES_ERR("Failed to load state from \"%s\".\n", path); return false; } - else + + bool ret = true; + SSNES_LOG("State size: %d bytes.\n", (int)size); + + uint8_t *block_buf[2] = {NULL, NULL}; + int block_type[2] = {-1, -1}; + unsigned block_size[2] = {0}; + + if (g_settings.block_sram_overwrite) { - SSNES_LOG("State size: %d bytes.\n", (int)size); - - uint8_t *block_buf[2] = {NULL, NULL}; - int block_type[2] = {-1, -1}; - unsigned block_size[2] = {0}; - - if (g_settings.block_sram_overwrite) + SSNES_LOG("Blocking SRAM overwrite!\n"); + switch (g_extern.game_type) { - SSNES_LOG("Blocking SRAM overwrite!\n"); - switch (g_extern.game_type) - { - case SSNES_CART_NORMAL: - block_type[0] = SNES_MEMORY_CARTRIDGE_RAM; - block_type[1] = SNES_MEMORY_CARTRIDGE_RTC; - break; + case SSNES_CART_NORMAL: + block_type[0] = SNES_MEMORY_CARTRIDGE_RAM; + block_type[1] = SNES_MEMORY_CARTRIDGE_RTC; + break; - case SSNES_CART_BSX: - case SSNES_CART_BSX_SLOTTED: - block_type[0] = SNES_MEMORY_BSX_RAM; - block_type[1] = SNES_MEMORY_BSX_PRAM; - break; + case SSNES_CART_BSX: + case SSNES_CART_BSX_SLOTTED: + block_type[0] = SNES_MEMORY_BSX_RAM; + block_type[1] = SNES_MEMORY_BSX_PRAM; + break; - case SSNES_CART_SUFAMI: - block_type[0] = SNES_MEMORY_SUFAMI_TURBO_A_RAM; - block_type[1] = SNES_MEMORY_SUFAMI_TURBO_B_RAM; - break; + case SSNES_CART_SUFAMI: + block_type[0] = SNES_MEMORY_SUFAMI_TURBO_A_RAM; + block_type[1] = SNES_MEMORY_SUFAMI_TURBO_B_RAM; + break; - case SSNES_CART_SGB: - block_type[0] = SNES_MEMORY_GAME_BOY_RAM; - block_type[1] = SNES_MEMORY_GAME_BOY_RTC; - break; - } + case SSNES_CART_SGB: + block_type[0] = SNES_MEMORY_GAME_BOY_RAM; + block_type[1] = SNES_MEMORY_GAME_BOY_RTC; + break; } - - for (unsigned i = 0; i < 2; i++) - if (block_type[i] != -1) - block_size[i] = psnes_get_memory_size(block_type[i]); - - for (unsigned i = 0; i < 2; i++) - if (block_size[i]) - block_buf[i] = (uint8_t*)malloc(block_size[i]); - - // Backup current SRAM which is overwritten by unserialize. - for (unsigned i = 0; i < 2; i++) - { - if (block_buf[i]) - { - const uint8_t *ptr = psnes_get_memory_data(block_type[i]); - if (ptr) - memcpy(block_buf[i], ptr, block_size[i]); - } - } - - psnes_unserialize((uint8_t*)buf, size); - - // Flush back :D - for (unsigned i = 0; i < 2; i++) - { - if (block_buf[i]) - { - uint8_t *ptr = psnes_get_memory_data(block_type[i]); - if (ptr) - memcpy(ptr, block_buf[i], block_size[i]); - } - } - - for (unsigned i = 0; i < 2; i++) - if (block_buf[i]) - free(block_buf[i]); } + for (unsigned i = 0; i < 2; i++) + if (block_type[i] != -1) + block_size[i] = psnes_get_memory_size(block_type[i]); + + for (unsigned i = 0; i < 2; i++) + if (block_size[i]) + block_buf[i] = (uint8_t*)malloc(block_size[i]); + + // Backup current SRAM which is overwritten by unserialize. + for (unsigned i = 0; i < 2; i++) + { + if (block_buf[i]) + { + const uint8_t *ptr = psnes_get_memory_data(block_type[i]); + if (ptr) + memcpy(block_buf[i], ptr, block_size[i]); + } + } + + ret = psnes_unserialize((uint8_t*)buf, size); + + // Flush back :D + for (unsigned i = 0; i < 2 && ret; i++) + { + if (block_buf[i]) + { + uint8_t *ptr = psnes_get_memory_data(block_type[i]); + if (ptr) + memcpy(ptr, block_buf[i], block_size[i]); + } + } + + for (unsigned i = 0; i < 2; i++) + if (block_buf[i]) + free(block_buf[i]); + free(buf); - return true; + return ret; } void load_ram_file(const char *path, int type) diff --git a/general.h b/general.h index b6246fa41b..8b6dd921a0 100644 --- a/general.h +++ b/general.h @@ -277,6 +277,7 @@ struct global // Rewind support. state_manager_t *state_manager; void *state_buf; + size_t state_size; bool frame_is_reverse; // Movie playback/recording support. diff --git a/ssnes.c b/ssnes.c index 70372c2c3d..b83080fc1a 100644 --- a/ssnes.c +++ b/ssnes.c @@ -1115,16 +1115,34 @@ static void deinit_cheats(void) static void init_rewind(void) { - if (g_settings.rewind_enable) + if (!g_settings.rewind_enable) + return; + + g_extern.state_size = psnes_serialize_size(); + + // Make sure we allocate at least 4-byte multiple. + size_t aligned_state_size = (g_extern.state_size + 3) & ~3; + g_extern.state_buf = calloc(1, aligned_state_size); + + if (!g_extern.state_buf) { - size_t serial_size = psnes_serialize_size(); - g_extern.state_buf = calloc(1, (serial_size + 3) & ~3); // Make sure we allocate at least 4-byte multiple. - psnes_serialize((uint8_t*)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 + 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"); + SSNES_ERR("Failed to allocate memory for rewind buffer!\n"); + return; } + + if (!psnes_serialize((uint8_t*)g_extern.state_buf, g_extern.state_size)) + { + SSNES_ERR("Failed to perform initial serialization for rewind!\n"); + free(g_extern.state_buf); + g_extern.state_buf = NULL; + return; + } + + SSNES_LOG("Initing rewind buffer with size: %u MB\n", (unsigned)(g_settings.rewind_buffer_size / 1000000)); + g_extern.state_manager = state_manager_new(aligned_state_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) @@ -1415,17 +1433,18 @@ static void check_savestates(void) else snprintf(save_path, sizeof(save_path), "%s", g_extern.savestate_name); - if (!save_state(save_path)) + char msg[512]; + if (save_state(save_path)) { msg_queue_clear(g_extern.msg_queue); - char msg[512]; - snprintf(msg, sizeof(msg), "Failed to save state to \"%s\"", save_path); - msg_queue_push(g_extern.msg_queue, msg, 2, 180); + snprintf(msg, sizeof(msg), "Saved state to slot #%u!", g_extern.state_slot); + msg_queue_push(g_extern.msg_queue, msg, 1, 180); } else { msg_queue_clear(g_extern.msg_queue); - msg_queue_push(g_extern.msg_queue, "Saved state!", 1, 180); + snprintf(msg, sizeof(msg), "Failed to save state to \"%s\"", save_path); + msg_queue_push(g_extern.msg_queue, msg, 2, 180); } } old_should_savestate = should_savestate; @@ -1441,17 +1460,18 @@ static void check_savestates(void) else snprintf(load_path, sizeof(load_path), "%s", g_extern.savestate_name); - if (!load_state(load_path)) + char msg[512]; + if (load_state(load_path)) { msg_queue_clear(g_extern.msg_queue); - char msg[512]; - snprintf(msg, sizeof(msg), "Failed to load state from \"%s\"", load_path); - msg_queue_push(g_extern.msg_queue, msg, 2, 180); + snprintf(msg, sizeof(msg), "Loaded state from slot #%u!", g_extern.state_slot); + msg_queue_push(g_extern.msg_queue, msg, 1, 180); } else { msg_queue_clear(g_extern.msg_queue); - msg_queue_push(g_extern.msg_queue, "Loaded state!", 1, 180); + snprintf(msg, sizeof(msg), "Failed to load state from \"%s\"", load_path); + msg_queue_push(g_extern.msg_queue, msg, 2, 180); } } old_should_loadstate = should_loadstate; @@ -1587,7 +1607,7 @@ static void check_rewind(void) setup_rewind_audio(); msg_queue_push(g_extern.msg_queue, "Rewinding!", 0, g_extern.is_paused ? 1 : 30); - psnes_unserialize((uint8_t*)buf, psnes_serialize_size()); + psnes_unserialize((uint8_t*)buf, g_extern.state_size); if (g_extern.bsv.movie) bsv_movie_frame_rewind(g_extern.bsv.movie); @@ -1601,7 +1621,7 @@ static void check_rewind(void) cnt = (cnt + 1) % (g_settings.rewind_granularity ? g_settings.rewind_granularity : 1); // Avoid possible SIGFPE. if (cnt == 0 || g_extern.bsv.movie) { - psnes_serialize((uint8_t*)g_extern.state_buf, psnes_serialize_size()); + psnes_serialize((uint8_t*)g_extern.state_buf, g_extern.state_size); state_manager_push(g_extern.state_manager, g_extern.state_buf); } }