71 lines
2.0 KiB
Rust
71 lines
2.0 KiB
Rust
use crate::base::ControlFlow;
|
|
use crate::prelude::*;
|
|
|
|
use std::time::{Duration, Instant};
|
|
use std::path::Path;
|
|
|
|
/// Uses [std::thread::sleep] to maintain the target FPS specified by the core.
|
|
///
|
|
/// The sleep occurs during either `video_refresh` or at the end of `run()`.
|
|
pub struct SleepFramerateLimitComponent {
|
|
did_sleep: bool,
|
|
started_video: bool,
|
|
fps: f64,
|
|
frame_begin: Instant,
|
|
}
|
|
|
|
impl RetroComponent for SleepFramerateLimitComponent {
|
|
fn post_load_game(&mut self, retro: &mut LibretroWrapper, _rom: &Path) -> crate::base::Result<()> {
|
|
self.fps = retro.get_system_av_info().timing.fps;
|
|
Ok(())
|
|
}
|
|
fn pre_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
|
self.did_sleep = false;
|
|
ControlFlow::Continue
|
|
}
|
|
fn post_run(&mut self, _retro: &mut LibretroWrapper) -> ControlFlow {
|
|
if self.started_video && !self.did_sleep {
|
|
self.do_sleep();
|
|
}
|
|
ControlFlow::Continue
|
|
}
|
|
}
|
|
|
|
impl RetroCallbacks for SleepFramerateLimitComponent {
|
|
fn video_refresh(&mut self, _frame: &VideoFrame) {
|
|
self.started_video = true;
|
|
self.do_sleep();
|
|
}
|
|
fn set_system_av_info(&mut self, system_av_info: &SystemAvInfo) -> Option<bool> {
|
|
self.fps = system_av_info.timing.fps;
|
|
Some(true)
|
|
}
|
|
}
|
|
|
|
impl Default for SleepFramerateLimitComponent {
|
|
fn default() -> Self {
|
|
SleepFramerateLimitComponent {
|
|
did_sleep: false,
|
|
started_video: false,
|
|
fps: 60.0, // default until load_game
|
|
frame_begin: Instant::now(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl SleepFramerateLimitComponent {
|
|
pub fn do_sleep(&mut self) {
|
|
// similar hack to the sample rate, make sure we don't divide by zero.
|
|
let mut spf = 1.0 / self.fps;
|
|
if spf.is_nan() || spf.is_infinite() {
|
|
spf = 1.0 / 60.0;
|
|
}
|
|
Duration::from_secs_f64(spf)
|
|
.checked_sub(self.frame_begin.elapsed())
|
|
.map(std::thread::sleep);
|
|
|
|
self.did_sleep = true;
|
|
self.frame_begin = Instant::now();
|
|
}
|
|
}
|