From 3f6a52cae6f89ed3b265e02641285b3438f54313 Mon Sep 17 00:00:00 2001 From: Michel Heily Date: Sat, 10 Aug 2019 18:14:37 +0300 Subject: [PATCH] Add sdl2 backend Currently has bad performance Former-commit-id: 384ef6b5cd7b1e1baeb6adfbc0b299b0d07d7a5d --- src/{ => backend}/minifb_backend.rs | 14 ++- src/{backend.rs => backend/mod.rs} | 10 ++- src/backend/sdl2_backend.rs | 132 ++++++++++++++++++++++++++++ src/bin/main.rs | 2 +- src/lib.rs | 1 - 5 files changed, 146 insertions(+), 13 deletions(-) rename src/{ => backend}/minifb_backend.rs (90%) rename src/{backend.rs => backend/mod.rs} (64%) create mode 100644 src/backend/sdl2_backend.rs diff --git a/src/minifb_backend.rs b/src/backend/minifb_backend.rs similarity index 90% rename from src/minifb_backend.rs rename to src/backend/minifb_backend.rs index 7fd0292..2d1991e 100644 --- a/src/minifb_backend.rs +++ b/src/backend/minifb_backend.rs @@ -6,10 +6,9 @@ extern crate minifb; use minifb::{Key, Window, WindowOptions}; -use super::backend::EmulatorBackend; +use super::EmulatorBackend; use crate::core::gpu::Gpu; - -use super::core::keypad; +use crate::core::keypad; pub struct MinifbBackend { window: Window, @@ -41,18 +40,17 @@ impl MinifbBackend { impl EmulatorBackend for MinifbBackend { fn render(&mut self, buffer: Vec) { - let now = time::Instant::now(); - if now - self.first_frame_start >= time::Duration::from_secs(1) { + self.frames_rendered += 1; + if self.first_frame_start.elapsed() >= time::Duration::from_secs(1) { let title = format!("rustboyadvance-ng ({} fps)", self.frames_rendered); self.window.set_title(&title); - self.first_frame_start = now; + self.first_frame_start = time::Instant::now(); self.frames_rendered = 0; } self.window.update_with_buffer(&buffer).unwrap(); - self.frames_rendered += 1; } - fn get_key_state(&self) -> u16 { + fn get_key_state(&mut self) -> u16 { let mut keyinput = keypad::KEYINPUT_ALL_RELEASED; keyinput.set_bit(keypad::Keys::Up as usize, !self.window.is_key_down(Key::Up)); keyinput.set_bit( diff --git a/src/backend.rs b/src/backend/mod.rs similarity index 64% rename from src/backend.rs rename to src/backend/mod.rs index 14c9b55..c45c85e 100644 --- a/src/backend.rs +++ b/src/backend/mod.rs @@ -1,11 +1,15 @@ use super::core::keypad; -pub use super::minifb_backend::MinifbBackend; +mod minifb_backend; +pub use minifb_backend::MinifbBackend; + +mod sdl2_backend; +pub use sdl2_backend::Sdl2Backend; pub trait EmulatorBackend { fn render(&mut self, buffer: Vec); - fn get_key_state(&self) -> u16; + fn get_key_state(&mut self) -> u16; } pub struct DummyBackend; @@ -17,7 +21,7 @@ impl DummyBackend { } impl EmulatorBackend for DummyBackend { - fn get_key_state(&self) -> u16 { + fn get_key_state(&mut self) -> u16 { keypad::KEYINPUT_ALL_RELEASED } fn render(&mut self, _buffer: Vec) {} diff --git a/src/backend/sdl2_backend.rs b/src/backend/sdl2_backend.rs new file mode 100644 index 0000000..e604e0f --- /dev/null +++ b/src/backend/sdl2_backend.rs @@ -0,0 +1,132 @@ +use std::time; +use std::convert::TryFrom; + +use crate::bit::BitIndex; + +extern crate sdl2; +use sdl2::event::Event; +use sdl2::keyboard::Keycode; +use sdl2::pixels::{Color, PixelFormat, PixelFormatEnum}; +use sdl2::rect::{Point, Rect}; +use sdl2::render::{Texture, TextureCreator, WindowCanvas}; +use sdl2::video::{Window, WindowContext}; + +use super::EmulatorBackend; +use crate::core::gpu::Gpu; +use crate::core::keypad; + +pub struct Sdl2Backend { + event_pump: sdl2::EventPump, + tc: TextureCreator, + canvas: WindowCanvas, + frames_rendered: u32, + fps_timer: time::Instant, + keyinput: u16, +} + +const SCREEN_WIDTH: u32 = Gpu::DISPLAY_WIDTH as u32; +const SCREEN_HEIGHT: u32 = Gpu::DISPLAY_HEIGHT as u32; + +impl Sdl2Backend { + pub fn new() -> Sdl2Backend { + let sdl_context = sdl2::init().unwrap(); + let video_subsystem = sdl_context.video().unwrap(); + + let window = video_subsystem + .window("RustBoyAdvance", SCREEN_WIDTH, SCREEN_HEIGHT) + .opengl() + .position_centered() + .build() + .unwrap(); + + let mut canvas = window.into_canvas().accelerated().build().unwrap(); + canvas.set_draw_color(Color::RGB(0, 0, 0)); + canvas.clear(); + let tc = canvas.texture_creator(); + let event_pump = sdl_context.event_pump().unwrap(); + + Sdl2Backend { + canvas: canvas, + event_pump: event_pump, + tc: tc, + frames_rendered: 0, + fps_timer: time::Instant::now(), + keyinput: keypad::KEYINPUT_ALL_RELEASED, + } + } +} + +impl EmulatorBackend for Sdl2Backend { + fn render(&mut self, buffer: Vec) { + let mut texture = self + .tc + .create_texture_target(PixelFormatEnum::RGB24, SCREEN_WIDTH, SCREEN_HEIGHT) + .unwrap(); + self.canvas + .with_texture_canvas(&mut texture, |texture_canvas| { + for y in 0i32..(SCREEN_HEIGHT as i32) { + for x in 0i32..(SCREEN_WIDTH as i32) { + let c = buffer[index2d!(x, y, SCREEN_WIDTH as i32) as usize]; + let color = Color::RGB((c >> 16) as u8, (c >> 8) as u8, c as u8); + texture_canvas.set_draw_color(color); + let _ = texture_canvas.draw_point(Point::from((x, y))); + } + } + }) + .unwrap(); + self.canvas + .copy( + &texture, + None, + Some(Rect::new(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)), + ) + .unwrap(); + self.canvas.present(); + + self.frames_rendered += 1; + if self.fps_timer.elapsed() >= time::Duration::from_secs(1) { + self.fps_timer = time::Instant::now(); + let title = format!("rustboyadvance-ng ({} fps)", self.frames_rendered); + self.canvas.window_mut().set_title(&title); + self.frames_rendered = 0; + } + } + + fn get_key_state(&mut self) -> u16 { + for event in self.event_pump.poll_iter() { + match event { + Event::KeyDown { + keycode: Some(keycode), + .. + } => { + if let Some(key) = keycode_to_keypad(keycode) { + self.keyinput.set_bit(key as usize, false); + } + } + Event::KeyUp { + keycode: Some(keycode), + .. + } => { + if let Some(key) = keycode_to_keypad(keycode) { + self.keyinput.set_bit(key as usize, true); + } + } + Event::Quit { .. } => panic!("quit!"), + _ => {} + } + } + + self.keyinput + } +} + + +fn keycode_to_keypad(keycode: Keycode) -> Option { + match keycode { + Keycode::Up => Some(keypad::Keys::Up), + Keycode::Down => Some(keypad::Keys::Down), + Keycode::Left => Some(keypad::Keys::Left), + Keycode::Right => Some(keypad::Keys::Right), + _ => None, + } +} \ No newline at end of file diff --git a/src/bin/main.rs b/src/bin/main.rs index ea34086..3e95ea4 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -25,7 +25,7 @@ fn run_emulator(matches: &ArgMatches) -> GBAResult<()> { }; let backend: Box = match matches.value_of("backend") { - Some("sdl2") => panic!("sdl2 not implemented"), + Some("sdl2") => Box::new(Sdl2Backend::new()), Some("minifb") => Box::new(MinifbBackend::new()), // None => DummyBackend::new(), None => Box::new(DummyBackend::new()), diff --git a/src/lib.rs b/src/lib.rs index 1c28254..9ef69b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,4 +22,3 @@ pub mod backend; pub mod core; pub mod debugger; pub mod disass; -pub mod minifb_backend;