From a564c38ec7bbd700a23f4714a15b09511021b8a2 Mon Sep 17 00:00:00 2001 From: Xevion Date: Sun, 14 Apr 2024 19:36:55 -0500 Subject: [PATCH] Asyncify, timing experiments --- Cargo.lock | 138 +++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 2 + src/emscripten.rs | 62 ++++++++++----------- src/main.rs | 83 ++++++++++++++++++++-------- 4 files changed, 227 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5ae1f0e..598409e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "cfg-if" version = "1.0.0" @@ -29,6 +35,26 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9226dbc05df4fb986f48d730b001532580883c4c06c5d1c213f4b34c1c157178" +[[package]] +name = "getrandom" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -37,9 +63,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "log" @@ -90,11 +116,13 @@ version = "0.1.0" dependencies = [ "colors-transform", "lazy_static", + "rand", "sdl2", "spin_sleep", "tracing", "tracing-error", "tracing-subscriber", + "web-time", ] [[package]] @@ -103,6 +131,12 @@ version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.66" @@ -121,6 +155,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "regex" version = "1.9.1" @@ -324,6 +388,76 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 7e6df01..93f89c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,10 @@ edition = "2021" [dependencies] colors-transform = "0.2.11" lazy_static = "1.4.0" +rand = "0.8.5" sdl2 = { version = "0.36", features = ["image", "ttf", "mixer"] } spin_sleep = "1.1.1" tracing = { version = "0.1.37", features = ["max_level_debug", "release_max_level_debug"]} tracing-error = "0.2.0" tracing-subscriber = {version = "0.3.17", features = ["env-filter"]} +web-time = "1.1.0" diff --git a/src/emscripten.rs b/src/emscripten.rs index e137cf8..dbb4a2e 100644 --- a/src/emscripten.rs +++ b/src/emscripten.rs @@ -1,44 +1,42 @@ - +#[allow(dead_code)] +#[cfg(target_os = "emscripten")] pub mod emscripten { - use std::cell::RefCell; - use std::os::raw::{c_float, c_int, c_void}; - use std::ptr::null_mut; - - #[allow(non_camel_case_types)] - type em_callback_func = unsafe extern "C" fn(); + use std::os::raw::c_uint; extern "C" { - pub fn emscripten_set_main_loop( - func: em_callback_func, - fps: c_int, - simulate_infinite_loop: c_int, - ); - pub fn emscripten_cancel_main_loop(); - pub fn emscripten_get_now() -> c_float; + pub fn emscripten_get_now() -> f64; + pub fn emscripten_sleep(ms: c_uint); + pub fn emscripten_run_script(script: *const u8); + pub fn emscripten_get_element_css_size( + target: *const u8, + width: *mut f64, + height: *mut f64, + ) -> i32; } - thread_local!(static MAIN_LOOP_CALLBACK: RefCell<*mut c_void> = RefCell::new(null_mut())); - - pub fn set_main_loop_callback(callback: F) - where - F: FnMut(), - { - MAIN_LOOP_CALLBACK.with(|log| { - *log.borrow_mut() = &callback as *const _ as *mut c_void; - }); + // milliseconds since start of program + pub fn now() -> f64 { + unsafe { emscripten_get_now() } + } + pub fn sleep(ms: u32) { unsafe { - emscripten_set_main_loop(wrapper::, 0, 1); + emscripten_sleep(ms); } + } - unsafe extern "C" fn wrapper() - where - F: FnMut(), - { - MAIN_LOOP_CALLBACK.with(|z| { - let closure = *z.borrow_mut() as *mut F; - (*closure)(); - }); + pub fn exec(script: &str) { + unsafe { + emscripten_run_script(script.as_ptr()); } } + + pub fn get_canvas_size() -> (u32, u32) { + let mut width = 0.0; + let mut height = 0.0; + unsafe { + emscripten_get_element_css_size("canvas\0".as_ptr(), &mut width, &mut height); + } + (width as u32, height as u32) + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 215e1e5..f945cfa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,14 +2,42 @@ use std::cell::RefCell; use std::process; use std::rc::Rc; +use rand::seq::IteratorRandom; use sdl2::event::Event; use sdl2::image::LoadTexture; use sdl2::keyboard::Keycode; use sdl2::pixels::Color; use sdl2::rect::{Point, Rect}; +use web_time::{Duration, Instant}; static BLACK: Color = Color::RGB(0, 0, 0); +#[cfg(target_os = "emscripten")] +mod emscripten; + +#[cfg(not(target_os = "emscripten"))] +fn sleep(ms: u32) { + std::thread::sleep(Duration::from_millis(ms as u64)); +} + +#[cfg(target_os = "emscripten")] +fn now() -> f64 { + emscripten::emscripten::now() / 1000f64 +} + +#[cfg(not(target_os = "emscripten"))] +fn now() -> f64 { + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_secs_f64() +} + +#[cfg(target_os = "emscripten")] +fn sleep(ms: u32) { + emscripten::emscripten::sleep(ms); +} + fn main() { let ctx = sdl2::init().unwrap(); let video_ctx = ctx.video().unwrap(); @@ -24,7 +52,7 @@ fn main() { Err(err) => panic!("failed to create window: {}", err), }; - let canvas = match window.into_canvas().accelerated().present_vsync().build() { + let mut canvas = match window.into_canvas().accelerated().build() { Ok(canvas) => canvas, Err(err) => panic!("failed to create canvas: {}", err), }; @@ -32,19 +60,23 @@ fn main() { let texture_creator = canvas.texture_creator(); let mut point = Point::new(0, 0); - let ctx = Rc::new(RefCell::new(ctx)); - let canvas = Rc::new(RefCell::new(canvas)); - let texture_creator = Rc::new(texture_creator); + // let ctx = Rc::new(RefCell::new(ctx)); + // let canvas = Rc::new(RefCell::new(canvas)); + // let texture_creator = Rc::new(texture_creator); let fruit_atlas = texture_creator .load_texture("./assets/fruit.png") .expect("could not load texture"); + let target_fps = 60; + let frame_time = Duration::from_secs_f32(1.0) / target_fps; + println!("Frame time: {:?}", frame_time); let mut frame = 0; loop { + let start = now(); let mut moved = false; - for event in ctx.borrow_mut().event_pump().unwrap().poll_iter() { + for event in ctx.event_pump().unwrap().poll_iter() { match event { Event::Quit { .. } | Event::KeyDown { @@ -61,6 +93,11 @@ fn main() { if frame > 7 { frame = 0; } + + // random number between 2 and 6 + let sleep_time = (15..=500).choose(&mut rand::thread_rng()).unwrap(); + println!("Sleeping for {} ms", sleep_time); + sleep(sleep_time); } Keycode::Left => { point.x -= 32; @@ -86,7 +123,7 @@ fn main() { // Handle wrapping at the edges if moved { - let canvas_size = canvas.borrow().window().size(); + let canvas_size = canvas.window().size(); if point.x < 0 { point.x = canvas_size.0 as i32 - 32; } else if point.x >= 640 { @@ -99,8 +136,6 @@ fn main() { } } - let mut canvas = canvas.borrow_mut(); - canvas.set_draw_color(BLACK); canvas.clear(); @@ -117,21 +152,21 @@ fn main() { .expect("could not draw texture"); canvas.present(); + + let t2 = now(); + let elapsed = Duration::from_secs_f64(t2 - start); + if elapsed < frame_time { + let sleep_time = frame_time - elapsed; + sleep(sleep_time.as_millis() as u32); + // println!("elapsed: {:?} sleep: {:?}ms ({:?})", elapsed, sleep_time, t2); + } else { + let excess = elapsed - frame_time; + println!("! excess: {:?} ({:?})", excess, t2); + } + + let t3 = now(); + let duration = Duration::from_secs_f64(t3 - start); + let fps = 1f64 / (duration.as_secs_f64()); + println!("FPS: {}", fps); } - - // #[cfg(target_family = "wasm")] - // { - // use crate::emscripten::emscripten::set_main_loop_callback; - // set_main_loop_callback(main_loop); - // } - - // #[cfg(not(target_family = "wasm"))] - // { - // use std::thread::sleep; - // use std::time::Duration; - // loop { - // main_loop(); - // sleep(Duration::from_millis(10)) - // } - // } }