static uint32_t *bsv_header_generate(size_t *size, uint32_t magic) { uint32_t bsv_header[4] = {0}; size_t serialize_size = pretro_serialize_size(); size_t header_size = sizeof(bsv_header) + serialize_size; *size = header_size; uint32_t *header = (uint32_t*)malloc(header_size); if (!header) return NULL; bsv_header[MAGIC_INDEX] = swap_if_little32(BSV_MAGIC); bsv_header[SERIALIZER_INDEX] = swap_if_big32(magic); bsv_header[CRC_INDEX] = swap_if_big32(g_extern.cart_crc); bsv_header[STATE_SIZE_INDEX] = swap_if_big32(serialize_size); if (serialize_size && !pretro_serialize(header + 4, serialize_size)) { free(header); return NULL; } memcpy(header, bsv_header, sizeof(bsv_header)); return header; }
bool save_state(const char *path) { RARCH_LOG("Saving state: \"%s\".\n", path); size_t size = pretro_serialize_size(); if (size == 0) return false; void *data = malloc(size); if (!data) { RARCH_ERR("Failed to allocate memory for save state buffer.\n"); return false; } RARCH_LOG("State size: %d bytes.\n", (int)size); bool ret = pretro_serialize(data, size); if (ret) ret = write_file(path, data, size); if (!ret) RARCH_ERR("Failed to save state to \"%s\".\n", path); free(data); return ret; }
static void netplay_pre_frame_net(netplay_t *handle) { pretro_serialize(handle->buffer[handle->self_ptr].state, handle->state_size); handle->can_poll = true; input_poll_net(); }
void bsv_movie_frame_rewind(bsv_movie_t *handle) { handle->did_rewind = true; // If we're at the beginning ... :) if ((handle->frame_ptr <= 1) && (handle->frame_pos[0] == handle->min_file_pos)) { handle->frame_ptr = 0; fseek(handle->file, handle->min_file_pos, SEEK_SET); } else { // First time rewind is performed, the old frame is simply replayed. // However, playing back that frame caused us to read data, and push data to the ring buffer. // Sucessively rewinding frames, we need to rewind past the read data, plus another. handle->frame_ptr = (handle->frame_ptr - (handle->first_rewind ? 1 : 2)) & handle->frame_mask; fseek(handle->file, handle->frame_pos[handle->frame_ptr], SEEK_SET); } // We rewound past the beginning. :O if (ftell(handle->file) <= (long)handle->min_file_pos) { // If recording, we simply reset the starting point. Nice and easy. if (!handle->playback) { fseek(handle->file, 4 * sizeof(uint32_t), SEEK_SET); pretro_serialize(handle->state, handle->state_size); fwrite(handle->state, 1, handle->state_size, handle->file); } else fseek(handle->file, handle->min_file_pos, SEEK_SET); } }
static void netplay_post_frame_net(netplay_t *handle) { handle->frame_count++; // Nothing to do... if (handle->other_frame_count == handle->read_frame_count) return; // Skip ahead if we predicted correctly. Skip until our simulation failed. while (handle->other_frame_count < handle->read_frame_count) { const struct delta_frame *ptr = &handle->buffer[handle->other_ptr]; if ((ptr->simulated_input_state != ptr->real_input_state) && !ptr->used_real) break; handle->other_ptr = NEXT_PTR(handle->other_ptr); handle->other_frame_count++; } if (handle->other_frame_count < handle->read_frame_count) { // Replay frames handle->is_replay = true; handle->tmp_ptr = handle->other_ptr; handle->tmp_frame_count = handle->other_frame_count; pretro_unserialize(handle->buffer[handle->other_ptr].state, handle->state_size); bool first = true; while (first || (handle->tmp_ptr != handle->self_ptr)) { pretro_serialize(handle->buffer[handle->tmp_ptr].state, handle->state_size); #if defined(HAVE_THREADS) && !defined(RARCH_CONSOLE) lock_autosave(); #endif pretro_run(); #if defined(HAVE_THREADS) && !defined(RARCH_CONSOLE) unlock_autosave(); #endif handle->tmp_ptr = NEXT_PTR(handle->tmp_ptr); handle->tmp_frame_count++; first = false; } handle->other_ptr = handle->read_ptr; handle->other_frame_count = handle->read_frame_count; handle->is_replay = false; } }
/** * save_state: * @path : path of saved state that shall be written to. * * Save a state from memory to disk. * * Returns: true if successful, false otherwise. **/ bool save_state(const char *path) { bool ret = false; void *data = NULL; size_t size = pretro_serialize_size(); RARCH_LOG("%s: \"%s\".\n", msg_hash_to_str(MSG_SAVING_STATE), path); if (size == 0) return false; data = malloc(size); if (!data) return false; RARCH_LOG("%s: %d %s.\n", msg_hash_to_str(MSG_STATE_SIZE), (int)size, msg_hash_to_str(MSG_BYTES)); ret = pretro_serialize(data, size); if (ret) ret = retro_write_file(path, data, size); if (!ret) RARCH_ERR("%s \"%s\".\n", msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO), path); free(data); return ret; }
static bool init_record(bsv_movie_t *handle, const char *path) { handle->file = fopen(path, "wb"); if (!handle->file) { RARCH_ERR("Couldn't open BSV \"%s\" for recording.\n", path); return false; } uint32_t header[4] = {0}; // This value is supposed to show up as BSV1 in a HEX editor, big-endian. header[MAGIC_INDEX] = swap_if_little32(BSV_MAGIC); header[CRC_INDEX] = swap_if_big32(g_extern.cart_crc); uint32_t state_size = pretro_serialize_size(); header[STATE_SIZE_INDEX] = swap_if_big32(state_size); fwrite(header, 4, sizeof(uint32_t), handle->file); handle->min_file_pos = sizeof(header) + state_size; handle->state_size = state_size; if (state_size) { handle->state = (uint8_t*)malloc(state_size); if (!handle->state) return false; pretro_serialize(handle->state, state_size); fwrite(handle->state, 1, state_size, handle->file); } return true; }
/** * check_rewind: * @pressed : was rewind key pressed or held? * * Checks if rewind toggle/hold was being pressed and/or held. **/ static void check_rewind(settings_t *settings, global_t *global, runloop_t *runloop, bool pressed) { static bool first = true; if (global->rewind.frame_is_reverse) { audio_driver_frame_is_reverse(); global->rewind.frame_is_reverse = false; } if (first) { first = false; return; } if (!global->rewind.state) return; if (pressed) { const void *buf = NULL; if (state_manager_pop(global->rewind.state, &buf)) { global->rewind.frame_is_reverse = true; audio_driver_setup_rewind(); rarch_main_msg_queue_push_new(MSG_REWINDING, 0, runloop->is_paused ? 1 : 30, true); pretro_unserialize(buf, global->rewind.size); if (global->bsv.movie) bsv_movie_frame_rewind(global->bsv.movie); } else rarch_main_msg_queue_push_new(MSG_REWIND_REACHED_END, 0, 30, true); } else { static unsigned cnt = 0; cnt = (cnt + 1) % (settings->rewind_granularity ? settings->rewind_granularity : 1); /* Avoid possible SIGFPE. */ if ((cnt == 0) || global->bsv.movie) { void *state = NULL; state_manager_push_where(global->rewind.state, &state); RARCH_PERFORMANCE_INIT(rewind_serialize); RARCH_PERFORMANCE_START(rewind_serialize); pretro_serialize(state, global->rewind.size); RARCH_PERFORMANCE_STOP(rewind_serialize); state_manager_push_do(global->rewind.state); } } retro_set_rewind_callbacks(); }
static void check_rewind(bool pressed) { static bool first = true; if (g_extern.frame_is_reverse) { /* We just rewound. Flush rewind audio buffer. */ retro_flush_audio(g_extern.audio_data.rewind_buf + g_extern.audio_data.rewind_ptr, g_extern.audio_data.rewind_size - g_extern.audio_data.rewind_ptr); g_extern.frame_is_reverse = false; } if (first) { first = false; return; } if (!g_extern.state_manager) return; if (pressed) { const void *buf = NULL; msg_queue_clear(g_extern.msg_queue); if (state_manager_pop(g_extern.state_manager, &buf)) { g_extern.frame_is_reverse = true; setup_rewind_audio(); msg_queue_push(g_extern.msg_queue, RETRO_MSG_REWINDING, 0, g_extern.is_paused ? 1 : 30); pretro_unserialize(buf, g_extern.state_size); if (g_extern.bsv.movie) bsv_movie_frame_rewind(g_extern.bsv.movie); } else msg_queue_push(g_extern.msg_queue, RETRO_MSG_REWIND_REACHED_END, 0, 30); } else { static unsigned cnt = 0; cnt = (cnt + 1) % (g_settings.rewind_granularity ? g_settings.rewind_granularity : 1); /* Avoid possible SIGFPE. */ if ((cnt == 0) || g_extern.bsv.movie) { void *state = NULL; state_manager_push_where(g_extern.state_manager, &state); RARCH_PERFORMANCE_INIT(rewind_serialize); RARCH_PERFORMANCE_START(rewind_serialize); pretro_serialize(state, g_extern.state_size); RARCH_PERFORMANCE_STOP(rewind_serialize); state_manager_push_do(g_extern.state_manager); } } retro_set_rewind_callbacks(); }