its less annoying now lol

This commit is contained in:
Alex Janka 2023-03-17 13:33:38 +11:00
parent 1e01308605
commit 30a94868d1
14 changed files with 70 additions and 77 deletions

View file

@ -88,8 +88,8 @@ fn main() {
.with_no_save(args.no_save) .with_no_save(args.no_save)
.with_verbose(args.verbose); .with_verbose(args.verbose);
let tile_window: Option<Box<dyn Renderer<u32>>> = if args.tile_window { let tile_window: Option<WindowRenderer> = if args.tile_window {
Some(Box::new(WindowRenderer::new(factor, None))) Some(WindowRenderer::new(factor, None))
} else { } else {
None None
}; };
@ -103,7 +103,7 @@ fn main() {
let mut core = EmulatorCore::init( let mut core = EmulatorCore::init(
receiver, receiver,
options, options,
Box::new(WindowRenderer::new(factor, Some(Gilrs::new().unwrap()))), WindowRenderer::new(factor, Some(Gilrs::new().unwrap())),
output, output,
tile_window, tile_window,
); );

View file

@ -12,7 +12,7 @@ default = []
savestate = [] savestate = []
[dependencies] [dependencies]
gb-emu-lib = { path = "../lib", features = ["async"] } gb-emu-lib = { path = "../lib" }
nih_plug = { path = "../vendored/nih-plug", features = ["standalone"] } nih_plug = { path = "../vendored/nih-plug", features = ["standalone"] }
baseview = { path = "../vendored/baseview" } baseview = { path = "../vendored/baseview" }
pixels = "0.11" pixels = "0.11"

View file

@ -49,7 +49,7 @@ struct EmuParams {
struct EmuVars { struct EmuVars {
rx: AsyncHeapConsumer<[f32; 2]>, rx: AsyncHeapConsumer<[f32; 2]>,
sender: Sender<EmulatorMessage>, sender: Sender<EmulatorMessage>,
emulator_core: EmulatorCore<[u8; 4]>, emulator_core: EmulatorCore<[u8; 4], EmulatorRenderer>,
serial_tx: Sender<u8>, serial_tx: Sender<u8>,
} }
@ -236,13 +236,11 @@ impl Plugin for GameboyEmu {
DOWNSAMPLE_TYPE, DOWNSAMPLE_TYPE,
); );
let (renderer, frame_receiver, key_handler) = EmulatorRenderer::new(); let (window, frame_receiver, key_handler) = EmulatorRenderer::new();
*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 window = Box::new(renderer);
let (serial_tx, gb_serial_rx) = mpsc::channel::<u8>(); let (serial_tx, gb_serial_rx) = mpsc::channel::<u8>();
let serial_target = SerialTarget::Custom { let serial_target = SerialTarget::Custom {
rx: Some(gb_serial_rx), rx: Some(gb_serial_rx),

View file

@ -5,7 +5,6 @@ edition = "2021"
[features] [features]
default = [] default = []
async = []
clocked-serial = [] clocked-serial = []
[dependencies] [dependencies]

View file

@ -20,20 +20,6 @@ pub enum RomFile {
Raw(Vec<u8>), Raw(Vec<u8>),
} }
#[cfg(feature = "async")]
pub trait Renderer<Format: From<Colour>>: Send {
fn prepare(&mut self, width: usize, height: usize);
fn display(&mut self, buffer: &[Format]);
fn set_title(&mut self, _title: String) {}
fn latest_joypad_state(&mut self) -> JoypadState;
fn set_rumble(&mut self, _rumbling: bool) {}
}
#[cfg(not(feature = "async"))]
pub trait Renderer<Format: From<Colour>> { pub trait Renderer<Format: From<Colour>> {
fn prepare(&mut self, width: usize, height: usize); fn prepare(&mut self, width: usize, height: usize);

View file

@ -93,18 +93,18 @@ static VERBOSE: OnceCell<bool> = OnceCell::new();
pub const WIDTH: usize = 160; pub const WIDTH: usize = 160;
pub const HEIGHT: usize = 144; pub const HEIGHT: usize = 144;
pub struct EmulatorCore<ColourFormat: From<Colour> + Clone> { pub struct EmulatorCore<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> {
receiver: Receiver<EmulatorMessage>, receiver: Receiver<EmulatorMessage>,
cpu: Cpu<ColourFormat>, cpu: Cpu<ColourFormat, R>,
} }
impl<ColourFormat: From<Colour> + Clone> EmulatorCore<ColourFormat> { impl<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> EmulatorCore<ColourFormat, R> {
pub fn init( pub fn init(
receiver: Receiver<EmulatorMessage>, receiver: Receiver<EmulatorMessage>,
options: Options, options: Options,
mut window: Box<dyn Renderer<ColourFormat>>, mut window: R,
output: AudioOutput, output: AudioOutput,
tile_window: Option<Box<dyn Renderer<ColourFormat>>>, tile_window: Option<R>,
) -> Self { ) -> Self {
if options.verbose { if options.verbose {
VERBOSE.set(true).unwrap(); VERBOSE.set(true).unwrap();
@ -164,7 +164,7 @@ impl<ColourFormat: From<Colour> + Clone> EmulatorCore<ColourFormat> {
) )
} }
fn new(receiver: Receiver<EmulatorMessage>, cpu: Cpu<ColourFormat>) -> Self { fn new(receiver: Receiver<EmulatorMessage>, cpu: Cpu<ColourFormat, R>) -> Self {
Self { receiver, cpu } Self { receiver, cpu }
} }
@ -217,15 +217,15 @@ impl<ColourFormat: From<Colour> + Clone> EmulatorCore<ColourFormat> {
} }
} }
pub fn get_save_state(&self) -> CpuSaveState<ColourFormat> { pub fn get_save_state(&self) -> CpuSaveState<ColourFormat, R> {
CpuSaveState::create(&self.cpu) CpuSaveState::create(&self.cpu)
} }
pub fn from_save_state( pub fn from_save_state(
state: CpuSaveState<ColourFormat>, state: CpuSaveState<ColourFormat, R>,
rom: RomFile, rom: RomFile,
receiver: Receiver<EmulatorMessage>, receiver: Receiver<EmulatorMessage>,
window: Box<dyn Renderer<ColourFormat>>, window: R,
output: AudioOutput, output: AudioOutput,
serial_target: SerialTarget, serial_target: SerialTarget,
) -> Self { ) -> Self {

View file

@ -1,9 +1,10 @@
use crate::{ use crate::{
connect::Renderer,
processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, Reg8, SplitRegister}, processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, Reg8, SplitRegister},
util::{clear_bit, get_bit, set_bit}, util::{clear_bit, get_bit, set_bit},
}; };
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> { impl<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> Cpu<ColourFormat, R> {
pub(crate) fn and(&mut self, first: u8, second: u8) -> u8 { pub(crate) fn and(&mut self, first: u8, second: u8) -> u8 {
let result = first & second; let result = first & second;
self.set_or_clear_flag(Flags::Zero, result == 0x0); self.set_or_clear_flag(Flags::Zero, result == 0x0);

View file

@ -1,10 +1,11 @@
use crate::{ use crate::{
connect::Renderer,
processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, SplitRegister}, processor::{memory::mmio::gpu::Colour, Cpu, Direction, Flags, SplitRegister},
util::{as_signed, get_bit, get_rotation_carry, rotate, Nibbles}, util::{as_signed, get_bit, get_rotation_carry, rotate, Nibbles},
}; };
use std::ops::{BitAnd, BitOr}; use std::ops::{BitAnd, BitOr};
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> { impl<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> Cpu<ColourFormat, R> {
pub(crate) fn pop_word(&mut self) -> u16 { pub(crate) fn pop_word(&mut self) -> u16 {
let mut word: u16 = 0x0; let mut word: u16 = 0x0;
word.set_low(self.memory.get(self.reg.sp)); word.set_low(self.memory.get(self.reg.sp));

View file

@ -22,7 +22,7 @@ pub(crate) mod rom;
pub(crate) type Address = u16; pub(crate) type Address = u16;
pub struct Memory<ColourFormat: From<Colour> + Clone> { pub struct Memory<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> {
bootrom: Option<Vec<u8>>, bootrom: Option<Vec<u8>>,
rom: Rom, rom: Rom,
ram: [u8; 8192], ram: [u8; 8192],
@ -32,7 +32,7 @@ pub struct Memory<ColourFormat: From<Colour> + Clone> {
pub(super) ime_scheduled: u8, pub(super) ime_scheduled: u8,
dma_addr: u8, dma_addr: u8,
joypad: Joypad, joypad: Joypad,
gpu: Gpu<ColourFormat>, gpu: Gpu<ColourFormat, R>,
apu: Apu, apu: Apu,
serial: Serial, serial: Serial,
timers: Timer, timers: Timer,
@ -40,7 +40,7 @@ pub struct Memory<ColourFormat: From<Colour> + Clone> {
#[serde_with::serde_as] #[serde_with::serde_as]
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct MemorySaveState<ColourFormat: From<Colour> + Clone> { pub struct MemorySaveState<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> {
rom: RomSaveState, rom: RomSaveState,
#[serde_as(as = "[_; 8192]")] #[serde_as(as = "[_; 8192]")]
ram: [u8; 8192], ram: [u8; 8192],
@ -51,14 +51,16 @@ pub struct MemorySaveState<ColourFormat: From<Colour> + Clone> {
pub(super) ime_scheduled: u8, pub(super) ime_scheduled: u8,
dma_addr: u8, dma_addr: u8,
joypad: Joypad, joypad: Joypad,
gpu: GpuSaveState<ColourFormat>, gpu: GpuSaveState<ColourFormat, R>,
apu: ApuSaveState, apu: ApuSaveState,
serial: SerialSaveState, serial: SerialSaveState,
timers: Timer, timers: Timer,
} }
impl<ColourFormat: From<Colour> + Clone> MemorySaveState<ColourFormat> { impl<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>>
pub fn create(memory: &Memory<ColourFormat>) -> Self { MemorySaveState<ColourFormat, R>
{
pub fn create(memory: &Memory<ColourFormat, R>) -> Self {
Self { Self {
rom: RomSaveState::create(&memory.rom), rom: RomSaveState::create(&memory.rom),
ram: memory.ram, ram: memory.ram,
@ -76,14 +78,14 @@ impl<ColourFormat: From<Colour> + Clone> MemorySaveState<ColourFormat> {
} }
} }
impl<ColourFormat: From<Colour> + Clone> Memory<ColourFormat> { impl<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> Memory<ColourFormat, R> {
pub fn init( pub fn init(
bootrom: Option<Vec<u8>>, bootrom: Option<Vec<u8>>,
rom: Rom, rom: Rom,
window: Box<dyn Renderer<ColourFormat>>, window: R,
output: AudioOutput, output: AudioOutput,
serial_target: SerialTarget, serial_target: SerialTarget,
tile_window: Option<Box<dyn Renderer<ColourFormat>>>, tile_window: Option<R>,
) -> Self { ) -> Self {
Self { Self {
bootrom, bootrom,
@ -274,9 +276,9 @@ impl<ColourFormat: From<Colour> + Clone> Memory<ColourFormat> {
} }
pub fn from_save_state( pub fn from_save_state(
state: MemorySaveState<ColourFormat>, state: MemorySaveState<ColourFormat, R>,
data: Vec<u8>, data: Vec<u8>,
window: Box<dyn Renderer<ColourFormat>>, window: R,
output: AudioOutput, output: AudioOutput,
serial_target: SerialTarget, serial_target: SerialTarget,
) -> Self { ) -> Self {
@ -298,7 +300,7 @@ impl<ColourFormat: From<Colour> + Clone> Memory<ColourFormat> {
} }
} }
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> { impl<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> Cpu<ColourFormat, R> {
pub fn increment_timers(&mut self, machine_cycles: u8) { pub fn increment_timers(&mut self, machine_cycles: u8) {
let steps = (machine_cycles as usize) * 4; let steps = (machine_cycles as usize) * 4;

View file

@ -1,3 +1,5 @@
use std::marker::PhantomData;
use self::{ use self::{
tile_window::TileWindow, tile_window::TileWindow,
types::{ types::{
@ -21,18 +23,18 @@ mod types;
const TILE_WINDOW_WIDTH: usize = 16 * 8; const TILE_WINDOW_WIDTH: usize = 16 * 8;
const TILE_WINDOW_HEIGHT: usize = 24 * 8; const TILE_WINDOW_HEIGHT: usize = 24 * 8;
pub struct Gpu<Format: From<Colour>> { pub struct Gpu<Format: From<Colour>, R: Renderer<Format>> {
pub buffer: Vec<Format>, pub buffer: Vec<Format>,
pub vram: Vram, pub vram: Vram,
pub oam: Oam, pub oam: Oam,
pub window: Box<dyn Renderer<Format>>, pub window: R,
is_bg_zero: Vec<bool>, is_bg_zero: Vec<bool>,
lcdc: Lcdc, lcdc: Lcdc,
stat: Stat, stat: Stat,
mode_clock: usize, mode_clock: usize,
scanline: u8, scanline: u8,
lyc: u8, lyc: u8,
tile_window: Option<TileWindow<Format>>, tile_window: Option<TileWindow<Format, R>>,
window_lc: u8, window_lc: u8,
has_window_been_enabled: bool, has_window_been_enabled: bool,
bg_palette: Palette, bg_palette: Palette,
@ -46,7 +48,7 @@ pub struct Gpu<Format: From<Colour>> {
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct GpuSaveState<Format: From<Colour>> { pub struct GpuSaveState<Format: From<Colour>, R: Renderer<Format>> {
buffer: Vec<Format>, buffer: Vec<Format>,
vram: Vram, vram: Vram,
oam: Oam, oam: Oam,
@ -66,10 +68,12 @@ pub struct GpuSaveState<Format: From<Colour>> {
wx: u8, wx: u8,
wy: u8, wy: u8,
prev_stat: bool, prev_stat: bool,
#[serde(skip)]
spooky: PhantomData<R>,
} }
impl<Format: From<Colour> + Clone> GpuSaveState<Format> { impl<Format: From<Colour> + Clone, R: Renderer<Format>> GpuSaveState<Format, R> {
pub fn create(gpu: &Gpu<Format>) -> Self { pub fn create(gpu: &Gpu<Format, R>) -> Self {
Self { Self {
buffer: gpu.buffer.clone(), buffer: gpu.buffer.clone(),
vram: gpu.vram, vram: gpu.vram,
@ -90,15 +94,13 @@ impl<Format: From<Colour> + Clone> GpuSaveState<Format> {
wx: gpu.wx, wx: gpu.wx,
wy: gpu.wy, wy: gpu.wy,
prev_stat: gpu.prev_stat, prev_stat: gpu.prev_stat,
spooky: PhantomData,
} }
} }
} }
impl<Format: From<Colour> + Clone> Gpu<Format> { impl<Format: From<Colour> + Clone, R: Renderer<Format>> Gpu<Format, R> {
pub fn new( pub fn new(window: R, tile_window_renderer: Option<R>) -> Self {
window: Box<dyn Renderer<Format>>,
tile_window_renderer: Option<Box<dyn Renderer<Format>>>,
) -> Self {
let tile_window = if let Some(mut tile_window_renderer) = tile_window_renderer { let tile_window = if let Some(mut tile_window_renderer) = tile_window_renderer {
tile_window_renderer.prepare(TILE_WINDOW_WIDTH, TILE_WINDOW_HEIGHT); tile_window_renderer.prepare(TILE_WINDOW_WIDTH, TILE_WINDOW_HEIGHT);
Some(TileWindow::new(tile_window_renderer)) Some(TileWindow::new(tile_window_renderer))
@ -133,9 +135,9 @@ impl<Format: From<Colour> + Clone> Gpu<Format> {
} }
pub fn from_save_state( pub fn from_save_state(
state: GpuSaveState<Format>, state: GpuSaveState<Format, R>,
window: Box<dyn Renderer<Format>>, window: R,
tile_window_renderer: Option<Box<dyn Renderer<Format>>>, tile_window_renderer: Option<R>,
) -> Self { ) -> Self {
let tile_window = if let Some(mut tile_window_renderer) = tile_window_renderer { let tile_window = if let Some(mut tile_window_renderer) = tile_window_renderer {
tile_window_renderer.prepare(TILE_WINDOW_WIDTH, TILE_WINDOW_HEIGHT); tile_window_renderer.prepare(TILE_WINDOW_WIDTH, TILE_WINDOW_HEIGHT);

View file

@ -1,11 +1,14 @@
use crate::util::{get_bit, set_or_clear_bit}; use crate::{
connect::Renderer,
util::{get_bit, set_or_clear_bit},
};
use super::{ use super::{
types::{DrawMode, ObjSize, Palette, TiledataArea, TilemapArea}, types::{DrawMode, ObjSize, Palette, TiledataArea, TilemapArea},
Colour, Gpu, Colour, Gpu,
}; };
impl<Format: From<Colour>> Gpu<Format> { impl<Format: From<Colour>, R: Renderer<Format>> Gpu<Format, R> {
pub fn update_lcdc(&mut self, data: u8) { pub fn update_lcdc(&mut self, data: u8) {
self.lcdc.enable = get_bit(data, 7); self.lcdc.enable = get_bit(data, 7);
self.lcdc.window_tilemap = if get_bit(data, 6) { self.lcdc.window_tilemap = if get_bit(data, 6) {

View file

@ -6,13 +6,13 @@ use crate::{
use super::{types::Vram, Colour}; use super::{types::Vram, Colour};
pub(super) struct TileWindow<Format: From<Colour>> { pub(super) struct TileWindow<Format: From<Colour>, R: Renderer<Format>> {
sprite_buffer: Vec<Format>, sprite_buffer: Vec<Format>,
sprite_renderer: Box<dyn Renderer<Format>>, sprite_renderer: R,
} }
impl<Format: From<Colour>> TileWindow<Format> { impl<Format: From<Colour>, R: Renderer<Format>> TileWindow<Format, R> {
pub(super) fn new(window: Box<dyn Renderer<Format>>) -> Self { pub(super) fn new(window: R) -> Self {
let mut sprite_buffer = Vec::new(); let mut sprite_buffer = Vec::new();
sprite_buffer.reserve_exact(TILE_WINDOW_WIDTH * TILE_WINDOW_HEIGHT); sprite_buffer.reserve_exact(TILE_WINDOW_WIDTH * TILE_WINDOW_HEIGHT);

View file

@ -23,8 +23,8 @@ pub(crate) enum Direction {
Right, Right,
} }
pub struct Cpu<ColourFormat: From<Colour> + Clone> { pub struct Cpu<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> {
pub memory: Memory<ColourFormat>, pub memory: Memory<ColourFormat, R>,
pub reg: Registers, pub reg: Registers,
pub last_instruction: u8, pub last_instruction: u8,
last_instruction_addr: u16, last_instruction_addr: u16,
@ -33,8 +33,8 @@ pub struct Cpu<ColourFormat: From<Colour> + Clone> {
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct CpuSaveState<ColourFormat: From<Colour> + Clone> { pub struct CpuSaveState<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> {
memory: MemorySaveState<ColourFormat>, memory: MemorySaveState<ColourFormat, R>,
reg: Registers, reg: Registers,
last_instruction: u8, last_instruction: u8,
last_instruction_addr: u16, last_instruction_addr: u16,
@ -42,8 +42,8 @@ pub struct CpuSaveState<ColourFormat: From<Colour> + Clone> {
should_halt_bug: bool, should_halt_bug: bool,
} }
impl<ColourFormat: From<Colour> + Clone> CpuSaveState<ColourFormat> { impl<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> CpuSaveState<ColourFormat, R> {
pub fn create(cpu: &Cpu<ColourFormat>) -> Self { pub fn create(cpu: &Cpu<ColourFormat, R>) -> Self {
Self { Self {
memory: MemorySaveState::create(&cpu.memory), memory: MemorySaveState::create(&cpu.memory),
reg: cpu.reg, reg: cpu.reg,
@ -55,8 +55,8 @@ impl<ColourFormat: From<Colour> + Clone> CpuSaveState<ColourFormat> {
} }
} }
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> { impl<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> Cpu<ColourFormat, R> {
pub fn new(mut memory: Memory<ColourFormat>, run_bootrom: bool) -> Self { pub fn new(mut memory: Memory<ColourFormat, R>, run_bootrom: bool) -> Self {
if !run_bootrom { if !run_bootrom {
memory.cpu_ram_init(); memory.cpu_ram_init();
} }
@ -155,9 +155,9 @@ impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> {
} }
pub fn from_save_state( pub fn from_save_state(
state: CpuSaveState<ColourFormat>, state: CpuSaveState<ColourFormat, R>,
data: Vec<u8>, data: Vec<u8>,
window: Box<dyn Renderer<ColourFormat>>, window: R,
output: AudioOutput, output: AudioOutput,
serial_target: SerialTarget, serial_target: SerialTarget,
) -> Self { ) -> Self {

View file

@ -1,4 +1,5 @@
use crate::{ use crate::{
connect::Renderer,
processor::{ processor::{
instructions::instructions::{res, set}, instructions::instructions::{res, set},
Cpu, Flags, Reg8, SplitRegister, Cpu, Flags, Reg8, SplitRegister,
@ -8,7 +9,7 @@ use crate::{
use super::memory::mmio::gpu::Colour; use super::memory::mmio::gpu::Colour;
impl<ColourFormat: From<Colour> + Clone> Cpu<ColourFormat> { impl<ColourFormat: From<Colour> + Clone, R: Renderer<ColourFormat>> Cpu<ColourFormat, R> {
pub fn run_opcode(&mut self, opcode: u8) -> u8 { pub fn run_opcode(&mut self, opcode: u8) -> u8 {
match opcode { match opcode {
0x00 => { 0x00 => {