vst specific config

This commit is contained in:
Alex Janka 2023-10-05 12:42:03 +11:00
parent a24a49fdcb
commit ebc84e24d7
4 changed files with 101 additions and 34 deletions

1
Cargo.lock generated
View file

@ -3507,6 +3507,7 @@ dependencies = [
"keyboard-types", "keyboard-types",
"nih_plug", "nih_plug",
"raw-window-handle", "raw-window-handle",
"serde",
] ]
[[package]] [[package]]

View file

@ -8,9 +8,10 @@ name = "vst"
crate-type = ["cdylib", "rlib"] crate-type = ["cdylib", "rlib"]
[features] [features]
default = ["vulkan"] default = ["pixels"]
pixels = ["gb-emu-lib/pixels-renderer"] pixels = ["gb-emu-lib/pixels-renderer"]
vulkan = ["dep:raw-window-handle", "gb-emu-lib/vulkan-static"] vulkan = ["dep:raw-window-handle", "gb-emu-lib/vulkan-renderer"]
vulkan-static = ["vulkan", "gb-emu-lib/vulkan-static"]
[dependencies] [dependencies]
gb-emu-lib = { path = "../lib", features = ["config"] } gb-emu-lib = { path = "../lib", features = ["config"] }
@ -20,3 +21,4 @@ async-ringbuf = "0.1"
futures = "0.3" futures = "0.3"
keyboard-types = "0.6.2" keyboard-types = "0.6.2"
raw-window-handle = { version = "0.5", optional = true } raw-window-handle = { version = "0.5", optional = true }
serde = { version = "1.0", features = ["derive"] }

View file

@ -1,4 +1,5 @@
use async_ringbuf::AsyncHeapConsumer; use async_ringbuf::AsyncHeapConsumer;
use baseview::Size;
use futures::executor; use futures::executor;
use gb_emu_lib::{ use gb_emu_lib::{
config::ConfigManager, config::ConfigManager,
@ -6,15 +7,16 @@ use gb_emu_lib::{
AudioOutput, CgbRomType, DownsampleType, EmulatorCoreTrait, EmulatorMessage, AudioOutput, CgbRomType, DownsampleType, EmulatorCoreTrait, EmulatorMessage,
EmulatorOptions, JoypadButtons, NoCamera, RomFile, SerialTarget, EmulatorOptions, JoypadButtons, NoCamera, RomFile, SerialTarget,
}, },
EmulatorCore, EmulatorCore, HEIGHT, WIDTH,
}; };
use nih_plug::prelude::*; use nih_plug::prelude::*;
use nih_plug::{midi::MidiResult::Basic, params::persist::PersistentField}; use nih_plug::{midi::MidiResult::Basic, params::persist::PersistentField};
use serde::{Deserialize, Serialize};
use std::{ use std::{
path::PathBuf, path::PathBuf,
sync::{ sync::{
mpsc::{self, channel, Receiver, Sender}, mpsc::{self, channel, Receiver, Sender},
Arc, Mutex, RwLock, Arc, Mutex, OnceLock, RwLock,
}, },
}; };
use ui::{Emulator, EmulatorRenderer}; use ui::{Emulator, EmulatorRenderer};
@ -54,6 +56,48 @@ struct EmuVars {
serial_tx: Sender<u8>, serial_tx: Sender<u8>,
} }
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(default)]
pub struct VstConfig {
scale_factor: usize,
rom: String,
force_skip_bootrom: bool,
}
impl Default for VstConfig {
fn default() -> Self {
Self {
scale_factor: 3,
rom: String::from(""),
force_skip_bootrom: true,
}
}
}
struct Configs {
vst_config: VstConfig,
emu_config: gb_emu_lib::config::Config,
config_dir: PathBuf,
}
impl Configs {
fn get() -> Self {
let config_manager = ConfigManager::get().expect("Could not open config folder");
let emu_config = config_manager.load_or_create_base_config();
let vst_config = config_manager.load_or_create_config::<VstConfig>("vst");
if vst_config.rom.is_empty() {
panic!("no rom provided!!");
}
Self {
vst_config,
emu_config,
config_dir: config_manager.dir(),
}
}
}
#[derive(Default)] #[derive(Default)]
pub struct GameboyEmu { pub struct GameboyEmu {
vars: Option<EmuVars>, vars: Option<EmuVars>,
@ -72,7 +116,7 @@ type JoypadSender = Mutex<Option<Sender<JoypadInfo>>>;
const BUFFERS_PER_FRAME: usize = 1; const BUFFERS_PER_FRAME: usize = 1;
const DOWNSAMPLE_TYPE: DownsampleType = DownsampleType::Linear; const DOWNSAMPLE_TYPE: DownsampleType = DownsampleType::Linear;
const ROM: &[u8; 65536] = include_bytes!("../../test-roms/mGB-save-patch.gb"); static CONFIGS: OnceLock<Configs> = OnceLock::new();
impl Plugin for GameboyEmu { impl Plugin for GameboyEmu {
const NAME: &'static str = "Gameboy"; const NAME: &'static str = "Gameboy";
@ -204,10 +248,18 @@ impl Plugin for GameboyEmu {
} }
fn editor(&mut self, _: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> { fn editor(&mut self, _: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
let configs = CONFIGS.get_or_init(Configs::get);
let size = Size::new(
(WIDTH * configs.vst_config.scale_factor) as f64,
(HEIGHT * configs.vst_config.scale_factor) as f64,
);
Some(Box::new(Emulator::new( Some(Box::new(Emulator::new(
self.frame_receiver.clone(), self.frame_receiver.clone(),
self.key_handler.clone(), self.key_handler.clone(),
self.shader_path.clone(), self.shader_path.clone(),
size,
))) )))
} }
@ -227,18 +279,24 @@ impl Plugin for GameboyEmu {
vars.emulator_core.replace_output(output); vars.emulator_core.replace_output(output);
vars.rx = rx; vars.rx = rx;
} else { } else {
let (rom, camera) = RomFile::Raw(ROM.to_vec()) let configs = CONFIGS.get_or_init(Configs::get);
let rom_path = configs.config_dir.join(configs.vst_config.rom.clone());
if !rom_path.is_file() {
panic!("{rom_path:?} is not a file!");
}
let (rom, camera) = RomFile::Path(rom_path)
.load(gb_emu_lib::connect::SramType::None, NoCamera::default()) .load(gb_emu_lib::connect::SramType::None, NoCamera::default())
.expect("failed to load rom"); .expect("failed to load rom");
let config_manager = ConfigManager::get().expect("Could not open config folder"); let shader_path =
let config = config_manager.load_or_create_base_config(); if rom.rom_type == CgbRomType::CgbOnly || configs.emu_config.prefer_cgb {
let shader_path = if rom.rom_type == CgbRomType::CgbOnly || config.prefer_cgb { configs.emu_config.vulkan_config.cgb_shader_path.as_ref()
config.vulkan_config.cgb_shader_path.as_ref() } else {
} else { configs.emu_config.vulkan_config.dmg_shader_path.as_ref()
config.vulkan_config.dmg_shader_path.as_ref() }
} .map(|v| configs.config_dir.join(v));
.map(|v| config_manager.dir().join(v));
let (sender, receiver) = channel::<EmulatorMessage>(); let (sender, receiver) = channel::<EmulatorMessage>();
@ -260,16 +318,20 @@ impl Plugin for GameboyEmu {
tx: None, tx: None,
}; };
let will_skip_bootrom =
configs.vst_config.force_skip_bootrom || !configs.emu_config.show_bootrom;
let mut emulator_core = { let mut emulator_core = {
let options = EmulatorOptions::new_with_config( let options = EmulatorOptions::new_with_config(
config, configs.emu_config.clone(),
config_manager.dir(), configs.config_dir.clone(),
window, window,
rom, rom,
output, output,
) )
.with_serial_target(serial_target) .with_serial_target(serial_target)
.with_sram_buffer(self.params.sram_save.state.clone()); .with_sram_buffer(self.params.sram_save.state.clone())
.with_show_bootrom(!will_skip_bootrom);
EmulatorCore::init(receiver, options, camera) EmulatorCore::init(receiver, options, camera)
}; };

View file

@ -6,9 +6,7 @@ use std::{
}, },
}; };
use baseview::{ use baseview::{Event, EventStatus, Size, Window, WindowEvent, WindowHandler, WindowOpenOptions};
Event, EventStatus, Size, Window, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
};
use gb_emu_lib::{ use gb_emu_lib::{
connect::{JoypadButtons, JoypadState, Renderer, ResolutionData, HEIGHT, WIDTH}, connect::{JoypadButtons, JoypadState, Renderer, ResolutionData, HEIGHT, WIDTH},
renderer::{RendererBackend, RendererBackendManager, WindowOptions}, renderer::{RendererBackend, RendererBackendManager, WindowOptions},
@ -16,12 +14,13 @@ use gb_emu_lib::{
use keyboard_types::{Code, KeyState}; use keyboard_types::{Code, KeyState};
use nih_plug::prelude::*; use nih_plug::prelude::*;
use crate::{Frame, FrameReceiver, JoypadInfo, JoypadSender}; use crate::{Configs, Frame, FrameReceiver, JoypadInfo, JoypadSender, CONFIGS};
pub struct Emulator { pub struct Emulator {
frame_receiver: Arc<FrameReceiver>, frame_receiver: Arc<FrameReceiver>,
joypad_sender: Arc<JoypadSender>, joypad_sender: Arc<JoypadSender>,
shader_path: Arc<Mutex<Option<PathBuf>>>, shader_path: Arc<Mutex<Option<PathBuf>>>,
size: Size,
} }
impl Emulator { impl Emulator {
@ -29,17 +28,17 @@ impl Emulator {
frame_receiver: Arc<FrameReceiver>, frame_receiver: Arc<FrameReceiver>,
joypad_sender: Arc<JoypadSender>, joypad_sender: Arc<JoypadSender>,
shader_path: Arc<Mutex<Option<PathBuf>>>, shader_path: Arc<Mutex<Option<PathBuf>>>,
size: Size,
) -> Self { ) -> Self {
Self { Self {
frame_receiver, frame_receiver,
joypad_sender, joypad_sender,
shader_path, shader_path,
size,
} }
} }
} }
const EXTRA_SCALE: usize = 4;
impl Editor for Emulator { impl Editor for Emulator {
fn spawn( fn spawn(
&self, &self,
@ -64,20 +63,27 @@ impl Editor for Emulator {
#[cfg(feature = "vulkan")] #[cfg(feature = "vulkan")]
let shader_path = self.shader_path.lock().unwrap().clone(); let shader_path = self.shader_path.lock().unwrap().clone();
// let shader_path = None; // let shader_path = None;
let scale_factor = CONFIGS.get_or_init(Configs::get).vst_config.scale_factor;
let size = Size::new(
(WIDTH * scale_factor) as f64,
(HEIGHT * scale_factor) as f64,
);
Window::open_parented( Window::open_parented(
&parent, &parent,
WindowOpenOptions { WindowOpenOptions {
title: String::from("gb-emu"), title: String::from("gb-emu"),
size: Size::new((WIDTH * EXTRA_SCALE) as f64, (HEIGHT * EXTRA_SCALE) as f64), size,
scale: baseview::WindowScalePolicy::SystemScaleFactor, scale: baseview::WindowScalePolicy::SystemScaleFactor,
gl_config: None, gl_config: None,
}, },
|w| { move |w| {
EmulatorWindow::new( EmulatorWindow::new(
w, w,
fr_cloned, fr_cloned,
js_cloned, js_cloned,
size,
#[cfg(feature = "vulkan")] #[cfg(feature = "vulkan")]
shader_path, shader_path,
) )
@ -87,11 +93,12 @@ impl Editor for Emulator {
self.frame_receiver.clone(), self.frame_receiver.clone(),
self.joypad_sender.clone(), self.joypad_sender.clone(),
self.shader_path.clone(), self.shader_path.clone(),
size,
)) ))
} }
fn size(&self) -> (u32, u32) { fn size(&self) -> (u32, u32) {
((WIDTH * EXTRA_SCALE) as u32, (HEIGHT * EXTRA_SCALE) as u32) (self.size.width as u32, self.size.height as u32)
} }
fn set_scale_factor(&self, _factor: f32) -> bool { fn set_scale_factor(&self, _factor: f32) -> bool {
@ -118,17 +125,12 @@ impl EmulatorWindow {
window: &mut Window, window: &mut Window,
frame_receiver: Arc<FrameReceiver>, frame_receiver: Arc<FrameReceiver>,
joypad_sender: Arc<JoypadSender>, joypad_sender: Arc<JoypadSender>,
size: Size,
#[cfg(feature = "vulkan")] shader_path: Option<PathBuf>, #[cfg(feature = "vulkan")] shader_path: Option<PathBuf>,
) -> Self { ) -> Self {
let info = WindowInfo::from_logical_size(
Size::new(WIDTH as f64, HEIGHT as f64),
EXTRA_SCALE as f64,
);
let physical_size = info.physical_size();
let current_resolution = ResolutionData { let current_resolution = ResolutionData {
real_width: physical_size.width, real_width: size.width as u32,
real_height: physical_size.height, real_height: size.height as u32,
scaled_width: WIDTH as u32, scaled_width: WIDTH as u32,
scaled_height: HEIGHT as u32, scaled_height: HEIGHT as u32,
}; };