diff --git a/Cargo.lock b/Cargo.lock index 6592657..c3638be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ dependencies = [ [[package]] name = "android-activity" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee91c0c2905bae44f84bfa4e044536541df26b7703fd0888deeb9060fcc44289" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" dependencies = [ "android-properties", "bitflags 2.5.0", @@ -81,9 +81,9 @@ dependencies = [ "jni-sys", "libc", "log", - "ndk", + "ndk 0.9.0", "ndk-context", - "ndk-sys", + "ndk-sys 0.6.0+11769913", "num_enum", "thiserror", ] @@ -243,22 +243,12 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" -[[package]] -name = "block-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae85a0696e7ea3b835a453750bf002770776609115e6d25c6d2ff28a8200f7e7" -dependencies = [ - "objc-sys", -] - [[package]] name = "block2" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b55663a85f33501257357e6421bb33e769d5c9ffb5ba0921c975a123e35e68" +checksum = "43ff7d91d3c1d568065b06c899777d1e48dcf76103a672a0adbc238a7f247f1e" dependencies = [ - "block-sys", "objc2", ] @@ -358,6 +348,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cfg_aliases" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77e53693616d3075149f4ead59bdeecd204ac6b8192d8969757601b74bddf00f" + [[package]] name = "clang-sys" version = "1.7.0" @@ -549,7 +545,7 @@ dependencies = [ "js-sys", "libc", "mach2", - "ndk", + "ndk 0.8.0", "ndk-context", "oboe", "wasm-bindgen", @@ -620,6 +616,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +dependencies = [ + "serde", +] + [[package]] name = "duplicate" version = "1.0.0" @@ -891,17 +896,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" -[[package]] -name = "icrate" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d3aaff8a54577104bafdf686ff18565c3b6903ca5782a2026ef06e2c7aa319" -dependencies = [ - "block2", - "dispatch", - "objc2", -] - [[package]] name = "indexmap" version = "2.2.6" @@ -1139,7 +1133,21 @@ dependencies = [ "bitflags 2.5.0", "jni-sys", "log", - "ndk-sys", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.5.0", + "jni-sys", + "log", + "ndk-sys 0.6.0+11769913", "num_enum", "raw-window-handle", "thiserror", @@ -1160,6 +1168,15 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + [[package]] name = "nom" version = "7.1.3" @@ -1256,19 +1273,53 @@ checksum = "da284c198fb9b7b0603f8635185e85fbd5b64ee154b1ed406d489077de2d6d60" [[package]] name = "objc2" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "559c5a40fdd30eb5e344fbceacf7595a81e242529fb4e21cf5f43fb4f11ff98d" +checksum = "b4b25e1034d0e636cd84707ccdaa9f81243d399196b8a773946dcffec0401659" dependencies = [ "objc-sys", "objc2-encode", ] +[[package]] +name = "objc2-app-kit" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb79768a710a9a1798848179edb186d1af7e8a8679f369e4b8d201dd2a034047" +dependencies = [ + "block2", + "objc2", + "objc2-core-data", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e092bc42eaf30a08844e6a076938c60751225ec81431ab89f5d1ccd9f958d6c" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + [[package]] name = "objc2-encode" -version = "3.0.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d079845b37af429bfe5dfa76e6d087d788031045b25cfc6fd898486fd9847666" +checksum = "88658da63e4cc2c8adb1262902cd6af51094df0488b760d6fd27194269c0950a" + +[[package]] +name = "objc2-foundation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfaefe14254871ea16c7d88968c0ff14ba554712a20d76421eec52f0a7fb8904" +dependencies = [ + "block2", + "dispatch", + "objc2", +] [[package]] name = "oboe" @@ -1277,7 +1328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" dependencies = [ "jni", - "ndk", + "ndk 0.8.0", "ndk-context", "num-derive", "num-traits", @@ -1507,15 +1558,6 @@ dependencies = [ "rustfft", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -1632,9 +1674,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sctk-adwaita" -version = "0.8.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b2eaf3a5b264a521b988b2e73042e742df700c4f962cde845d1541adb46550" +checksum = "7de61fa7334ee8ee1f5c3c58dcc414fb9361e7e8f5bff9d45f4d69eeb89a7169" dependencies = [ "ab_glyph", "log", @@ -2211,9 +2253,9 @@ dependencies = [ [[package]] name = "web-time" -version = "0.2.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa30049b1c872b72c89866d458eae9f20380ab280ffd1b1e18df2d3e2d98cfe0" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", @@ -2227,7 +2269,7 @@ checksum = "32ff1bfee408e1028e2e3acbf6d32d98b08a5a059ccbf5f33305534453ba5d3e" dependencies = [ "arrayvec", "cfg-if", - "cfg_aliases", + "cfg_aliases 0.1.1", "document-features", "js-sys", "log", @@ -2254,7 +2296,7 @@ dependencies = [ "arrayvec", "bit-vec", "bitflags 2.5.0", - "cfg_aliases", + "cfg_aliases 0.1.1", "codespan-reporting", "document-features", "indexmap", @@ -2284,7 +2326,7 @@ dependencies = [ "bit-set", "bitflags 2.5.0", "block", - "cfg_aliases", + "cfg_aliases 0.1.1", "core-graphics-types", "d3d12", "glow", @@ -2300,7 +2342,7 @@ dependencies = [ "log", "metal", "naga", - "ndk-sys", + "ndk-sys 0.5.0+25.2.9519653", "objc", "once_cell", "parking_lot", @@ -2422,15 +2464,6 @@ dependencies = [ "windows-targets 0.42.2", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -2620,9 +2653,9 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winit" -version = "0.29.15" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d59ad965a635657faf09c8f062badd885748428933dad8e8bdd64064d92e5ca" +checksum = "ea9e6d5d66cbf702e0dd820302144f51b69a95acdc495dd98ca280ff206562b1" dependencies = [ "ahash", "android-activity", @@ -2630,28 +2663,30 @@ dependencies = [ "bitflags 2.5.0", "bytemuck", "calloop", - "cfg_aliases", + "cfg_aliases 0.2.0", + "concurrent-queue", "core-foundation", "core-graphics", "cursor-icon", - "icrate", + "dpi", "js-sys", "libc", - "log", "memmap2", - "ndk", - "ndk-sys", + "ndk 0.9.0", "objc2", - "once_cell", + "objc2-app-kit", + "objc2-foundation", "orbclient", "percent-encoding", + "pin-project", "raw-window-handle", - "redox_syscall 0.3.5", + "redox_syscall 0.4.1", "rustix", "sctk-adwaita", "serde", "smithay-client-toolkit", "smol_str", + "tracing", "unicode-segmentation", "wasm-bindgen", "wasm-bindgen-futures", @@ -2661,7 +2696,7 @@ dependencies = [ "wayland-protocols-plasma", "web-sys", "web-time", - "windows-sys 0.48.0", + "windows-sys 0.52.0", "x11-dl", "x11rb", "xkbcommon-dl", diff --git a/Cargo.toml b/Cargo.toml index b7ab902..ed89bc4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -winit = { version = "0.29", features = ["serde"] } +winit = { version = "0.30", features = ["serde"] } cpal = "0.15" fundsp = { version = "0.17", default-features = false } clap = { version = "4.5", features = ["derive"] } @@ -16,4 +16,4 @@ num-traits = "0.2" num-derive = "0.4" serde = { version = "1.0", features = ["derive"] } toml = "0.8" -pollster = "0.3.0" \ No newline at end of file +pollster = "0.3" \ No newline at end of file diff --git a/src/context.rs b/src/context.rs index 31ba330..401a906 100644 --- a/src/context.rs +++ b/src/context.rs @@ -374,7 +374,7 @@ impl Context { ] } - pub fn update(&mut self, rgba: Vec) { + pub fn update(&mut self, rgba: &Vec) { self.queue.write_texture( wgpu::ImageCopyTexture { aspect: wgpu::TextureAspect::All, diff --git a/src/main.rs b/src/main.rs index 8ffdc26..c59f3d3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,17 +8,19 @@ use clap::Parser; use std::fs::File; use std::io::{Read, Write}; use std::{process, thread}; -use std::sync::{Arc, Mutex}; -use std::sync::mpsc::{Sender}; +use std::sync::{Arc, Mutex, RwLock}; +use std::sync::mpsc::Sender; use std::sync::mpsc; use std::time::{Duration, Instant}; use pollster::FutureExt; use wgpu::SurfaceError; -use winit::event::{ElementState, Event, WindowEvent}; -use winit::event_loop::ControlFlow; +use winit::event::{ElementState, WindowEvent}; +use winit::event_loop::{ActiveEventLoop, ControlFlow}; use winit::keyboard::Key; use winit::platform::modifier_supplement::KeyEventExtModifierSupplement; -use winit::{event_loop::EventLoop, window::WindowBuilder}; +use winit::event_loop::EventLoop; +use winit::application::ApplicationHandler; +use winit::window::{Window, WindowId}; mod config; mod context; @@ -34,10 +36,83 @@ pub const STEP_CYCLES: u32 = (STEP_TIME as f64 / (1000_f64 / CLOCK_FREQUENCY as #[derive(Parser)] struct Args { rom_path: String, - boot_rom: Option, + boot_rom: Option } -fn main() -> Result<(), impl std::error::Error> { +struct App { + game_name: String, + context: Option>>, + config: Config, + input_tx: Sender<(JoypadButton, bool)>, + framebuffer: Arc>> +} + +impl ApplicationHandler for App { + fn resumed(&mut self, event_loop: &ActiveEventLoop) { + let window_attributes = Window::default_attributes() + .with_title(format!("tetsuyu - {:}", self.game_name)) + .with_inner_size(winit::dpi::LogicalSize::new( + self.config.window_w, + self.config.window_h, + )); + let window = event_loop.create_window(window_attributes).unwrap(); + + let context_future = Context::new(Arc::new(window), self.config.clone().shader); + self.context = Some(Arc::new(Mutex::new(context_future.block_on()))); + } + + fn window_event(&mut self, event_loop: &ActiveEventLoop, window_id: WindowId, event: WindowEvent) { + let context_arc = Arc::clone(&self.context.as_ref().unwrap()); + let mut context = context_arc.lock().unwrap(); + let size = context.size; + + match event { + WindowEvent::RedrawRequested if window_id == context.window().id() => { + match context.render() { + Ok(_) => {} + Err(SurfaceError::Lost) => context.resize(size), + Err(SurfaceError::OutOfMemory) => event_loop.exit(), + Err(e) => println!("{:?}", e), + } + } + WindowEvent::Resized(physical_size) => { + context.resize(physical_size); + } + WindowEvent::KeyboardInput { event, .. } => { + if !event.repeat { + if event.state == ElementState::Pressed { + send_input( + event.key_without_modifiers(), + true, + self.config.clone().input, + self.input_tx.clone(), + ); + } else if event.state == ElementState::Released { + send_input( + event.key_without_modifiers(), + false, + self.config.clone().input, + self.input_tx.clone(), + ); + } + } + } + _ => (), + } + } + + fn about_to_wait(&mut self, _event_loop: &ActiveEventLoop) { + 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 _ = context.render(); + } +} + +fn main() { let config = match File::open("./config.toml") { Ok(mut file) => { let mut config_data = String::new(); @@ -84,116 +159,59 @@ fn main() -> Result<(), impl std::error::Error> { let event_loop = EventLoop::new().unwrap(); event_loop.set_control_flow(ControlFlow::Poll); - let window = WindowBuilder::new() - .with_title(format!("tetsuyu - {:}", game_name)) - .with_inner_size(winit::dpi::LogicalSize::new( - config.window_w, - config.window_h, - )) - .build(&event_loop) - .unwrap(); - - let context_future = Context::new(Arc::new(window), config.clone().shader); - let context = Arc::new(Mutex::new(context_future.block_on())); - 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 mut app = App { + game_name: String::from(game_name), + context: None, + config: config.clone(), + input_tx, + framebuffer: framebuffer_rw.clone() + }; - { - let config = config.clone(); - let context = Arc::clone(&context); - // Start CPU - thread::spawn( move || { - let mut cpu = CPU::new(buffer, config); - let mut step_cycles = 0; - let mut step_zero = Instant::now(); - - loop { - // https://github.com/mohanson/gameboy/blob/master/src/cpu.rs#L13 - if step_cycles > STEP_CYCLES { - step_cycles -= STEP_CYCLES; - let now = Instant::now(); - let duration = now.duration_since(step_zero); - let milliseconds = STEP_TIME.saturating_sub(duration.as_millis() as u32); - // println!("[CPU] Sleeping {}ms", milliseconds); - thread::sleep(Duration::from_millis(milliseconds as u64)); - step_zero = now; - } + // Start CPU + thread::spawn(move || { + let mut cpu = CPU::new(buffer, config); + let mut step_cycles = 0; + let mut step_zero = Instant::now(); + + loop { + // https://github.com/mohanson/gameboy/blob/master/src/cpu.rs#L13 + if step_cycles > STEP_CYCLES { + step_cycles -= STEP_CYCLES; + let now = Instant::now(); + let duration = now.duration_since(step_zero); + let milliseconds = STEP_TIME.saturating_sub(duration.as_millis() as u32); + // println!("[CPU] Sleeping {}ms", milliseconds); + thread::sleep(Duration::from_millis(milliseconds as u64)); + step_zero = now; + } - match input_rx.try_recv() { - Ok(v) => { - if v.1 { - cpu.mem.joypad.down(v.0); - } else { - cpu.mem.joypad.up(v.0); - } + match input_rx.try_recv() { + Ok(v) => { + if v.1 { + cpu.mem.joypad.down(v.0); + } else { + cpu.mem.joypad.up(v.0); } - Err(_) => {} - } - - let cycles = cpu.cycle(); - step_cycles += cycles; - let did_draw = cpu.mem.cycle(cycles); - if did_draw { - let frame_buffer = cpu.mem.ppu.frame_buffer.clone(); - let mut context = context.lock().unwrap(); - context.update(frame_buffer); - drop(context); } + Err(_) => {} } - }); - } - { - let context = Arc::clone(&context); - event_loop.run(move |event, elwt| { - let config = config.clone(); - let mut context = context.lock().unwrap(); + 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(); - match event { - Event::AboutToWait => { - // TODO: Handle errors - let _ = context.render(); - } - Event::WindowEvent { event, window_id } => { - let size = context.size; - match event { - WindowEvent::RedrawRequested if window_id == context.window().id() => { - match context.render() { - Ok(_) => {} - Err(SurfaceError::Lost) => context.resize(size), - Err(SurfaceError::OutOfMemory) => elwt.exit(), - Err(e) => println!("{:?}", e), - } - } - WindowEvent::Resized(physical_size) => { - context.resize(physical_size); - } - WindowEvent::KeyboardInput { event, .. } => { - if !event.repeat { - if event.state == ElementState::Pressed { - send_input( - event.key_without_modifiers(), - true, - config.input, - input_tx.clone(), - ); - } else if event.state == ElementState::Released { - send_input( - event.key_without_modifiers(), - false, - config.input, - input_tx.clone(), - ); - } - } - } - _ => (), - } - } - _ => (), + let mut framebuffer_w = framebuffer_rw.write().unwrap(); + *framebuffer_w = framebuffer; } - }) - } + } + }); + + let _ = event_loop.run_app(&mut app); } pub fn send_input(