mirror of
https://github.com/transistorfet/moa.git
synced 2025-03-03 17:29:24 +00:00
Fixed minifb frame updater to allow slower framerates
If the sim is running slower than 60Hz, it was using the frame limiter to not apply because no frame was drawn, and so it would end up running at full speed. Minifb can save the last frame without cloning it, and redraw the same frame if no new frame is ready, which allows the limiter to still delay the next frame, so slower speeds work. This was also preventing things that didn't update the screen from allowing inputs including escape to have any effect
This commit is contained in:
parent
a9d51fb919
commit
4cb423d85a
@ -5,7 +5,7 @@ use std::collections::VecDeque;
|
||||
|
||||
use crate::Clock;
|
||||
use crate::Error;
|
||||
use crate::host::traits::{WindowUpdater, BlitableSurface};
|
||||
use crate::host::traits::{WindowUpdater, BlitableSurface, ClockedQueue};
|
||||
|
||||
|
||||
pub const MASK_COLOUR: u32 = 0xFFFFFFFF;
|
||||
@ -111,23 +111,23 @@ impl WindowUpdater for FrameSwapper {
|
||||
#[derive(Clone)]
|
||||
pub struct FrameQueue {
|
||||
max_size: (u32, u32),
|
||||
queue: Arc<Mutex<VecDeque<(Clock, Frame)>>>,
|
||||
queue: ClockedQueue<Frame>,
|
||||
}
|
||||
|
||||
impl FrameQueue {
|
||||
pub fn new(width: u32, height: u32) -> Self {
|
||||
Self {
|
||||
max_size: (width, height),
|
||||
queue: Arc::new(Mutex::new(VecDeque::new())),
|
||||
queue: ClockedQueue::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&self, clock: Clock, frame: Frame) {
|
||||
self.queue.lock().unwrap().push_back((clock, frame));
|
||||
self.queue.push(clock, frame);
|
||||
}
|
||||
|
||||
pub fn latest(&self) -> Option<(Clock, Frame)> {
|
||||
self.queue.lock().unwrap().drain(..).last()
|
||||
self.queue.pop_latest()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::{Arc, Mutex, MutexGuard};
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::{Clock, Error};
|
||||
use crate::host::keys::Key;
|
||||
use crate::host::gfx::Frame;
|
||||
use crate::host::controllers::{ControllerDevice, ControllerEvent};
|
||||
@ -96,6 +97,24 @@ impl<T: Copy> HostData<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClockedQueue<T>(Arc<Mutex<VecDeque<(Clock, T)>>>);
|
||||
|
||||
impl<T: Clone> ClockedQueue<T> {
|
||||
pub fn new() -> Self {
|
||||
Self(Arc::new(Mutex::new(VecDeque::new())))
|
||||
}
|
||||
|
||||
pub fn push(&self, clock: Clock, data: T) {
|
||||
self.0.lock().unwrap().push_back((clock, data));
|
||||
}
|
||||
|
||||
pub fn pop_latest(&self) -> Option<(Clock, T)> {
|
||||
self.0.lock().unwrap().drain(..).last()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct DummyAudio();
|
||||
|
||||
impl Audio for DummyAudio {
|
||||
|
@ -4,8 +4,8 @@ use std::sync::mpsc;
|
||||
use moa_minifb;
|
||||
use moa_peripherals_yamaha::{Ym2612, Sn76489};
|
||||
|
||||
use moa_core::host::gfx::Frame;
|
||||
use moa_core::host::{Host, KeyboardUpdater, Key};
|
||||
use moa_core::host::gfx::{Frame, FrameQueue};
|
||||
use moa_core::host::{Host, WindowUpdater, KeyboardUpdater, Key};
|
||||
use moa_core::{System, Error, ClockElapsed, Address, Addressable, Steppable, Transmutable, TransmutableBox, wrap_transmutable};
|
||||
|
||||
|
||||
@ -18,12 +18,14 @@ impl KeyboardUpdater for SynthControlsUpdater {
|
||||
}
|
||||
|
||||
struct SynthControl {
|
||||
queue: FrameQueue,
|
||||
receiver: mpsc::Receiver<(Key, bool)>,
|
||||
}
|
||||
|
||||
impl SynthControl {
|
||||
pub fn new(receiver: mpsc::Receiver<(Key, bool)>) -> Self {
|
||||
pub fn new(queue: FrameQueue, receiver: mpsc::Receiver<(Key, bool)>) -> Self {
|
||||
Self {
|
||||
queue,
|
||||
receiver,
|
||||
}
|
||||
}
|
||||
@ -49,7 +51,11 @@ impl Steppable for SynthControl {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(1_000_000)
|
||||
let size = self.queue.max_size();
|
||||
let frame = Frame::new(size.0, size.1);
|
||||
self.queue.add(system.clock, frame);
|
||||
|
||||
Ok(33_000_000)
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,8 +94,9 @@ fn main() {
|
||||
moa_minifb::run(matches, |host| {
|
||||
let mut system = System::new();
|
||||
|
||||
let queue = FrameQueue::new(384, 128);
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
let control = wrap_transmutable(SynthControl::new(receiver));
|
||||
let control = wrap_transmutable(SynthControl::new(queue.clone(), receiver));
|
||||
system.add_device("control", control)?;
|
||||
|
||||
let ym_sound = wrap_transmutable(Ym2612::create(host)?);
|
||||
@ -99,8 +106,7 @@ fn main() {
|
||||
let sn_sound = wrap_transmutable(Sn76489::create(host)?);
|
||||
system.add_addressable_device(0x10, sn_sound)?;
|
||||
|
||||
let frame = Frame::new_shared(384, 128);
|
||||
host.add_window(Frame::new_updater(frame.clone()))?;
|
||||
host.add_window(Box::new(queue.clone()))?;
|
||||
host.register_keyboard(Box::new(SynthControlsUpdater(sender)))?;
|
||||
|
||||
Ok(system)
|
||||
|
@ -9,6 +9,7 @@ use clap::{App, Arg, ArgMatches};
|
||||
|
||||
use moa_core::{System, Error, Clock};
|
||||
use moa_core::host::{Host, HostData, ControllerUpdater, KeyboardUpdater, WindowUpdater, Audio, ControllerDevice};
|
||||
use moa_core::host::gfx::Frame;
|
||||
|
||||
use moa_common::audio::{AudioOutput, AudioMixer, AudioSource};
|
||||
|
||||
@ -226,6 +227,7 @@ impl MiniFrontend {
|
||||
|
||||
let mut average_time = 0;
|
||||
let mut update_timer = Instant::now();
|
||||
let mut last_frame = Frame::new(size.0, size.1);
|
||||
while window.is_open() && !window.is_key_down(Key::Escape) {
|
||||
let frame_time = update_timer.elapsed().as_micros();
|
||||
update_timer = Instant::now();
|
||||
@ -259,8 +261,9 @@ impl MiniFrontend {
|
||||
|
||||
if let Some(updater) = self.window.as_mut() {
|
||||
if let Ok(frame) = updater.take_frame() {
|
||||
window.update_with_buffer(&frame.bitmap, frame.width as usize, frame.height as usize).unwrap();
|
||||
last_frame = frame
|
||||
}
|
||||
window.update_with_buffer(&last_frame.bitmap, last_frame.width as usize, last_frame.height as usize).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user