Optimize framebuffer render

This commit is contained in:
Franco Colmenarez 2021-11-03 11:59:48 -05:00
parent 659f602b2a
commit 60fd55abca
4 changed files with 29 additions and 26 deletions

View File

@ -78,7 +78,7 @@ impl Bus {
}; };
let mut data = [0x00; 0x10000]; let mut data = [0x00; 0x10000];
// Hardware registers after the bootrom // Hardware registers after the bootrom
data[0xFF00] = 0b11001111; data[0xFF00] = 0xCF;
data[0xFF01] = 0x00; data[0xFF01] = 0x00;
data[0xFF02] = 0x7E; data[0xFF02] = 0x7E;
data[0xFF04] = 0x18; data[0xFF04] = 0x18;
@ -111,6 +111,9 @@ impl Bus {
if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) { if BANK_ZERO.in_range(address) || BANK_SWITCHABLE.in_range(address) {
return self.game_rom.read(address); return self.game_rom.read(address);
} }
if address == JOYPAD_ADDRESS {
println!("{:08b}", self.data[address as usize]);
}
self.data[address as usize] self.data[address as usize]
} }
@ -142,6 +145,8 @@ impl Bus {
} else if address == JOYPAD_ADDRESS { } else if address == JOYPAD_ADDRESS {
let byte = self.data[JOYPAD_ADDRESS as usize]; let byte = self.data[JOYPAD_ADDRESS as usize];
self.data[JOYPAD_ADDRESS as usize] = (data & 0b11110000) | (byte & 0b00001111); self.data[JOYPAD_ADDRESS as usize] = (data & 0b11110000) | (byte & 0b00001111);
} else if address == LCD_Y_ADDRESS {
println!("Write to LCD_Y not allowed");
} else { } else {
self.data[address as usize] = data; self.data[address as usize] = data;
} }

View File

@ -101,14 +101,7 @@ impl Emulator {
} }
} }
pub fn draw(&mut self, frame: &mut [u8]) { pub fn run(&mut self, cpu_cycles: Cycles, frame_buffer: &mut [u8]) {
let ppu_frame = self.ppu.get_rgba_frame();
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
pixel.copy_from_slice(&ppu_frame[i]);
}
}
pub fn run(&mut self, cpu_cycles: Cycles) {
self.cpu.reset_cycles(); self.cpu.reset_cycles();
while self.cpu.get_cycles().0 <= cpu_cycles.0 { while self.cpu.get_cycles().0 <= cpu_cycles.0 {
self.cpu.run(&mut self.bus); self.cpu.run(&mut self.bus);
@ -116,7 +109,7 @@ impl Emulator {
self.bus.reset_timer = false; self.bus.reset_timer = false;
self.timer.reset(&mut self.bus); self.timer.reset(&mut self.bus);
} }
self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles(), frame_buffer);
self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
// 1 CPU cycle = 238.42ns // 1 CPU cycle = 238.42ns
@ -127,13 +120,14 @@ impl Emulator {
pub fn cpu_loop(&mut self) { pub fn cpu_loop(&mut self) {
let mut exit = false; let mut exit = false;
let mut frame: [u8; 144 * 160] = [0; 144 * 160];
while !exit { while !exit {
self.cpu.run(&mut self.bus); self.cpu.run(&mut self.bus);
if self.bus.reset_timer { if self.bus.reset_timer {
self.bus.reset_timer = false; self.bus.reset_timer = false;
self.timer.reset(&mut self.bus); self.timer.reset(&mut self.bus);
} }
self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles(), &mut frame);
self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); self.timer.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles());
// exit = self.cpu.get_exec_calls_count() >= 1258895; // log 1 // exit = self.cpu.get_exec_calls_count() >= 1258895; // log 1

View File

@ -116,15 +116,15 @@ impl PPU {
self.cycles.0 += cycles.0; self.cycles.0 += cycles.0;
} }
pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles) { pub fn do_cycles(&mut self, bus: &mut Bus, cycles: Cycles, frame_buffer: &mut [u8]) {
let mut count = 0; let mut count = 0;
while count < cycles.0 { while count < cycles.0 {
self.cycle(bus); self.cycle(bus, frame_buffer);
count += 1; count += 1;
} }
} }
pub fn cycle(&mut self, bus: &mut Bus) { pub fn cycle(&mut self, bus: &mut Bus, frame_buffer: &mut [u8]) {
if !PPU::get_lcd_control(bus, LCDControl::LCDEnable) { if !PPU::get_lcd_control(bus, LCDControl::LCDEnable) {
self.increment_cycles(Cycles(1)); self.increment_cycles(Cycles(1));
return; return;
@ -139,7 +139,7 @@ impl PPU {
} }
} else if self.cycles.0 == 80 + 1 { } else if self.cycles.0 == 80 + 1 {
// Mode 3 drawing pixel line. This could also last 289 cycles // Mode 3 drawing pixel line. This could also last 289 cycles
self.draw_line(bus); self.draw_line(bus, frame_buffer);
PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD), true); PPU::set_lcd_status(bus, LCDStatus::ModeFlag(LCDStatusModeFlag::TransferringToLCD), true);
} else if self.cycles.0 == 80 + 172 + 1 { } else if self.cycles.0 == 80 + 172 + 1 {
// Mode 0 Horizontal blank. This could last 87 or 204 cycles depending on the mode 3 // Mode 0 Horizontal blank. This could last 87 or 204 cycles depending on the mode 3
@ -190,7 +190,7 @@ impl PPU {
} }
fn set_lcd_y(bus: &mut Bus, val: u8) { fn set_lcd_y(bus: &mut Bus, val: u8) {
bus.write(LCD_Y_ADDRESS, val); bus.force_write(LCD_Y_ADDRESS, val);
} }
fn get_scroll_x(bus: &Bus) -> u8 { fn get_scroll_x(bus: &Bus) -> u8 {
@ -300,7 +300,7 @@ impl PPU {
Some(pixels[(x as usize).rem_euclid(8)]) Some(pixels[(x as usize).rem_euclid(8)])
} }
fn draw_line(&mut self, bus: &Bus) { fn draw_line(&mut self, bus: &Bus, frame_buffer: &mut [u8]) {
let palette = bus.read(BACKGROUND_PALETTE_ADDRESS); let palette = bus.read(BACKGROUND_PALETTE_ADDRESS);
let lcd_y = PPU::get_lcd_y(bus); let lcd_y = PPU::get_lcd_y(bus);
if lcd_y as u32 >= LCD_HEIGHT { if lcd_y as u32 >= LCD_HEIGHT {
@ -321,10 +321,18 @@ impl PPU {
let bg_pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2, palette); let bg_pixels = PPU::get_byte_pixels(tile_byte_1, tile_byte_2, palette);
for pixel in bg_pixels { for pixel in bg_pixels {
let idx = lcd_x as usize + (lcd_y as usize * LCD_WIDTH as usize); let idx = (lcd_x as usize + (lcd_y as usize * LCD_WIDTH as usize)) * 4;
self.rgba_frame[idx] = PPU::get_rgba(pixel); let rgba = PPU::get_rgba(pixel);
frame_buffer[idx] = rgba[0];
frame_buffer[idx + 1] = rgba[1];
frame_buffer[idx + 2] = rgba[2];
frame_buffer[idx + 3] = rgba[3];
if let Some(window_pixel) = PPU::get_window_pixel(lcd_x, bus) { if let Some(window_pixel) = PPU::get_window_pixel(lcd_x, bus) {
self.rgba_frame[idx] = PPU::get_rgba(window_pixel); let rgba = PPU::get_rgba(pixel);
frame_buffer[idx] = rgba[0];
frame_buffer[idx + 1] = rgba[1];
frame_buffer[idx + 2] = rgba[2];
frame_buffer[idx + 3] = rgba[3];
} }
lcd_x += 1; lcd_x += 1;
@ -373,8 +381,4 @@ impl PPU {
PPU::get_pixel(PPU::get_palette((byte1 & 0b01) | ((byte2 << 1) & 0b10), palette)), PPU::get_pixel(PPU::get_palette((byte1 & 0b01) | ((byte2 << 1) & 0b10), palette)),
] ]
} }
pub fn get_rgba_frame(&self) -> &[[u8; 4]; FRAME_BUFFER_LENGTH as usize] {
&self.rgba_frame
}
} }

View File

@ -64,8 +64,8 @@ pub fn start_eventloop() {
*control_flow = ControlFlow::Exit *control_flow = ControlFlow::Exit
}, },
Event::MainEventsCleared => { Event::MainEventsCleared => {
emulator.run(Cycles(70224)); emulator.run(Cycles(70224), pixels.get_frame());
emulator.draw(pixels.get_frame()); // emulator.draw(pixels.get_frame());
// thread::sleep(time::Duration::from_millis(14)); // thread::sleep(time::Duration::from_millis(14));
window.request_redraw(); window.request_redraw();