diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/buffer.rs | 27 | ||||
| -rw-r--r-- | src/file.rs | 16 | ||||
| -rw-r--r-- | src/main.rs | 26 | ||||
| -rw-r--r-- | src/scene.rs | 7 | ||||
| -rw-r--r-- | src/script.rs | 138 |
5 files changed, 130 insertions, 84 deletions
diff --git a/src/buffer.rs b/src/buffer.rs index 999a32c..6d983db 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -60,16 +60,23 @@ impl Buffer { fn render(&mut self) -> std::io::Result<()> { puffin::profile_function!(); - self.cells.sort_unstable_by_key(|cell| cell.z); - queue!(self.stdout, BeginSynchronizedUpdate, Clear(ClearType::All))?; - for cell in &self.cells { - queue!( - self.stdout, - MoveTo(cell.x, cell.y), - PrintStyledContent(StyledContent::new(cell.style, cell.character)) - )?; + { + puffin::profile_scope!("sort cells"); + self.cells.sort_unstable_by_key(|cell| cell.z); } - queue!(self.stdout, EndSynchronizedUpdate)?; + { + puffin::profile_scope!("queue"); + queue!(self.stdout, BeginSynchronizedUpdate, Clear(ClearType::All))?; + for cell in &self.cells { + queue!( + self.stdout, + MoveTo(cell.x, cell.y), + PrintStyledContent(StyledContent::new(cell.style, cell.character)) + )?; + } + queue!(self.stdout, EndSynchronizedUpdate)?; + } + puffin::profile_scope!("flush"); self.stdout.flush()?; Ok(()) } @@ -96,6 +103,7 @@ impl Buffer { } }); loop { + puffin::profile_scope!("frame"); while let Ok(event) = receiver.try_recv() { if let Ok(event) = event.try_into() { event_handler(self, event); @@ -103,6 +111,7 @@ impl Buffer { } event_handler(self, Event::Render); self.render()?; + puffin::GlobalProfiler::lock().new_frame(); } })?; self.finish()?; diff --git a/src/file.rs b/src/file.rs index 42fecfa..2963879 100644 --- a/src/file.rs +++ b/src/file.rs @@ -1,4 +1,4 @@ -use std::{ffi::OsStr, path::Path, sync::Arc}; +use std::{ffi::OsStr, path::Path}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; @@ -9,7 +9,6 @@ use crate::scene::{Scene, scene_id_by_name}; type FileTask = Task<std::io::Result<FileData>>; pub struct FileManager { - pub wasm_compiler: Arc<wasmi::Engine>, active_tasks: FxHashMap<Box<Path>, FileTask>, cache: FxHashMap<Box<Path>, FileData>, } @@ -87,17 +86,20 @@ impl FileData { impl FileManager { pub fn new() -> Self { Self { - wasm_compiler: Arc::new(wasmi::Engine::default()), active_tasks: FxHashMap::default(), cache: FxHashMap::default(), } } - pub fn load_file(&mut self, path: Box<Path>) -> std::io::Result<&FileData> { + pub fn load_file( + &mut self, + path: Box<Path>, + wasm_compiler: &wasmi::Engine, + ) -> std::io::Result<&FileData> { let data = compile_data( path.as_ref(), &std::fs::read(path.as_ref()).map(Vec::into_boxed_slice)?, - &self.wasm_compiler.clone(), + wasm_compiler, )?; self.cache.entry(path.clone()).insert_entry(data); Ok(self.cache.get(&path).unwrap()) @@ -120,9 +122,9 @@ impl FileManager { } } - pub fn start_loading_file(&mut self, path: impl AsRef<Path>) { + pub fn start_loading_file(&mut self, path: impl AsRef<Path>, wasm_compiler: &wasmi::Engine) { let boxed_path = Box::from(path.as_ref()); - let compiler = self.wasm_compiler.clone(); + let compiler = wasm_compiler.clone(); let task = unblock(move || { compile_data( &boxed_path, diff --git a/src/main.rs b/src/main.rs index 14e3925..bd42e18 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,7 +7,7 @@ use tortuise::{ file::FileManager, input::InputManager, scene::switch_scenes, - script::{ScriptContext, ScriptDeclaration, ScriptManager}, + script::{ScriptContext, ScriptDeclaration, ScriptManager, WasmRunner}, }; #[global_allocator] @@ -17,13 +17,12 @@ fn get_timestamp() -> u128 { SystemTime::UNIX_EPOCH.elapsed().unwrap().as_nanos() } -fn init_first_frame<'a>(_: &mut ScriptContext<'a>, state: &mut Box<[u8]>) { +fn init_first_frame(_: &mut ScriptContext, state: &mut Box<[u8]>) { *state = Box::from(get_timestamp().to_ne_bytes()); } -fn render_frame_rate<'a>(ctx: &mut ScriptContext<'a>, state: &mut Box<[u8]>) { +fn render_frame_rate(ctx: &mut ScriptContext, state: &mut Box<[u8]>) { puffin::profile_function!(); - ctx.buffer.cells.clear(); let end = get_timestamp(); let last_frame_start = u128::from_ne_bytes(*state.as_array().unwrap()); let frame_time = end - last_frame_start + 1; @@ -35,6 +34,7 @@ fn render_frame_rate<'a>(ctx: &mut ScriptContext<'a>, state: &mut Box<[u8]>) { frame_time % 100 / 10, frame_time % 10, ]; + ctx.buffer.cells.clear(); for (x, digit) in digits.into_iter().enumerate() { ctx.buffer.cells.push(Cell { character: char::from_digit(digit as u32, 10).unwrap(), @@ -55,6 +55,14 @@ fn exit_on_escape(ctx: &mut ScriptContext, _: &mut Box<[u8]>) { } fn main() { + let mut files = FileManager::default(); + let wasm_runner = WasmRunner::new(); + let manifest = files + .load_file(Box::from("manifest.toml".as_ref()), &wasm_runner.engine) + .unwrap() + .unwrap_manifest() + .clone(); + let stdout = Box::new(std::io::stdout().lock()); let mut buffer = Buffer::new(stdout).unwrap(); let mut input = InputManager::new(); @@ -62,6 +70,7 @@ fn main() { buffer: &mut buffer, input: &input, }; + let scripts = [ ScriptDeclaration::Static { start: Some(init_first_frame), @@ -76,17 +85,12 @@ fn main() { ]; let mut scripts = ScriptManager::new(&scripts); - let mut files = FileManager::default(); - let manifest = files - .load_file(Box::from("manifest.toml".as_ref())) - .unwrap() - .unwrap_manifest() - .clone(); switch_scenes( &manifest.scenes, &mut scripts, &mut context, &mut files, + &wasm_runner, manifest.first_scene, ); @@ -105,7 +109,7 @@ fn main() { buffer, input: &input, }; - scripts.run_scripts(&mut context); + scripts.run_scripts(&mut context, &wasm_runner, &mut files); input.reset_next_frame(); puffin::GlobalProfiler::lock().new_frame(); } diff --git a/src/scene.rs b/src/scene.rs index 8f70350..34ff877 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::{ file::FileManager, - script::{ScriptContext, ScriptManager}, + script::{ScriptContext, ScriptManager, WasmRunner}, }; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -33,15 +33,16 @@ pub fn switch_scenes( scripts: &mut ScriptManager, context: &mut ScriptContext<'_>, files: &mut FileManager, + wasm_runner: &WasmRunner, new: usize, ) { let active_scripts = FxHashSet::from_iter(scripts.active_scripts.iter().cloned()); let scripts_to_load = &scenes[new].scripts.required; for script in scripts_to_load { if !active_scripts.contains(script) { - scripts.activate_script(*script, context, files); + scripts.activate_script(*script, context, wasm_runner, files); } else { - scripts.reset_script(*script, context); + scripts.reset_script(*script, context, wasm_runner, files); } } } diff --git a/src/script.rs b/src/script.rs index be7f6f4..861f665 100644 --- a/src/script.rs +++ b/src/script.rs @@ -1,7 +1,6 @@ use std::path::Path; use rustc_hash::FxHashMap; -use wasmer::{Imports, Instance, Module, Store}; use crate::{buffer::Buffer, file::FileManager, input::InputManager}; @@ -11,12 +10,17 @@ pub struct ScriptManager<'a> { script_states: FxHashMap<usize, Box<[u8]>>, } +pub struct WasmRunner { + pub engine: wasmi::Engine, + pub linker: wasmi::Linker<&'static ScriptContext<'static>>, +} + pub struct ScriptContext<'a> { pub buffer: &'a mut Buffer, pub input: &'a InputManager, } -type StaticScriptFunction = Option<fn(&mut ScriptContext, &mut Box<[u8]>)>; +type StaticScriptFunction = Option<fn(&mut ScriptContext<'_>, &mut Box<[u8]>)>; pub enum ScriptDeclaration { Static { @@ -29,17 +33,6 @@ pub enum ScriptDeclaration { }, } -pub struct WasmScript { - pub module: Module, - pub instance: Instance, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Profile { - Debug, - Release, -} - impl<'a> ScriptContext<'a> { pub fn exit(&mut self) -> ! { let _ = self.buffer.finish(); @@ -51,6 +44,42 @@ fn get_script_state(states: &mut FxHashMap<usize, Box<[u8]>>, script_id: usize) states.entry(script_id).or_insert(Box::from([])) } +impl Default for WasmRunner { + fn default() -> Self { + Self::new() + } +} + +impl WasmRunner { + pub fn new() -> Self { + let engine = wasmi::Engine::default(); + let linker = wasmi::Linker::new(&engine); + Self { engine, linker } + } + + pub fn compile(&self, data: &[u8]) -> Result<wasmi::Module, wasmi::Error> { + wasmi::Module::new(&self.engine, data) + } + + pub fn run_function( + &self, + module: &wasmi::Module, + context: &mut ScriptContext<'_>, + function_name: &str, + ) -> Result<(), wasmi::Error> { + // safety: the store won't be kept around after this function ends. Only the + // lifetimes are being transmuted + let mut store = wasmi::Store::new(&self.engine, unsafe { + std::mem::transmute::<&ScriptContext<'_>, &ScriptContext<'_>>(context) + }); + let instance = self.linker.instantiate_and_start(&mut store, module)?; + let function = instance.get_func(&store, function_name).ok_or_else(|| { + wasmi::Error::new(format!("No function named {function_name} was exported")) + })?; + function.call(&mut store, &[], &mut []) + } +} + impl<'a> ScriptManager<'a> { pub fn new(scripts: &'a [ScriptDeclaration]) -> Self { Self { @@ -64,6 +93,7 @@ impl<'a> ScriptManager<'a> { &mut self, script_id: usize, context: &mut ScriptContext<'_>, + wasm_runner: &WasmRunner, files: &mut FileManager, ) { let Some(script_declaration) = self.scripts.get(script_id) else { @@ -79,19 +109,23 @@ impl<'a> ScriptManager<'a> { }); } ScriptDeclaration::Wasm { path } => { - todo!("wasm scripts") - // let module = files.load_file(path.clone()).unwrap().unwrap_wasm_module(); - // let mut store = wasmi::Store::new(&files.wasm_compiler, context); - // let instance = self - // .linker - // .instantiate_and_start(&mut store, &module) - // .unwrap(); + let module = files + .load_file(path.clone(), &wasm_runner.engine) + .unwrap() + .unwrap_wasm_module(); + wasm_runner.run_function(module, context, "start"); } } self.active_scripts.push(script_id); } - pub fn deactivate_script(&mut self, script_id: usize, context: &mut ScriptContext<'_>) { + pub fn deactivate_script( + &mut self, + script_id: usize, + context: &mut ScriptContext<'_>, + wasm_runner: &WasmRunner, + files: &mut FileManager, + ) { self.active_scripts.retain(|element| { if *element != script_id { let Some(script) = self.scripts.get(script_id) else { @@ -106,7 +140,13 @@ impl<'a> ScriptManager<'a> { ); }); } - ScriptDeclaration::Wasm { .. } => todo!("wasm scripts"), + ScriptDeclaration::Wasm { path } => { + let module = files + .load_file(path.clone(), &wasm_runner.engine) + .unwrap() + .unwrap_wasm_module(); + wasm_runner.run_function(module, context, "end"); + } }; true @@ -116,13 +156,18 @@ impl<'a> ScriptManager<'a> { }); } - pub fn run_scripts(&mut self, context: &mut ScriptContext<'_>) { + pub fn run_scripts( + &mut self, + context: &mut ScriptContext<'_>, + wasm_runner: &WasmRunner, + files: &mut FileManager, + ) { puffin::profile_function!(); for script_id in &self.active_scripts { let Some(script) = self.scripts.get(*script_id) else { unreachable!("The active script does not exist"); }; - match *script { + match script { ScriptDeclaration::Static { update, .. } => { if let Some(s) = update { s( @@ -131,40 +176,25 @@ impl<'a> ScriptManager<'a> { ) } } - ScriptDeclaration::Wasm { .. } => todo!("wasm scripts"), - } - } - } - - pub fn reset_script(&mut self, script_id: usize, context: &mut ScriptContext<'_>) { - let script = &self.scripts[script_id]; - match script { - ScriptDeclaration::Static { start, end, .. } => { - if let Some(s) = start { - s( - context, - get_script_state(&mut self.script_states, script_id), - ) - } - if let Some(s) = end { - s( - context, - get_script_state(&mut self.script_states, script_id), - ) + ScriptDeclaration::Wasm { path } => { + let module = files + .load_file(path.clone(), &wasm_runner.engine) + .unwrap() + .unwrap_wasm_module(); + wasm_runner.run_function(module, context, "update"); } } - ScriptDeclaration::Wasm { .. } => todo!("wasm scripts"), } } -} -impl WasmScript { - fn call_function(&self, name: &str, profile: Profile, store: &mut Store, imports: &Imports) { - let instance = match profile { - Profile::Debug => &Instance::new(store, &self.module, imports).unwrap(), - Profile::Release => &self.instance, - }; - let function = instance.exports.get_function(name).unwrap(); - function.call(store, &[]).unwrap(); + pub fn reset_script( + &mut self, + script_id: usize, + context: &mut ScriptContext<'_>, + wasm_runner: &WasmRunner, + files: &mut FileManager, + ) { + self.activate_script(script_id, context, wasm_runner, files); + self.deactivate_script(script_id, context, wasm_runner, files); } } |
