dynamically calculate speed limit frequency (#245)

* dynamically calculate speed limit frequency

* dynamically calculate speed limit frequency

* dynamically calculate speed limit frequency

* more
This commit is contained in:
Logan McNaughton
2025-02-12 21:18:54 +01:00
committed by GitHub
parent 6ee55ce4ca
commit d0965c03e1
2 changed files with 52 additions and 10 deletions
+4
View File
@@ -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,
+48 -10
View File
@@ -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();
}
}