mirror of
https://github.com/gopher64/gopher64.git
synced 2026-07-11 01:25:20 +02:00
Add RDP to savestate (#348)
* organize RDP device * more * more * more * more * more * more * more * more
This commit is contained in:
@@ -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");
|
||||
|
||||
+72
-55
@@ -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<bool> rdram_dirty;
|
||||
uint64_t sync_signal;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float SourceSize[4];
|
||||
float OutputSize[4];
|
||||
} Push;
|
||||
|
||||
static std::vector<bool> 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<const uint32_t *>(gfx_info.DMEM + offset));
|
||||
cmd_data[2 * cmd_ptr + 1] = SDL_Swap32BE(*reinterpret_cast<const uint32_t *>(gfx_info.DMEM + offset + 4));
|
||||
rdp_device.cmd_data[2 * rdp_device.cmd_ptr + 0] = SDL_Swap32BE(*reinterpret_cast<const uint32_t *>(gfx_info.DMEM + offset));
|
||||
rdp_device.cmd_data[2 * rdp_device.cmd_ptr + 1] = SDL_Swap32BE(*reinterpret_cast<const uint32_t *>(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<const uint32_t *>(gfx_info.RDRAM + offset);
|
||||
cmd_data[2 * cmd_ptr + 1] = *reinterpret_cast<const uint32_t *>(gfx_info.RDRAM + offset + 4);
|
||||
rdp_device.cmd_data[2 * rdp_device.cmd_ptr + 0] = *reinterpret_cast<const uint32_t *>(gfx_info.RDRAM + offset);
|
||||
rdp_device.cmd_data[2 * rdp_device.cmd_ptr + 1] = *reinterpret_cast<const uint32_t *>(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;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <cstdint>
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
+5
-2
@@ -70,7 +70,8 @@ where
|
||||
}
|
||||
|
||||
pub fn create_savestate(device: &device::Device) {
|
||||
ui::video::full_sync();
|
||||
let mut rdp_state: Vec<u8> = 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::Device>(&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");
|
||||
}
|
||||
|
||||
+11
-3
@@ -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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user