From d968983ceb110cc38cc523059d0e839c2e4ab111 Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Sun, 31 May 2026 21:29:28 +0200 Subject: [PATCH] Savestate tweaks (#999) * move savestate processing * fix stack overflow * more * more --- parallel-rdp/interface.cpp | 7 +++++-- src/device.rs | 3 ++- src/device/controller.rs | 4 ++-- src/device/rdp.rs | 16 +--------------- src/device/vi.rs | 5 ++--- src/savestates.rs | 24 ++++++++++++++++++++---- 6 files changed, 32 insertions(+), 27 deletions(-) diff --git a/parallel-rdp/interface.cpp b/parallel-rdp/interface.cpp index 5b6d26a5..00358d4b 100644 --- a/parallel-rdp/interface.cpp +++ b/parallel-rdp/interface.cpp @@ -703,8 +703,11 @@ void rdp_check_framebuffers(uint32_t address, uint32_t length) { size_t rdp_state_size() { return sizeof(RDP_DEVICE); } void rdp_save_state(uint8_t *state, bool rewind) { - if (!rewind) // speed hack for rewind - processor->wait_for_timeline(processor->signal_timeline()); + if (!rewind) { // speed hack for rewind + processor->idle(); + rdram_dirty.assign(gfx_info.RDRAM_SIZE >> 3, false); + sync_signal = 0; + } memcpy(state, &rdp_device, sizeof(RDP_DEVICE)); } diff --git a/src/device.rs b/src/device.rs index abf7e251..2dcdcc0c 100644 --- a/src/device.rs +++ b/src/device.rs @@ -229,6 +229,7 @@ pub struct Device { #[serde(skip)] pub ui: ui::Ui, pub byte_swap: usize, + pub frame_counter: u64, pub savestate: savestates::Savestate, pub cpu: cpu::Cpu, pub pif: pif::Pif, @@ -290,6 +291,7 @@ impl Device { ui::Ui::default() }, byte_swap, + frame_counter: 0, savestate: savestates::Savestate { save_state: false, load_state: false, @@ -529,7 +531,6 @@ impl Device { count_per_scanline: 0, enable_speed_limiter: true, next_pace_deadline: None, - vi_counter: 0, min_wait_time: std::time::Duration::from_secs(1), frame_time: 0.0, elapsed_time: 0.0, diff --git a/src/device/controller.rs b/src/device/controller.rs index 6a761fd1..78277896 100644 --- a/src/device/controller.rs +++ b/src/device/controller.rs @@ -58,12 +58,12 @@ pub fn process(device: &mut device::Device, channel: usize) { let offset = device.pif.channels[channel].rx_buf.unwrap(); let input = if let Some(netplay) = &mut device.netplay { if netplay.player_number as usize == channel { - let local_input = ui::input::get(&mut device.ui, 0, device.vi.vi_counter); + let local_input = ui::input::get(&mut device.ui, 0, device.frame_counter); netplay::send_input(netplay, local_input); } netplay::get_input(device, channel) } else { - ui::input::get(&mut device.ui, channel, device.vi.vi_counter) + ui::input::get(&mut device.ui, channel, device.frame_counter) }; device.pif.ram[offset..offset + 4].copy_from_slice(&input.data.to_ne_bytes()); diff --git a/src/device/rdp.rs b/src/device/rdp.rs index 4a149cbb..3d115f8a 100644 --- a/src/device/rdp.rs +++ b/src/device/rdp.rs @@ -120,21 +120,7 @@ fn run_rdp(device: &mut device::Device) { device.rdp.regs_dpc[DPC_PIPEBUSY_REG] = 0xFFFFFF; if timer != 0 { - if device.savestate.save_state || device.savestate.save_rewind { - // Right after full sync, good time for save state - let rewind = device.savestate.save_rewind && !device.savestate.save_state; - if rewind { - device.savestate.save_rewind = false; - } - device.savestate.save_state = false; - savestates::create_savestate(device, rewind); - } else if device.savestate.load_state || device.savestate.load_rewind { - // Right after full sync, good time for save state - device.savestate.load_state = false; - let rewind = device.savestate.load_rewind; - device.savestate.load_rewind = false; - savestates::load_savestate(device, rewind); - } + savestates::process_savestates(device); device::events::create_event(device, device::events::EVENT_TYPE_DP, timer) } } diff --git a/src/device/vi.rs b/src/device/vi.rs index 664999f1..f0d8fc4d 100644 --- a/src/device/vi.rs +++ b/src/device/vi.rs @@ -26,7 +26,6 @@ pub struct Vi { pub next_pace_deadline: Option, pub count_per_scanline: u64, pub enable_speed_limiter: bool, - pub vi_counter: u64, pub min_wait_time: std::time::Duration, pub frame_time: f64, pub elapsed_time: f64, @@ -152,14 +151,14 @@ pub fn vertical_interrupt_event(device: &mut device::Device) { reset_pace_deadline(device); } - if device.vi.vi_counter.is_multiple_of(device.vi.limit_freq) && device.vi.enable_speed_limiter { + if device.frame_counter.is_multiple_of(device.vi.limit_freq) && device.vi.enable_speed_limiter { speed_limiter(device); } unsafe { sdl3_sys::events::SDL_PumpEvents() }; ui::video::update_screen(); - device.vi.vi_counter += 1; + device.frame_counter += 1; if device.netplay.is_none() && paused { if retroachievements::get_hardcore() { diff --git a/src/savestates.rs b/src/savestates.rs index 273ab5ff..4868062a 100644 --- a/src/savestates.rs +++ b/src/savestates.rs @@ -94,7 +94,23 @@ static DEVICE_CLONE: std::sync::LazyLock> = static SAVES_CLONE: std::sync::LazyLock> = std::sync::LazyLock::new(|| std::sync::Mutex::new(ui::storage::Saves::default())); -pub fn create_savestate(device: &mut device::Device, rewind: bool) { +pub fn process_savestates(device: &mut device::Device) { + if device.savestate.save_state || device.savestate.save_rewind { + let rewind = device.savestate.save_rewind && !device.savestate.save_state; + if rewind { + device.savestate.save_rewind = false; + } + device.savestate.save_state = false; + create_savestate(device, rewind); + } else if device.savestate.load_state || device.savestate.load_rewind { + device.savestate.load_state = false; + let rewind = device.savestate.load_rewind; + device.savestate.load_rewind = false; + load_savestate(device, rewind); + } +} + +fn create_savestate(device: &mut device::Device, rewind: bool) { let mut rdp_state: Vec = vec![0; ui::video::state_size()]; ui::video::save_state(rdp_state.as_mut_ptr(), rewind); @@ -175,7 +191,7 @@ pub fn create_savestate(device: &mut device::Device, rewind: bool) { }); } -pub fn load_savestate(device: &mut device::Device, rewind: bool) { +fn load_savestate(device: &mut device::Device, rewind: bool) { if retroachievements::get_hardcore() { ui::video::onscreen_message( "Cannot load savestate in RA hardcore mode", @@ -196,11 +212,11 @@ pub fn load_savestate(device: &mut device::Device, rewind: bool) { && let Ok(saves_data) = ui::storage::decompress_file(savestate, "saves") && let Ok(rdp_state) = ui::storage::decompress_file(savestate, "rdp_state") && let Ok(ra_state) = ui::storage::decompress_file(savestate, "ra_state") - && let Ok(state) = postcard::from_bytes::(&device_data) + && let Ok(state) = postcard::from_bytes::>(&device_data) && let Ok(saves) = postcard::from_bytes(&saves_data) { Some(SavestateData { - device: state, + device: *state, saves, rdp_state, ra_state,