From 2b93fb8aa1e94ee77ac571b691ec6d854d425e2e Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Fri, 19 Sep 2025 11:32:48 +0200 Subject: [PATCH] re-add framebuffer tracking (#573) --- build.rs | 1 + parallel-rdp/interface.cpp | 130 +++++++++++++++++++++++++++++++++++- parallel-rdp/interface.hpp | 1 + src/device/pi.rs | 4 ++ src/device/rdram.rs | 5 ++ src/device/rsp_interface.rs | 2 + src/device/si.rs | 3 + src/ui/video.rs | 4 ++ 8 files changed, 148 insertions(+), 2 deletions(-) diff --git a/build.rs b/build.rs index 399adf9c..7b241001 100644 --- a/build.rs +++ b/build.rs @@ -117,6 +117,7 @@ fn main() { .allowlist_function("rdp_onscreen_message") .allowlist_function("rdp_check_callback") .allowlist_function("rdp_new_processor") + .allowlist_function("rdp_check_framebuffers") .allowlist_function("rdp_state_size") .allowlist_function("rdp_save_state") .allowlist_function("rdp_load_state") diff --git a/parallel-rdp/interface.cpp b/parallel-rdp/interface.cpp index 5aa7aa0d..152f1f35 100644 --- a/parallel-rdp/interface.cpp +++ b/parallel-rdp/interface.cpp @@ -53,12 +53,26 @@ enum vi_registers VI_REGS_COUNT }; +typedef struct +{ + uint32_t depthbuffer_address; + uint32_t framebuffer_address; + uint32_t framebuffer_y_offset; + uint32_t texture_address; + uint32_t framebuffer_pixel_size; + uint32_t framebuffer_width; + uint32_t texture_pixel_size; + uint32_t texture_width; + uint32_t framebuffer_height; +} 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; @@ -73,6 +87,9 @@ static GFX_INFO gfx_info; static const uint32_t *fragment_spirv; static size_t fragment_size; +std::vector rdram_dirty; +uint64_t sync_signal; + static TTF_Font *message_font; static std::queue messages; static uint64_t message_timer; @@ -238,6 +255,9 @@ void rdp_new_processor(GFX_INFO _gfx_info) { gfx_info = _gfx_info; + sync_signal = 0; + rdram_dirty.assign(gfx_info.RDRAM_SIZE >> 3, false); + if (processor) { delete processor; @@ -544,6 +564,27 @@ CALL_BACK rdp_check_callback() return return_value; } +void rdp_check_framebuffers(uint32_t address, uint32_t length) +{ + if (sync_signal) + { + address >>= 3; + length = (length + 7) >> 3; + for (uint32_t i = 0; i < length; i++) + { + if (address + i >= rdram_dirty.size()) + return; + if (rdram_dirty[address + i]) + { + processor->wait_for_timeline(sync_signal); + rdram_dirty.assign(gfx_info.RDRAM_SIZE >> 3, false); + sync_signal = 0; + return; + } + } + } +} + size_t rdp_state_size() { return sizeof(RDP_DEVICE); @@ -551,6 +592,7 @@ size_t rdp_state_size() void rdp_save_state(uint8_t *state) { + processor->wait_for_timeline(processor->signal_timeline()); memcpy(state, &rdp_device, sizeof(RDP_DEVICE)); } @@ -566,6 +608,24 @@ void rdp_onscreen_message(const char *_message) messages.push(_message); } +uint32_t pixel_size(uint32_t pixel_type, uint32_t area) +{ + switch (pixel_type) + { + case 0: + return area / 2; + case 1: + return area; + case 2: + return area * 2; + case 3: + return area * 4; + default: + printf("Invalid pixel size: %u\n", pixel_type); + return 0; + } +} + uint64_t rdp_process_commands() { uint64_t interrupt_timer = 0; @@ -629,6 +689,69 @@ uint64_t rdp_process_commands() switch (RDP::Op(command)) { + case RDP::Op::FillZBufferTriangle: + case RDP::Op::TextureZBufferTriangle: + case RDP::Op::ShadeZBufferTriangle: + case RDP::Op::ShadeTextureZBufferTriangle: + { + uint32_t offset_address = (rdp_device.frame_buffer_info.depthbuffer_address + pixel_size(2, rdp_device.frame_buffer_info.framebuffer_y_offset * rdp_device.frame_buffer_info.framebuffer_width)) >> 3; + if (offset_address < rdram_dirty.size() && !rdram_dirty[offset_address]) + { + std::fill_n(rdram_dirty.begin() + offset_address, (pixel_size(2, rdp_device.frame_buffer_info.framebuffer_width * rdp_device.frame_buffer_info.framebuffer_height) + 7) >> 3, true); + } + } + case RDP::Op::FillTriangle: + case RDP::Op::TextureTriangle: + case RDP::Op::ShadeTriangle: + case RDP::Op::ShadeTextureTriangle: + case RDP::Op::TextureRectangle: + case RDP::Op::TextureRectangleFlip: + case RDP::Op::FillRectangle: + { + uint32_t offset_address = (rdp_device.frame_buffer_info.framebuffer_address + pixel_size(rdp_device.frame_buffer_info.framebuffer_pixel_size, rdp_device.frame_buffer_info.framebuffer_y_offset * rdp_device.frame_buffer_info.framebuffer_width)) >> 3; + if (offset_address < rdram_dirty.size() && !rdram_dirty[offset_address]) + { + std::fill_n(rdram_dirty.begin() + offset_address, (pixel_size(rdp_device.frame_buffer_info.framebuffer_pixel_size, rdp_device.frame_buffer_info.framebuffer_width * rdp_device.frame_buffer_info.framebuffer_height) + 7) >> 3, true); + } + } + break; + case RDP::Op::LoadTLut: + case RDP::Op::LoadTile: + { + uint32_t upper_left_t = (w1 & 0xFFF) >> 2; + uint32_t offset_address = (rdp_device.frame_buffer_info.texture_address + pixel_size(rdp_device.frame_buffer_info.texture_pixel_size, upper_left_t * rdp_device.frame_buffer_info.texture_width)) >> 3; + if (offset_address < rdram_dirty.size() && !rdram_dirty[offset_address]) + { + uint32_t lower_right_t = (w2 & 0xFFF) >> 2; + std::fill_n(rdram_dirty.begin() + offset_address, (pixel_size(rdp_device.frame_buffer_info.texture_pixel_size, (lower_right_t - upper_left_t) * rdp_device.frame_buffer_info.texture_width) + 7) >> 3, true); + } + } + break; + case RDP::Op::LoadBlock: + { + uint32_t upper_left_s = ((w1 >> 12) & 0xFFF) >> 2; + uint32_t upper_left_t = (w1 & 0xFFF) >> 2; + uint32_t offset_address = (rdp_device.frame_buffer_info.texture_address + pixel_size(rdp_device.frame_buffer_info.texture_pixel_size, upper_left_s + upper_left_t * rdp_device.frame_buffer_info.texture_width)) >> 3; + if (offset_address < rdram_dirty.size() && !rdram_dirty[offset_address]) + { + uint32_t lower_right_s = ((w2 >> 12) & 0xFFF) >> 2; + std::fill_n(rdram_dirty.begin() + offset_address, (pixel_size(rdp_device.frame_buffer_info.texture_pixel_size, lower_right_s - upper_left_s) + 7) >> 3, true); + } + } + break; + case RDP::Op::SetColorImage: + rdp_device.frame_buffer_info.framebuffer_address = (w2 & 0x00FFFFFF); + rdp_device.frame_buffer_info.framebuffer_pixel_size = (w1 >> 19) & 0x3; + rdp_device.frame_buffer_info.framebuffer_width = (w1 & 0x3FF) + 1; + break; + case RDP::Op::SetMaskImage: + rdp_device.frame_buffer_info.depthbuffer_address = (w2 & 0x00FFFFFF); + break; + case RDP::Op::SetTextureImage: + rdp_device.frame_buffer_info.texture_address = (w2 & 0x00FFFFFF); + rdp_device.frame_buffer_info.texture_pixel_size = (w1 >> 19) & 0x3; + rdp_device.frame_buffer_info.texture_width = (w1 & 0x3FF) + 1; + break; case RDP::Op::SetScissor: { uint32_t upper_left_x = ((w1 >> 12) & 0xFFF) >> 2; @@ -643,10 +766,13 @@ uint64_t rdp_process_commands() { rdp_device.region = 0; } - break; + + rdp_device.frame_buffer_info.framebuffer_y_offset = upper_left_y; + rdp_device.frame_buffer_info.framebuffer_height = lower_right_y - upper_left_y; } + break; case RDP::Op::SyncFull: - processor->wait_for_timeline(processor->signal_timeline()); + sync_signal = processor->signal_timeline(); interrupt_timer = rdp_device.region; if (interrupt_timer == 0) diff --git a/parallel-rdp/interface.hpp b/parallel-rdp/interface.hpp index ad9421f1..7106406c 100644 --- a/parallel-rdp/interface.hpp +++ b/parallel-rdp/interface.hpp @@ -47,6 +47,7 @@ extern "C" uint64_t rdp_process_commands(); void rdp_onscreen_message(const char *_message); void rdp_new_processor(GFX_INFO _gfx_info); + void rdp_check_framebuffers(uint32_t address, uint32_t length); size_t rdp_state_size(); void rdp_save_state(uint8_t *state); void rdp_load_state(const uint8_t *state); diff --git a/src/device/pi.rs b/src/device/pi.rs index f18629c2..2ca4f02a 100644 --- a/src/device/pi.rs +++ b/src/device/pi.rs @@ -1,4 +1,5 @@ use crate::device; +use crate::ui; use rand_chacha::rand_core::RngCore; const PI_DRAM_ADDR_REG: u32 = 0; @@ -92,6 +93,9 @@ fn dma_write(device: &mut device::Device) { length -= dram_addr & 0x7; } + // check RDP before PI writes to RDRAM + ui::video::check_framebuffers(dram_addr, length); + let cycles = (handler.write)(device, cart_addr, dram_addr, length); device::events::create_event(device, device::events::EVENT_TYPE_PI, cycles); diff --git a/src/device/rdram.rs b/src/device/rdram.rs index 956c57eb..2d7e05f4 100644 --- a/src/device/rdram.rs +++ b/src/device/rdram.rs @@ -1,4 +1,5 @@ use crate::device; +use crate::ui; use std::alloc::{Layout, alloc_zeroed}; //const RDRAM_CONFIG_REG: u32 = 0; @@ -50,6 +51,8 @@ pub fn read_mem( ); let masked_address = address as usize & RDRAM_MASK; + ui::video::check_framebuffers(masked_address as u32, 4); + u32::from_ne_bytes( device .rdram @@ -62,6 +65,8 @@ pub fn read_mem( } pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u32) { + ui::video::check_framebuffers(address as u32, 4); + let mut data = u32::from_ne_bytes( device .rdram diff --git a/src/device/rsp_interface.rs b/src/device/rsp_interface.rs index 34d169ef..64377e3e 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, count * (length + skip) - skip); if dma.dir == DmaDir::Read { let mut j = 0; while j < count { diff --git a/src/device/si.rs b/src/device/si.rs index 017958ae..32e1b041 100644 --- a/src/device/si.rs +++ b/src/device/si.rs @@ -1,6 +1,7 @@ use rand_chacha::rand_core::RngCore; use crate::device; +use crate::ui; const SI_DRAM_ADDR_REG: u32 = 0; const SI_PIF_ADDR_RD64B_REG: u32 = 1; @@ -98,6 +99,8 @@ fn copy_pif_rdram(device: &mut device::Device) { i += 4; } } else if device.si.dma_dir == DmaDir::Read { + // check RDP before SI writes to RDRAM + ui::video::check_framebuffers(dram_addr as u32, device::pif::PIF_RAM_SIZE as u32); let mut i = 0; while i < device::pif::PIF_RAM_SIZE { let data = u32::from_be_bytes(device.pif.ram[i..i + 4].try_into().unwrap()); diff --git a/src/ui/video.rs b/src/ui/video.rs index 0f316aa7..952449b4 100644 --- a/src/ui/video.rs +++ b/src/ui/video.rs @@ -192,6 +192,10 @@ pub fn process_rdp_list() -> u64 { unsafe { rdp_process_commands() } } +pub fn check_framebuffers(address: u32, length: u32) { + unsafe { rdp_check_framebuffers(address, length) } +} + pub fn onscreen_message(_ui: &ui::Ui, message: &str) { unsafe { rdp_onscreen_message(std::ffi::CString::new(message).unwrap().as_ptr()) }; }