From 656e390171bd64a352a6282a3c9c3b3f5d3dea05 Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Mon, 17 Feb 2025 22:13:45 +0100 Subject: [PATCH] track RDP RDRAM writes (#259) * track RDP RDRAM writes * more * more * more * more * more --- build.rs | 2 + parallel-rdp/interface.cpp | 93 +++++++++++++++++++++++++++++++++++-- parallel-rdp/interface.hpp | 2 + src/device/rdram.rs | 3 ++ src/device/rsp_interface.rs | 2 + src/savestates.rs | 2 + src/ui/video.rs | 8 ++++ 7 files changed, 108 insertions(+), 4 deletions(-) diff --git a/build.rs b/build.rs index 43eb5b7..0b20db2 100644 --- a/build.rs +++ b/build.rs @@ -101,6 +101,8 @@ fn main() { .allowlist_function("rdp_process_commands") .allowlist_function("rdp_check_callback") .allowlist_function("rdp_new_processor") + .allowlist_function("rdp_check_framebuffers") + .allowlist_function("rdp_full_sync") .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 ab00243..45a549d 100644 --- a/parallel-rdp/interface.cpp +++ b/parallel-rdp/interface.cpp @@ -64,6 +64,15 @@ static CALL_BACK callback; static GFX_INFO gfx_info; static uint32_t region; +static uint32_t depthbuffer_address; +static uint32_t framebuffer_address; +static uint32_t framebuffer_pixel_size; +static uint32_t framebuffer_width; +static uint32_t framebuffer_height; +static uint8_t depthbuffer_enabled; +static uint8_t *rdram_dirty; +static uint64_t sync_signal; + static const unsigned cmd_len_lut[64] = { 1, 1, @@ -234,10 +243,20 @@ void rdp_init(void *_window, GFX_INFO _gfx_info, bool _upscale, bool _integer_sc callback.emu_running = true; callback.enable_speedlimiter = true; + + sync_signal = 0; + rdram_dirty = (uint8_t *)malloc(gfx_info.RDRAM_SIZE / 8); + memset(rdram_dirty, 0, gfx_info.RDRAM_SIZE / 8); } void rdp_close() { + if (rdram_dirty) + { + free(rdram_dirty); + rdram_dirty = nullptr; + } + wsi->end_frame(); if (processor) @@ -369,6 +388,21 @@ CALL_BACK rdp_check_callback() return return_value; } +void rdp_check_framebuffers(uint32_t address) +{ + if (sync_signal && rdram_dirty[address >> 3]) + { + processor->wait_for_timeline(sync_signal); + memset(rdram_dirty, 0, gfx_info.RDRAM_SIZE / 8); + sync_signal = 0; + } +} + +void rdp_full_sync() +{ + processor->wait_for_timeline(processor->signal_timeline()); +} + uint64_t rdp_process_commands() { uint64_t interrupt_timer = 0; @@ -430,18 +464,69 @@ uint64_t rdp_process_commands() if (command >= 8) processor->enqueue_command(cmd_length * 2, &cmd_data[2 * cmd_cur]); - if (RDP::Op(command) == RDP::Op::SetScissor) + 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) + { + uint32_t size = 0; + switch (framebuffer_pixel_size) + { + case 0: + size = (framebuffer_width * framebuffer_height / 2) >> 3; + break; + case 1: + size = (framebuffer_width * framebuffer_height) >> 3; + break; + case 2: + size = (framebuffer_width * framebuffer_height * 2) >> 3; + break; + case 3: + size = (framebuffer_width * framebuffer_height * 4) >> 3; + break; + } + + for (uint32_t i = framebuffer_address; i < framebuffer_address + size; ++i) + { + rdram_dirty[i] = 1; + } + + if (depthbuffer_enabled) + { + size = (framebuffer_width * framebuffer_height * 2) >> 3; + + for (uint32_t i = depthbuffer_address; i < depthbuffer_address + size; ++i) + { + rdram_dirty[i] = 1; + } + } + } + else if (RDP::Op(command) == RDP::Op::SetOtherModes) + { + depthbuffer_enabled = (w2 >> 5) & 1; + } + else if (RDP::Op(command) == RDP::Op::SetColorImage) + { + framebuffer_address = (w2 & 0x00FFFFFF) >> 3; + framebuffer_pixel_size = (w1 >> 19) & 0x3; + framebuffer_width = (w1 & 0x3FF) + 1; + } + else if (RDP::Op(command) == RDP::Op::SetMaskImage) + { + depthbuffer_address = (w2 & 0x00FFFFFF) >> 3; + } + else if (RDP::Op(command) == RDP::Op::SetScissor) { uint32_t upper_left_x = ((w1 >> 12) & 0xFFF) >> 2; uint32_t upper_left_y = (w1 & 0xFFF) >> 2; uint32_t lower_right_x = ((w2 >> 12) & 0xFFF) >> 2; uint32_t lower_right_y = (w2 & 0xFFF) >> 2; region = (lower_right_x - upper_left_x) * (lower_right_y - upper_left_y); + framebuffer_height = lower_right_y; } - if (RDP::Op(command) == RDP::Op::SyncFull) + else if (RDP::Op(command) == RDP::Op::SyncFull) { - processor->wait_for_timeline(processor->signal_timeline()); - + sync_signal = processor->signal_timeline(); interrupt_timer = region; if (interrupt_timer == 0) interrupt_timer = 5000; diff --git a/parallel-rdp/interface.hpp b/parallel-rdp/interface.hpp index 5ed2419..c4786b7 100644 --- a/parallel-rdp/interface.hpp +++ b/parallel-rdp/interface.hpp @@ -34,6 +34,8 @@ extern "C" CALL_BACK rdp_check_callback(); uint64_t rdp_process_commands(); void rdp_new_processor(GFX_INFO _gfx_info, bool _upscale); + void rdp_check_framebuffers(uint32_t address); + void rdp_full_sync(); #ifdef __cplusplus } diff --git a/src/device/rdram.rs b/src/device/rdram.rs index a94a468..a8946bd 100644 --- a/src/device/rdram.rs +++ b/src/device/rdram.rs @@ -1,4 +1,5 @@ use crate::device; +use crate::ui; use std::alloc::{alloc_zeroed, Layout}; //const RDRAM_CONFIG_REG: u32 = 0; @@ -46,6 +47,7 @@ pub fn read_mem( ); let masked_address = address as usize & RDRAM_MASK; if address < device.rdram.size as u64 { + ui::video::check_framebuffers(masked_address as u32); u32::from_ne_bytes( device.rdram.mem[masked_address..masked_address + 4] .try_into() @@ -58,6 +60,7 @@ pub fn read_mem( pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u32) { if address < device.rdram.size as u64 { + ui::video::check_framebuffers(address as u32); let mut data = u32::from_ne_bytes( device.rdram.mem[address as usize..(address + 4) as usize] .try_into() diff --git a/src/device/rsp_interface.rs b/src/device/rsp_interface.rs index 2916cc3..56bc045 100644 --- a/src/device/rsp_interface.rs +++ b/src/device/rsp_interface.rs @@ -1,4 +1,5 @@ use crate::device; +use crate::ui; const SP_MEM_ADDR_REG: u32 = 0; const SP_DRAM_ADDR_REG: u32 = 1; @@ -146,6 +147,7 @@ fn do_dma(device: &mut device::Device, dma: RspDma) { let mut dram_addr = dma.dramaddr & 0xfffff8; let offset = dma.memaddr & 0x1000; + ui::video::check_framebuffers(dram_addr); if dma.dir == DmaDir::Read { let mut j = 0; while j < count { diff --git a/src/savestates.rs b/src/savestates.rs index bb80b84..3213f43 100644 --- a/src/savestates.rs +++ b/src/savestates.rs @@ -70,6 +70,8 @@ where } pub fn create_savestate(device: &device::Device) { + ui::video::full_sync(); + let data: &[(&[u8], &str)] = &[ (&postcard::to_stdvec(device).unwrap(), "device"), (&postcard::to_stdvec(&device.ui.saves).unwrap(), "saves"), diff --git a/src/ui/video.rs b/src/ui/video.rs index af0d0d5..0553fed 100644 --- a/src/ui/video.rs +++ b/src/ui/video.rs @@ -67,6 +67,14 @@ pub fn update_screen() { unsafe { rdp_update_screen() } } +pub fn check_framebuffers(address: u32) { + unsafe { rdp_check_framebuffers(address) } +} + +pub fn full_sync() { + unsafe { rdp_full_sync() } +} + pub fn load_state(device: &mut device::Device) { let gfx_info = GFX_INFO { RDRAM: device.rdram.mem.as_mut_ptr(),