From d0965c03e12fbee0908df6ddba4b520a41193c04 Mon Sep 17 00:00:00 2001 From: Logan McNaughton <848146+loganmc10@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:18:54 +0100 Subject: [PATCH] dynamically calculate speed limit frequency (#245) * dynamically calculate speed limit frequency * dynamically calculate speed limit frequency * dynamically calculate speed limit frequency * more --- src/device.rs | 4 ++++ src/device/vi.rs | 58 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/device.rs b/src/device.rs index 5f98d9b2..00c7278a 100644 --- a/src/device.rs +++ b/src/device.rs @@ -438,6 +438,10 @@ impl Device { vi_counter: 0, last_origin: 0, internal_frame_counter: 0, + min_wait_time: std::time::Duration::from_secs(1), + frame_time: 0.0, + limit_freq: 2, + limit_freq_check: std::time::Instant::now(), }, vru_window: controller::vru::VruWindow { window_notifier: None, diff --git a/src/device/vi.rs b/src/device/vi.rs index 16ca49f4..9258f793 100644 --- a/src/device/vi.rs +++ b/src/device/vi.rs @@ -29,24 +29,37 @@ pub struct Vi { pub vi_counter: u64, pub last_origin: u32, pub internal_frame_counter: u64, + pub min_wait_time: std::time::Duration, + pub frame_time: f64, + pub limit_freq: u64, + #[serde(skip)] + #[serde(default = "std::time::Instant::now")] + pub limit_freq_check: std::time::Instant, } -const LIMIT_BUFFER: u64 = 3; +const MAX_LIMIT_FREQ: u64 = 3; pub fn set_expected_refresh_rate(device: &mut device::Device) { let expected_refresh_rate = device.vi.clock as f64 / (device.vi.regs[VI_V_SYNC_REG as usize] + 1) as f64 / ((device.vi.regs[VI_H_SYNC_REG as usize] & 0xFFF) + 1) as f64 * 2.0; + device.vi.frame_time = 1.0 / expected_refresh_rate; device.vi.delay = (device.cpu.clock_rate as f64 / expected_refresh_rate) as u64; device.vi.count_per_scanline = device.vi.delay / (device.vi.regs[VI_V_SYNC_REG as usize] + 1) as u64; + create_limiter(device); +} + +fn create_limiter(device: &mut device::Device) { let quota = governor::Quota::with_period(std::time::Duration::from_secs_f64( - (1.0 / expected_refresh_rate) * LIMIT_BUFFER as f64, + device.vi.frame_time * device.vi.limit_freq as f64, )) .unwrap(); - device.vi.limiter = Some(governor::RateLimiter::direct(quota)) + device.vi.limiter = Some(governor::RateLimiter::direct(quota)); + let _ = device.vi.limiter.as_ref().unwrap().check(); + //println!("new limit freq: {}", device.vi.limit_freq); } fn set_vertical_interrupt(device: &mut device::Device) { @@ -134,16 +147,16 @@ pub fn vertical_interrupt_event(device: &mut device::Device) { } device.vi.vi_counter += 1; - if device.vi.vi_counter % LIMIT_BUFFER == 0 && enable_speed_limiter { + if device.vi.vi_counter % device.vi.limit_freq == 0 && enable_speed_limiter { speed_limiter(device); } /* - let vis = if device.cart.pal { 50 } else { 60 }; - if device.vi.vi_counter % vis == 0 { - println!("FPS: {}", device.vi.internal_frame_counter); - device.vi.internal_frame_counter = 0; - } + let vis = if device.cart.pal { 50 } else { 60 }; + if device.vi.vi_counter % vis == 0 { + println!("FPS: {}", device.vi.internal_frame_counter); + device.vi.internal_frame_counter = 0; + } */ /* toggle vi field if in interlaced mode */ @@ -166,13 +179,38 @@ pub fn init(device: &mut device::Device) { } } -fn speed_limiter(device: &device::Device) { +fn speed_limiter(device: &mut device::Device) { let result = device.vi.limiter.as_ref().unwrap().check(); if result.is_err() { let outcome = result.unwrap_err(); let dur = outcome.wait_time_from(governor::clock::DefaultClock::default().now()); spin_sleep::sleep(dur); + if dur < device.vi.min_wait_time { + device.vi.min_wait_time = dur; + } let _ = device.vi.limiter.as_ref().unwrap().check(); + } else { + device.vi.min_wait_time = std::time::Duration::from_secs(0); + } + + if std::time::Instant::now() + .duration_since(device.vi.limit_freq_check) + .as_secs_f64() + > 1.0 + { + if device.vi.min_wait_time.as_secs_f64() == 0.0 && device.vi.limit_freq < MAX_LIMIT_FREQ { + device.vi.limit_freq += 1; + create_limiter(device); + } else if device.vi.min_wait_time.as_secs_f64() > device.vi.frame_time + && device.vi.limit_freq > 1 + { + device.vi.limit_freq -= 1; + create_limiter(device); + } + + //println!("limit freq: {}", device.vi.limit_freq); + device.vi.min_wait_time = std::time::Duration::from_secs(1); + device.vi.limit_freq_check = std::time::Instant::now(); } }