From 0c8afc76b978276c06d8ec65e8f25e09c6feda2f Mon Sep 17 00:00:00 2001 From: Isaac Marovitz Date: Tue, 30 Apr 2024 14:38:23 -0400 Subject: [PATCH] Avoid extra framebuffer copies --- src/components/cpu.rs | 7 +++++-- src/components/mmu.rs | 15 +++++++++------ src/components/ppu.rs | 32 ++++++++++++++------------------ src/main.rs | 22 +++++++++------------- 4 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/components/cpu.rs b/src/components/cpu.rs index 1950719..cd26bb8 100644 --- a/src/components/cpu.rs +++ b/src/components/cpu.rs @@ -3,6 +3,7 @@ use std::io::Read; use std::process; use crate::config::Config; use crate::components::prelude::*; +use crate::Framebuffer; pub struct CPU { pub reg: Registers, @@ -16,7 +17,9 @@ pub struct CPU { unsafe impl Send for CPU {} impl CPU { - pub fn new(rom: Vec, config: Config) -> Self { + pub fn new(rom: Vec, + config: Config, + framebuffer: Framebuffer) -> Self { let mut boot_rom: [u8; 0x900] = [0; 0x900]; let booting: bool = match config.boot_rom { Some(ref path) => { @@ -45,7 +48,7 @@ impl CPU { Self { reg: Registers::new(config.clone().mode, booting), - mem: MMU::new(rom, config, booting, boot_rom), + mem: MMU::new(rom, config, booting, boot_rom, framebuffer), halted: false, ime: false, ime_ask: false diff --git a/src/components/mmu.rs b/src/components/mmu.rs index 743837f..ac9d5cc 100644 --- a/src/components/mmu.rs +++ b/src/components/mmu.rs @@ -2,6 +2,7 @@ use crate::components::prelude::*; use crate::config::Config; use crate::mbc::prelude::*; use crate::sound::apu::APU; +use crate::Framebuffer; use bitflags::bitflags; use num_traits::FromPrimitive; @@ -34,7 +35,11 @@ bitflags! { } impl MMU { - pub fn new(rom: Vec, config: Config, booting: bool, boot_rom: [u8; 0x900]) -> Self { + pub fn new(rom: Vec, + config: Config, + booting: bool, + boot_rom: [u8; 0x900], + framebuffer: Framebuffer) -> Self { let cart_type: CartTypes = FromPrimitive::from_u8(rom[0x0147]).expect("Failed to get Cart Type!"); let mbc_mode = match cart_type.get_mbc() { MBCMode::Unsupported => panic!("Unsupported Cart Type! {:}", cart_type), @@ -56,7 +61,7 @@ impl MMU { Self { mbc: mbc, apu: APU::new(), - ppu: PPU::new(config.clone()), + ppu: PPU::new(config.clone(), framebuffer), serial: Serial::new(config.print_serial), joypad: Joypad::new(), timer: Timer::new(), @@ -71,7 +76,7 @@ impl MMU { } } - pub fn cycle(&mut self, cycles: u32) -> bool { + pub fn cycle(&mut self, cycles: u32) { self.timer.cycle(cycles); self.intf |= self.timer.interrupts; self.timer.interrupts = Interrupts::empty(); @@ -79,7 +84,7 @@ impl MMU { self.intf |= self.joypad.interrupts; self.joypad.interrupts = Interrupts::empty(); - let did_draw = self.ppu.cycle(cycles); + self.ppu.cycle(cycles); self.intf |= self.ppu.interrupts; self.ppu.interrupts = Interrupts::empty(); @@ -87,8 +92,6 @@ impl MMU { self.intf |= self.serial.interrupts; self.serial.interrupts = Interrupts::empty(); - - did_draw } fn oamdma(&mut self, value: u8) { diff --git a/src/components/ppu.rs b/src/components/ppu.rs index 2536daa..7816436 100644 --- a/src/components/ppu.rs +++ b/src/components/ppu.rs @@ -1,5 +1,6 @@ use crate::components::prelude::*; use crate::config::{Color, Config, Palette}; +use crate::Framebuffer; use bitflags::bitflags; pub const SCREEN_W: usize = 160; @@ -33,7 +34,7 @@ pub struct PPU { opri: bool, bgprio: [Priority; SCREEN_W], pub interrupts: Interrupts, - pub frame_buffer: Vec, + pub framebuffer: Framebuffer, } #[derive(PartialEq, Copy, Clone)] @@ -130,7 +131,7 @@ impl BGPI { } impl PPU { - pub fn new(config: Config) -> Self { + pub fn new(config: Config, framebuffer: Framebuffer) -> Self { Self { mode: config.mode, palette: config.palette, @@ -159,13 +160,13 @@ impl PPU { opri: true, bgprio: [Priority::Normal; SCREEN_W], interrupts: Interrupts::empty(), - frame_buffer: vec![0x00; 4 * SCREEN_W * SCREEN_H], + framebuffer, } } - pub fn cycle(&mut self, cycles: u32) -> bool { + pub fn cycle(&mut self, cycles: u32) { if !self.lcdc.contains(LCDC::LCD_ENABLE) { - return false; + return } self.cycle_count += cycles; @@ -178,7 +179,6 @@ impl PPU { self.ppu_mode = PPUMode::Draw; // println!("[PPU] Switching to Draw!"); } - false } PPUMode::Draw => { // TODO: Allow variable length Mode 3 @@ -194,9 +194,6 @@ impl PPU { self.draw_sprites(); } // println!("[PPU] Switching to HBlank!"); - false - } else { - false } } PPUMode::HBlank => { @@ -211,18 +208,15 @@ impl PPU { if self.lcds.contains(LCDS::MODE_1_SELECT) { self.interrupts |= Interrupts::LCD; } - true // println!("[PPU] Switching to VBlank!"); } else { self.ppu_mode = PPUMode::OAMScan; if self.lcds.contains(LCDS::MODE_2_SELECT) { self.interrupts |= Interrupts::LCD; } - false // println!("[PPU] Switching to OAMScan!"); }; } - false } PPUMode::VBlank => { if self.cycle_count >= 456 { @@ -243,7 +237,6 @@ impl PPU { self.check_lyc(); } - false } }; } @@ -309,10 +302,11 @@ impl PPU { let horizontal_offset = x * bytes_per_pixel; let total_offset = vertical_offset + horizontal_offset; - self.frame_buffer[total_offset + 0] = r; - self.frame_buffer[total_offset + 1] = g; - self.frame_buffer[total_offset + 2] = b; - self.frame_buffer[total_offset + 3] = 0xFF; + let mut framebuffer = self.framebuffer.write().unwrap(); + framebuffer[total_offset + 0] = r; + framebuffer[total_offset + 1] = g; + framebuffer[total_offset + 2] = b; + framebuffer[total_offset + 3] = 0xFF; } fn draw_bg(&mut self) { @@ -615,7 +609,9 @@ impl Memory for PPU { if !self.lcdc.contains(LCDC::LCD_ENABLE) { self.reset_ly(); self.ppu_mode = PPUMode::HBlank; - self.frame_buffer = vec![0x00; 4 * SCREEN_W * SCREEN_H]; + + let mut framebuffer = self.framebuffer.write().unwrap(); + *framebuffer = vec![0x00; 4 * SCREEN_W * SCREEN_H]; } } 0xFF41 => { diff --git a/src/main.rs b/src/main.rs index c59f3d3..e1fbe01 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,8 @@ use winit::event_loop::EventLoop; use winit::application::ApplicationHandler; use winit::window::{Window, WindowId}; +type Framebuffer = Arc>>; + mod config; mod context; mod components; @@ -44,7 +46,7 @@ struct App { context: Option>>, config: Config, input_tx: Sender<(JoypadButton, bool)>, - framebuffer: Arc>> + framebuffer: Framebuffer } impl ApplicationHandler for App { @@ -105,8 +107,8 @@ impl ApplicationHandler for App { let context_arc = Arc::clone(&self.context.as_ref().unwrap()); let mut context = context_arc.lock().unwrap(); - let framebuffer_arc = Arc::clone(&self.framebuffer); - context.update(&*framebuffer_arc.read().unwrap()); + let framebuffer = Arc::clone(&self.framebuffer); + context.update(&*framebuffer.read().unwrap()); let _ = context.render(); } @@ -160,19 +162,19 @@ fn main() { event_loop.set_control_flow(ControlFlow::Poll); let (input_tx, input_rx) = mpsc::channel::<(JoypadButton, bool)>(); - let framebuffer_rw: Arc>> = Arc::new(RwLock::new(vec![0; 4 * SCREEN_W * SCREEN_H])); + let framebuffer: Framebuffer = Arc::new(RwLock::new(vec![0; 4 * SCREEN_W * SCREEN_H])); let mut app = App { game_name: String::from(game_name), context: None, config: config.clone(), input_tx, - framebuffer: framebuffer_rw.clone() + framebuffer: framebuffer.clone() }; // Start CPU thread::spawn(move || { - let mut cpu = CPU::new(buffer, config); + let mut cpu = CPU::new(buffer, config, framebuffer); let mut step_cycles = 0; let mut step_zero = Instant::now(); @@ -201,13 +203,7 @@ fn main() { let cycles = cpu.cycle(); step_cycles += cycles; - let did_draw = cpu.mem.cycle(cycles); - if did_draw { - let framebuffer = cpu.mem.ppu.frame_buffer.clone(); - - let mut framebuffer_w = framebuffer_rw.write().unwrap(); - *framebuffer_w = framebuffer; - } + cpu.mem.cycle(cycles); } });