From 8a09cb711f21ccde1a870d427b5a0f4a863d1664 Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Sat, 22 Mar 2025 21:24:39 +0100 Subject: [PATCH] Add RDP to savestate (#348) * organize RDP device * more * more * more * more * more * more * more * more --- build.rs | 4 +- parallel-rdp/interface.cpp | 127 +++++++++++++++++++++---------------- parallel-rdp/interface.hpp | 5 +- src/savestates.rs | 7 +- src/ui/video.rs | 14 +++- 5 files changed, 95 insertions(+), 62 deletions(-) diff --git a/build.rs b/build.rs index 509dfbf7..67a6e8de 100644 --- a/build.rs +++ b/build.rs @@ -109,7 +109,9 @@ fn main() { .allowlist_function("rdp_check_callback") .allowlist_function("rdp_new_processor") .allowlist_function("rdp_check_framebuffers") - .allowlist_function("rdp_full_sync") + .allowlist_function("rdp_state_size") + .allowlist_function("rdp_save_state") + .allowlist_function("rdp_load_state") .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) .generate() .expect("Unable to generate bindings"); diff --git a/parallel-rdp/interface.cpp b/parallel-rdp/interface.cpp index 697d8980..11bc25f1 100644 --- a/parallel-rdp/interface.cpp +++ b/parallel-rdp/interface.cpp @@ -52,20 +52,6 @@ enum vi_registers VI_REGS_COUNT }; -static SDL_Window *window; -static RDP::CommandProcessor *processor; -static SDL_WSIPlatform *wsi_platform; -static WSI *wsi; -static uint32_t cmd_data[0x00040000 >> 2]; -static int cmd_cur; -static int cmd_ptr; -static CALL_BACK callback; -static GFX_INFO gfx_info; -static uint32_t region; -static bool crop_letterbox; -static const uint32_t *fragment_spirv; -static size_t fragment_size; - typedef struct { uint32_t depthbuffer_address; @@ -78,16 +64,36 @@ typedef struct uint8_t depthbuffer_enabled; } FrameBufferInfo; +typedef struct +{ + uint32_t cmd_data[0x00040000 >> 2]; + int cmd_cur; + int cmd_ptr; + uint32_t region; + FrameBufferInfo frame_buffer_info; +} RDP_DEVICE; + +static SDL_Window *window; +static RDP::CommandProcessor *processor; +static SDL_WSIPlatform *wsi_platform; +static WSI *wsi; + +static RDP_DEVICE rdp_device; +static bool crop_letterbox; +static CALL_BACK callback; +static GFX_INFO gfx_info; +static const uint32_t *fragment_spirv; +static size_t fragment_size; + +std::vector rdram_dirty; +uint64_t sync_signal; + typedef struct { float SourceSize[4]; float OutputSize[4]; } Push; -static std::vector rdram_dirty; -static uint64_t sync_signal; -static FrameBufferInfo frame_buffer_info; - static const unsigned cmd_len_lut[64] = { 1, 1, @@ -211,11 +217,11 @@ bool sdl_event_filter(void *userdata, SDL_Event *event) void rdp_new_processor(GFX_INFO _gfx_info) { - memset(&frame_buffer_info, 0, sizeof(FrameBufferInfo)); + gfx_info = _gfx_info; + sync_signal = 0; rdram_dirty.assign(gfx_info.RDRAM_SIZE / 8, false); - gfx_info = _gfx_info; if (processor) { delete processor; @@ -470,29 +476,40 @@ void rdp_check_framebuffers(uint32_t address) } } -void rdp_full_sync() +size_t rdp_state_size() +{ + return sizeof(RDP_DEVICE); +} + +void rdp_save_state(uint8_t *state) { processor->wait_for_timeline(processor->signal_timeline()); + memcpy(state, &rdp_device, sizeof(RDP_DEVICE)); +} + +void rdp_load_state(const uint8_t *state) +{ + memcpy(&rdp_device, state, sizeof(RDP_DEVICE)); } void calculate_buffer_size() { - switch (frame_buffer_info.framebuffer_pixel_size) + switch (rdp_device.frame_buffer_info.framebuffer_pixel_size) { case 0: - frame_buffer_info.framebuffer_size = (frame_buffer_info.framebuffer_width * frame_buffer_info.framebuffer_height / 2) >> 3; + rdp_device.frame_buffer_info.framebuffer_size = (rdp_device.frame_buffer_info.framebuffer_width * rdp_device.frame_buffer_info.framebuffer_height / 2) >> 3; break; case 1: - frame_buffer_info.framebuffer_size = (frame_buffer_info.framebuffer_width * frame_buffer_info.framebuffer_height) >> 3; + rdp_device.frame_buffer_info.framebuffer_size = (rdp_device.frame_buffer_info.framebuffer_width * rdp_device.frame_buffer_info.framebuffer_height) >> 3; break; case 2: - frame_buffer_info.framebuffer_size = (frame_buffer_info.framebuffer_width * frame_buffer_info.framebuffer_height * 2) >> 3; + rdp_device.frame_buffer_info.framebuffer_size = (rdp_device.frame_buffer_info.framebuffer_width * rdp_device.frame_buffer_info.framebuffer_height * 2) >> 3; break; case 3: - frame_buffer_info.framebuffer_size = (frame_buffer_info.framebuffer_width * frame_buffer_info.framebuffer_height * 4) >> 3; + rdp_device.frame_buffer_info.framebuffer_size = (rdp_device.frame_buffer_info.framebuffer_width * rdp_device.frame_buffer_info.framebuffer_height * 4) >> 3; break; } - frame_buffer_info.depthbuffer_size = (frame_buffer_info.framebuffer_width * frame_buffer_info.framebuffer_height * 2) >> 3; + rdp_device.frame_buffer_info.depthbuffer_size = (rdp_device.frame_buffer_info.framebuffer_width * rdp_device.frame_buffer_info.framebuffer_height * 2) >> 3; } uint64_t rdp_process_commands() @@ -506,7 +523,7 @@ uint64_t rdp_process_commands() return interrupt_timer; length = unsigned(length) >> 3; - if ((cmd_ptr + length) & ~(0x0003FFFF >> 3)) + if ((rdp_device.cmd_ptr + length) & ~(0x0003FFFF >> 3)) return interrupt_timer; uint32_t offset = DP_CURRENT; @@ -515,10 +532,10 @@ uint64_t rdp_process_commands() do { offset &= 0xFF8; - cmd_data[2 * cmd_ptr + 0] = SDL_Swap32BE(*reinterpret_cast(gfx_info.DMEM + offset)); - cmd_data[2 * cmd_ptr + 1] = SDL_Swap32BE(*reinterpret_cast(gfx_info.DMEM + offset + 4)); + rdp_device.cmd_data[2 * rdp_device.cmd_ptr + 0] = SDL_Swap32BE(*reinterpret_cast(gfx_info.DMEM + offset)); + rdp_device.cmd_data[2 * rdp_device.cmd_ptr + 1] = SDL_Swap32BE(*reinterpret_cast(gfx_info.DMEM + offset + 4)); offset += sizeof(uint64_t); - cmd_ptr++; + rdp_device.cmd_ptr++; } while (--length > 0); } else @@ -532,59 +549,59 @@ uint64_t rdp_process_commands() do { offset &= 0xFFFFF8; - cmd_data[2 * cmd_ptr + 0] = *reinterpret_cast(gfx_info.RDRAM + offset); - cmd_data[2 * cmd_ptr + 1] = *reinterpret_cast(gfx_info.RDRAM + offset + 4); + rdp_device.cmd_data[2 * rdp_device.cmd_ptr + 0] = *reinterpret_cast(gfx_info.RDRAM + offset); + rdp_device.cmd_data[2 * rdp_device.cmd_ptr + 1] = *reinterpret_cast(gfx_info.RDRAM + offset + 4); offset += sizeof(uint64_t); - cmd_ptr++; + rdp_device.cmd_ptr++; } while (--length > 0); } } - while (cmd_cur - cmd_ptr < 0) + while (rdp_device.cmd_cur - rdp_device.cmd_ptr < 0) { - uint32_t w1 = cmd_data[2 * cmd_cur]; - uint32_t w2 = cmd_data[2 * cmd_cur + 1]; + uint32_t w1 = rdp_device.cmd_data[2 * rdp_device.cmd_cur]; + uint32_t w2 = rdp_device.cmd_data[2 * rdp_device.cmd_cur + 1]; uint32_t command = (w1 >> 24) & 63; int cmd_length = cmd_len_lut[command]; - if (cmd_ptr - cmd_cur - cmd_length < 0) + if (rdp_device.cmd_ptr - rdp_device.cmd_cur - cmd_length < 0) { *gfx_info.DPC_START_REG = *gfx_info.DPC_CURRENT_REG = *gfx_info.DPC_END_REG; return interrupt_timer; } if (command >= 8) - processor->enqueue_command(cmd_length * 2, &cmd_data[2 * cmd_cur]); + processor->enqueue_command(cmd_length * 2, &rdp_device.cmd_data[2 * rdp_device.cmd_cur]); if ((RDP::Op(command) >= RDP::Op::FillTriangle && RDP::Op(command) <= RDP::Op::ShadeTextureZBufferTriangle) || RDP::Op(command) == RDP::Op::TextureRectangle || RDP::Op(command) == RDP::Op::TextureRectangleFlip || RDP::Op(command) == RDP::Op::FillRectangle) { - if (!rdram_dirty[frame_buffer_info.framebuffer_address]) + if (!rdram_dirty[rdp_device.frame_buffer_info.framebuffer_address]) { - std::fill_n(rdram_dirty.begin() + frame_buffer_info.framebuffer_address, frame_buffer_info.framebuffer_size, true); + std::fill_n(rdram_dirty.begin() + rdp_device.frame_buffer_info.framebuffer_address, rdp_device.frame_buffer_info.framebuffer_size, true); } - if (frame_buffer_info.depthbuffer_enabled && !rdram_dirty[frame_buffer_info.depthbuffer_address]) + if (rdp_device.frame_buffer_info.depthbuffer_enabled && !rdram_dirty[rdp_device.frame_buffer_info.depthbuffer_address]) { - std::fill_n(rdram_dirty.begin() + frame_buffer_info.depthbuffer_address, frame_buffer_info.depthbuffer_size, true); + std::fill_n(rdram_dirty.begin() + rdp_device.frame_buffer_info.depthbuffer_address, rdp_device.frame_buffer_info.depthbuffer_size, true); } } else if (RDP::Op(command) == RDP::Op::SetOtherModes) { - frame_buffer_info.depthbuffer_enabled = (w2 >> 5) & 1; + rdp_device.frame_buffer_info.depthbuffer_enabled = (w2 >> 5) & 1; } else if (RDP::Op(command) == RDP::Op::SetColorImage) { - frame_buffer_info.framebuffer_address = (w2 & 0x00FFFFFF) >> 3; - frame_buffer_info.framebuffer_pixel_size = (w1 >> 19) & 0x3; - frame_buffer_info.framebuffer_width = (w1 & 0x3FF) + 1; + rdp_device.frame_buffer_info.framebuffer_address = (w2 & 0x00FFFFFF) >> 3; + rdp_device.frame_buffer_info.framebuffer_pixel_size = (w1 >> 19) & 0x3; + rdp_device.frame_buffer_info.framebuffer_width = (w1 & 0x3FF) + 1; calculate_buffer_size(); } else if (RDP::Op(command) == RDP::Op::SetMaskImage) { - frame_buffer_info.depthbuffer_address = (w2 & 0x00FFFFFF) >> 3; + rdp_device.frame_buffer_info.depthbuffer_address = (w2 & 0x00FFFFFF) >> 3; } else if (RDP::Op(command) == RDP::Op::SetScissor) { @@ -594,29 +611,29 @@ uint64_t rdp_process_commands() uint32_t lower_right_y = (w2 & 0xFFF) >> 2; if (lower_right_x > upper_left_x && lower_right_y > upper_left_y) { - region = (lower_right_x - upper_left_x) * (lower_right_y - upper_left_y); + rdp_device.region = (lower_right_x - upper_left_x) * (lower_right_y - upper_left_y); } else { - region = 0; + rdp_device.region = 0; } - frame_buffer_info.framebuffer_height = lower_right_y; + rdp_device.frame_buffer_info.framebuffer_height = lower_right_y; calculate_buffer_size(); } else if (RDP::Op(command) == RDP::Op::SyncFull) { sync_signal = processor->signal_timeline(); - interrupt_timer = region; + interrupt_timer = rdp_device.region; if (interrupt_timer == 0) interrupt_timer = 5000; } - cmd_cur += cmd_length; + rdp_device.cmd_cur += cmd_length; } - cmd_ptr = 0; - cmd_cur = 0; + rdp_device.cmd_ptr = 0; + rdp_device.cmd_cur = 0; *gfx_info.DPC_CURRENT_REG = *gfx_info.DPC_END_REG; return interrupt_timer; diff --git a/parallel-rdp/interface.hpp b/parallel-rdp/interface.hpp index 8856e47c..8c3ae2d9 100644 --- a/parallel-rdp/interface.hpp +++ b/parallel-rdp/interface.hpp @@ -2,6 +2,7 @@ #ifdef __cplusplus #include +#include extern "C" { @@ -42,7 +43,9 @@ extern "C" uint64_t rdp_process_commands(); void rdp_new_processor(GFX_INFO _gfx_info); void rdp_check_framebuffers(uint32_t address); - void rdp_full_sync(); + size_t rdp_state_size(); + void rdp_save_state(uint8_t *state); + void rdp_load_state(const uint8_t *state); #ifdef __cplusplus } diff --git a/src/savestates.rs b/src/savestates.rs index 033b139f..fda8b772 100644 --- a/src/savestates.rs +++ b/src/savestates.rs @@ -70,7 +70,8 @@ where } pub fn create_savestate(device: &device::Device) { - ui::video::full_sync(); + let mut rdp_state: Vec = vec![0; ui::video::state_size()]; + ui::video::save_state(rdp_state.as_mut_ptr()); let data: &[(&[u8], &str)] = &[ (&postcard::to_stdvec(device).unwrap(), "device"), @@ -78,6 +79,7 @@ pub fn create_savestate(device: &device::Device) { &postcard::to_stdvec(&device.ui.storage.saves).unwrap(), "saves", ), + (&rdp_state, "rdp_state"), ]; let compressed_file = ui::storage::compress_file(data); std::fs::write( @@ -92,6 +94,7 @@ pub fn load_savestate(device: &mut device::Device) { if savestate.is_ok() { let device_bytes = ui::storage::decompress_file(savestate.as_ref().unwrap(), "device"); let save_bytes = ui::storage::decompress_file(savestate.as_ref().unwrap(), "saves"); + let rdp_state = ui::storage::decompress_file(savestate.as_ref().unwrap(), "rdp_state"); if let Ok(state) = postcard::from_bytes::(&device_bytes) { device.ui.storage.saves = postcard::from_bytes(&save_bytes).unwrap(); @@ -186,7 +189,7 @@ pub fn load_savestate(device: &mut device::Device) { ui::audio::close(&mut device.ui); ui::audio::init(&mut device.ui, device.ai.freq); - ui::video::load_state(device); + ui::video::load_state(device, rdp_state.as_ptr()); } else { println!("Failed to load savestate"); } diff --git a/src/ui/video.rs b/src/ui/video.rs index 755b13aa..3ab118f0 100644 --- a/src/ui/video.rs +++ b/src/ui/video.rs @@ -78,11 +78,15 @@ pub fn check_framebuffers(address: u32) { unsafe { rdp_check_framebuffers(address) } } -pub fn full_sync() { - unsafe { rdp_full_sync() } +pub fn state_size() -> usize { + unsafe { rdp_state_size() } } -pub fn load_state(device: &mut device::Device) { +pub fn save_state(rdp_state: *mut u8) { + unsafe { rdp_save_state(rdp_state) } +} + +pub fn load_state(device: &mut device::Device, rdp_state: *const u8) { let gfx_info = GFX_INFO { RDRAM: device.rdram.mem.as_mut_ptr(), DMEM: device.rsp.mem.as_mut_ptr(), @@ -99,7 +103,11 @@ pub fn load_state(device: &mut device::Device) { crt: device.ui.config.video.crt, }; unsafe { + rdp_load_state(rdp_state); rdp_new_processor(gfx_info); + for reg in 0..device::vi::VI_REGS_COUNT { + rdp_set_vi_register(reg, device.vi.regs[reg as usize]) + } } }