From 4cb423d85a181ce74758733f45dfba3558f26173 Mon Sep 17 00:00:00 2001 From: transistor Date: Sun, 2 Oct 2022 13:07:15 -0700 Subject: [PATCH] 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 --- emulator/core/src/host/gfx.rs | 10 ++++----- emulator/core/src/host/traits.rs | 21 ++++++++++++++++++- .../frontends/minifb/src/bin/moa-synth.rs | 20 +++++++++++------- emulator/frontends/minifb/src/lib.rs | 5 ++++- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/emulator/core/src/host/gfx.rs b/emulator/core/src/host/gfx.rs index cee9dfe..60e1fda 100644 --- a/emulator/core/src/host/gfx.rs +++ b/emulator/core/src/host/gfx.rs @@ -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>>, + queue: ClockedQueue, } 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() } } diff --git a/emulator/core/src/host/traits.rs b/emulator/core/src/host/traits.rs index 7df949e..77dce7a 100644 --- a/emulator/core/src/host/traits.rs +++ b/emulator/core/src/host/traits.rs @@ -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 HostData { } } +#[derive(Clone)] +pub struct ClockedQueue(Arc>>); + +impl ClockedQueue { + 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 { diff --git a/emulator/frontends/minifb/src/bin/moa-synth.rs b/emulator/frontends/minifb/src/bin/moa-synth.rs index 918c761..8c32815 100644 --- a/emulator/frontends/minifb/src/bin/moa-synth.rs +++ b/emulator/frontends/minifb/src/bin/moa-synth.rs @@ -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) diff --git a/emulator/frontends/minifb/src/lib.rs b/emulator/frontends/minifb/src/lib.rs index bd7b8fc..58f3ad4 100644 --- a/emulator/frontends/minifb/src/lib.rs +++ b/emulator/frontends/minifb/src/lib.rs @@ -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(); } } }