save state restore

This commit is contained in:
Alex Janka 2023-03-15 13:15:32 +11:00
parent 250cc92536
commit 5aa308f695
2 changed files with 30 additions and 20 deletions

View file

@ -1,7 +1,7 @@
use async_ringbuf::AsyncHeapConsumer; use async_ringbuf::AsyncHeapConsumer;
use futures::executor; use futures::executor;
use gb_emu_lib::{ use gb_emu_lib::{
connect::{AudioOutput, DownsampleType, EmulatorMessage, JoypadButtons, RomFile}, connect::{AudioOutput, CpuSaveState, DownsampleType, EmulatorMessage, JoypadButtons, RomFile},
EmulatorCore, EmulatorCore,
}; };
use nih_plug::prelude::*; use nih_plug::prelude::*;
@ -27,6 +27,7 @@ pub struct GameboyEmu {
vars: Option<EmuVars>, vars: Option<EmuVars>,
frame_receiver: Arc<FrameReceiver>, frame_receiver: Arc<FrameReceiver>,
key_handler: Arc<JoypadSender>, key_handler: Arc<JoypadSender>,
last_save_state: Option<CpuSaveState<[u8; 4]>>,
} }
type FrameReceiver = Mutex<Option<Receiver<Vec<[u8; 4]>>>>; type FrameReceiver = Mutex<Option<Receiver<Vec<[u8; 4]>>>>;
@ -36,6 +37,9 @@ const FRAMES_TO_BUFFER: usize = 1;
const INCLUDE_BOOTROM: bool = false; const INCLUDE_BOOTROM: bool = false;
const DOWNSAMPLE_TYPE: DownsampleType = DownsampleType::ZeroOrderHold; const DOWNSAMPLE_TYPE: DownsampleType = DownsampleType::ZeroOrderHold;
const ROM: &[u8; 65536] = include_bytes!("../../test-roms/mGB1_3_0.gb");
const BOOTROM: &[u8; 256] = include_bytes!("../../bootrom/dmg_boot.bin");
impl Plugin for GameboyEmu { impl Plugin for GameboyEmu {
const NAME: &'static str = "Gameboy"; const NAME: &'static str = "Gameboy";
@ -48,7 +52,7 @@ impl Plugin for GameboyEmu {
const VERSION: &'static str = "0.1"; const VERSION: &'static str = "0.1";
const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[AudioIOLayout { const AUDIO_IO_LAYOUTS: &'static [AudioIOLayout] = &[AudioIOLayout {
main_input_channels: NonZeroU32::new(2), main_input_channels: None,
main_output_channels: NonZeroU32::new(2), main_output_channels: NonZeroU32::new(2),
aux_input_ports: &[], aux_input_ports: &[],
@ -60,6 +64,9 @@ impl Plugin for GameboyEmu {
names: PortNames::const_default(), names: PortNames::const_default(),
}]; }];
const MIDI_INPUT: MidiConfig = MidiConfig::MidiCCs;
const SAMPLE_ACCURATE_AUTOMATION: bool = true;
type SysExMessage = (); type SysExMessage = ();
type BackgroundTask = (); type BackgroundTask = ();
@ -118,25 +125,12 @@ impl Plugin for GameboyEmu {
vars.rx = rx; vars.rx = rx;
} else { } else {
let bootrom = if INCLUDE_BOOTROM { let bootrom = if INCLUDE_BOOTROM {
Some(RomFile::Raw( Some(RomFile::Raw(BOOTROM.to_vec()))
include_bytes!("../../bootrom/dmg_boot.bin").to_vec(),
))
} else { } else {
None None
}; };
let options = gb_emu_lib::Options { let rom = RomFile::Raw(ROM.to_vec());
rom: RomFile::Raw(
include_bytes!("../../test-roms/Tetris.gb")
.to_vec()
.to_vec(),
),
save_path: None,
no_save: true,
bootrom,
connect_serial: false,
verbose: false,
};
let (sender, receiver) = channel::<EmulatorMessage>(); let (sender, receiver) = channel::<EmulatorMessage>();
@ -152,8 +146,22 @@ impl Plugin for GameboyEmu {
*self.frame_receiver.lock().unwrap() = Some(frame_receiver); *self.frame_receiver.lock().unwrap() = Some(frame_receiver);
*self.key_handler.lock().unwrap() = Some(key_handler); *self.key_handler.lock().unwrap() = Some(key_handler);
let mut emulator_core = let window = Box::new(renderer);
EmulatorCore::init(receiver, options, Box::new(renderer), output, None);
let mut emulator_core = if let Some(state) = self.last_save_state.take() {
EmulatorCore::from_save_state(state, rom, receiver, window, output)
} else {
let options = gb_emu_lib::Options {
rom,
save_path: None,
no_save: true,
bootrom,
connect_serial: false,
verbose: false,
};
EmulatorCore::init(receiver, options, window, output, None)
};
emulator_core.run_until_buffer_full(); emulator_core.run_until_buffer_full();
self.vars = Some(EmuVars { self.vars = Some(EmuVars {
@ -169,6 +177,7 @@ impl Plugin for GameboyEmu {
fn deactivate(&mut self) { fn deactivate(&mut self) {
nih_log!("deactivating"); nih_log!("deactivating");
if let Some(ref mut vars) = self.vars { if let Some(ref mut vars) = self.vars {
self.last_save_state = Some(vars.emulator_core.get_save_state());
match vars.sender.send(EmulatorMessage::Stop) { match vars.sender.send(EmulatorMessage::Stop) {
Ok(_) => self.vars = None, Ok(_) => self.vars = None,
Err(e) => nih_log!("error {e} sending message to emulator"), Err(e) => nih_log!("error {e} sending message to emulator"),
@ -181,7 +190,7 @@ impl Vst3Plugin for GameboyEmu {
const VST3_CLASS_ID: [u8; 16] = *b"alexjankagbemula"; const VST3_CLASS_ID: [u8; 16] = *b"alexjankagbemula";
const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] = const VST3_SUBCATEGORIES: &'static [Vst3SubCategory] =
&[Vst3SubCategory::Distortion, Vst3SubCategory::Dynamics]; &[Vst3SubCategory::Instrument, Vst3SubCategory::Synth];
} }
nih_export_vst3!(GameboyEmu); nih_export_vst3!(GameboyEmu);

View file

@ -1,5 +1,6 @@
use crate::processor::memory::mmio::gpu::Colour; use crate::processor::memory::mmio::gpu::Colour;
pub use crate::processor::memory::mmio::joypad::{JoypadButtons, JoypadState}; pub use crate::processor::memory::mmio::joypad::{JoypadButtons, JoypadState};
pub use crate::processor::CpuSaveState;
pub use crate::{HEIGHT, WIDTH}; pub use crate::{HEIGHT, WIDTH};
use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb}; use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb};