From 3181ba4f918e92332d5c3bfeca6b4ba35b67b519 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 23 Oct 2023 21:27:46 -0700 Subject: [PATCH 1/3] Ability to preload textures during gltf loading --- blade-render/src/model/mod.rs | 47 +++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/blade-render/src/model/mod.rs b/blade-render/src/model/mod.rs index 7336064a..46e53e2e 100644 --- a/blade-render/src/model/mod.rs +++ b/blade-render/src/model/mod.rs @@ -7,6 +7,19 @@ use std::{ sync::{Arc, Mutex}, }; +const PRELOAD_TEXTURES: bool = false; + +const META_BASE_COLOR: crate::texture::Meta = crate::texture::Meta { + format: blade_graphics::TextureFormat::Bc1UnormSrgb, + generate_mips: true, + y_flip: false, +}; +const META_NORMAL: crate::texture::Meta = crate::texture::Meta { + format: blade_graphics::TextureFormat::Bc5Snorm, + generate_mips: false, + y_flip: false, +}; + fn pack4x8snorm(v: [f32; 4]) -> u32 { v.iter().rev().fold(0u32, |u, f| { (u << 8) | (f.clamp(-1.0, 1.0) * 127.0 + 0.5) as i8 as u8 as u32 @@ -404,12 +417,24 @@ impl blade_asset::Baker for Baker { let pbr = g_material.pbr_metallic_roughness(); model.materials.push(CookedMaterial { base_color_path: Cow::Owned(match pbr.base_color_texture() { - Some(info) => texture_paths[info.texture().index()].as_bytes().to_vec(), + Some(info) => { + let path = &texture_paths[info.texture().index()]; + if PRELOAD_TEXTURES { + self.asset_textures.load(path, META_BASE_COLOR); + } + path.as_bytes().to_vec() + } None => Vec::new(), }), base_color_factor: pbr.base_color_factor(), normal_path: Cow::Owned(match g_material.normal_texture() { - Some(info) => texture_paths[info.texture().index()].as_bytes().to_vec(), + Some(info) => { + let path = &texture_paths[info.texture().index()]; + if PRELOAD_TEXTURES { + self.asset_textures.load(path, META_BASE_COLOR); + } + path.as_bytes().to_vec() + } None => Vec::new(), }), transparent: g_material.alpha_mode() != gltf::material::AlphaMode::Opaque, @@ -468,14 +493,7 @@ impl blade_asset::Baker for Baker { None } else { let path_str = str::from_utf8(&material.base_color_path).unwrap(); - let (handle, task) = self.asset_textures.load( - path_str, - crate::texture::Meta { - format: blade_graphics::TextureFormat::Bc1UnormSrgb, - generate_mips: true, - y_flip: false, - }, - ); + let (handle, task) = self.asset_textures.load(path_str, META_BASE_COLOR); exe_context.add_fork(&task); Some(handle) }; @@ -483,14 +501,7 @@ impl blade_asset::Baker for Baker { None } else { let path_str = str::from_utf8(&material.normal_path).unwrap(); - let (handle, task) = self.asset_textures.load( - path_str, - crate::texture::Meta { - format: blade_graphics::TextureFormat::Bc5Snorm, - generate_mips: false, - y_flip: false, - }, - ); + let (handle, task) = self.asset_textures.load(path_str, META_NORMAL); exe_context.add_fork(&task); Some(handle) }; From 7d12c461587634a6f18a9f53d30d5aa9a4da8c4b Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 23 Oct 2023 23:38:22 -0700 Subject: [PATCH 2/3] List running tasks, improve transparency --- blade-asset/src/arena.rs | 33 +++++++++++++++++++++++++++++-- blade-asset/src/lib.rs | 10 ++++++++++ blade-render/code/debug-draw.wgsl | 2 +- blade-render/src/asset_hub.rs | 8 ++++++++ examples/scene/main.rs | 20 +++++++++++++++++-- 5 files changed, 68 insertions(+), 5 deletions(-) diff --git a/blade-asset/src/arena.rs b/blade-asset/src/arena.rs index 8a44e942..2bf9bf78 100644 --- a/blade-asset/src/arena.rs +++ b/blade-asset/src/arena.rs @@ -11,7 +11,7 @@ use std::{ }; #[repr(C)] -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Hash, Ord)] struct Address { index: u32, chunk: NonZeroU8, @@ -81,6 +81,10 @@ impl Arena { } } + fn chunk_size(&self, chunk: NonZeroU8) -> usize { + self.min_size << chunk.get() + } + pub fn alloc(&self, value: T) -> Handle { let mut freeman = self.freeman.lock().unwrap(); let (address, chunk_start) = match freeman.free_list.pop() { @@ -93,7 +97,7 @@ impl Arena { index: 0, chunk: NonZeroU8::new(freeman.chunk_bases.len() as _).unwrap(), }; - let size = self.min_size << freeman.chunk_bases.len(); + let size = self.chunk_size(address.chunk); let mut data = (0..size).map(|_| T::default()).collect::>(); let chunk_start: *mut T = data.first_mut().unwrap(); self.chunks[address.chunk.get() as usize].store(chunk_start, Ordering::Release); @@ -126,6 +130,31 @@ impl Arena { let ptr = self.get_mut_ptr(handle); unsafe { mem::take(&mut *ptr) } } + + pub fn for_each(&self, mut fun: impl FnMut(Handle, &T)) { + let mut freeman = self.freeman.lock().unwrap(); + freeman.free_list.sort(); // enables fast search + for (chunk_index, chunk_start) in self.chunks[..freeman.chunk_bases.len()] + .iter() + .enumerate() + .skip(1) + { + let first_ptr = chunk_start.load(Ordering::Acquire); + let chunk = NonZeroU8::new(chunk_index as _).unwrap(); + for index in 0..self.chunk_size(chunk) { + let address = Address { + index: index as u32, + chunk, + }; + if freeman.free_list.binary_search(&address).is_err() { + //Note: this is only safe if `get_mut_ptr` isn't called + // for example, during hot reloading. + let item = unsafe { &*first_ptr.add(index) }; + fun(Handle(address, PhantomData), item); + } + } + } + } } impl Drop for FreeManager { diff --git a/blade-asset/src/lib.rs b/blade-asset/src/lib.rs index 8f71ee42..1a1fdf1f 100644 --- a/blade-asset/src/lib.rs +++ b/blade-asset/src/lib.rs @@ -529,4 +529,14 @@ impl AssetManager { task }) } + + pub fn list_running_tasks(&self, list: &mut Vec) { + self.slots.for_each(|_, slot| { + if let Some(ref task) = slot.load_task { + if !task.is_done() { + list.push(task.clone()); + } + } + }); + } } diff --git a/blade-render/code/debug-draw.wgsl b/blade-render/code/debug-draw.wgsl index ce1be0f0..01065e70 100644 --- a/blade-render/code/debug-draw.wgsl +++ b/blade-render/code/debug-draw.wgsl @@ -23,7 +23,7 @@ fn debug_vs(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index) inst let ndc = local_dir.xy / tan(0.5 * camera.fov); var out: DebugVarying; - out.pos = vec4(ndc, 0.0, local_dir.z); + out.pos = vec4(ndc, 0.0, -local_dir.z); out.color = unpack4x8unorm(point.color); out.dir = world_dir; return out; diff --git a/blade-render/src/asset_hub.rs b/blade-render/src/asset_hub.rs index cec69f56..aa297e52 100644 --- a/blade-render/src/asset_hub.rs +++ b/blade-render/src/asset_hub.rs @@ -77,6 +77,14 @@ impl AssetHub { finish_task: self.shaders.choir.spawn(name).init_dummy(), } } + + pub fn list_running_tasks(&self) -> Vec { + let mut list = Vec::new(); + self.textures.list_running_tasks(&mut list); + self.models.list_running_tasks(&mut list); + self.shaders.list_running_tasks(&mut list); + list + } } impl LoadContext<'_> { diff --git a/examples/scene/main.rs b/examples/scene/main.rs index 152a5180..283f53ce 100644 --- a/examples/scene/main.rs +++ b/examples/scene/main.rs @@ -378,8 +378,14 @@ impl Example { self.render_times.push_front(delta.as_millis() as u32); if self.pending_scene.is_some() { - ui.spinner(); + ui.horizontal(|ui| { + ui.label("Loading..."); + ui.spinner(); + }); //TODO: seeing GPU Device Lost issues without this + for task in self.asset_hub.list_running_tasks() { + ui.label(format!("{}", task.as_ref())); + } return; } @@ -778,7 +784,17 @@ fn main() { let mut quit = false; let raw_input = egui_winit.take_egui_input(&window); let egui_output = egui_ctx.run(raw_input, |egui_ctx| { - let frame = egui::Frame::default().fill(egui::Color32::from_white_alpha(0x80)); + let frame = { + let mut frame = egui::Frame::side_top_panel(&egui_ctx.style()); + let mut fill = frame.fill.to_array(); + for f in fill.iter_mut() { + *f = (*f as u32 * 7 / 8) as u8; + } + frame.fill = egui::Color32::from_rgba_premultiplied( + fill[0], fill[1], fill[2], fill[3], + ); + frame + }; egui::SidePanel::right("control_panel") .frame(frame) .show(egui_ctx, |ui| { From bd52e06ae20b3e52022a00e0a748e21ee7b6265f Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Mon, 23 Oct 2023 23:45:42 -0700 Subject: [PATCH 3/3] Fix camera rotation --- examples/scene/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/scene/main.rs b/examples/scene/main.rs index 283f53ce..36e48a3c 100644 --- a/examples/scene/main.rs +++ b/examples/scene/main.rs @@ -767,13 +767,14 @@ fn main() { winit::event::WindowEvent::CursorMoved { position, .. } => { last_mouse_pos = [position.x as i32, position.y as i32]; if let Some(ref mut drag) = drag_start { + // This is rotation around the world UP, which is assumed to be Y let qx = glam::Quat::from_rotation_y( (drag.screen_pos.x - last_mouse_pos[0]) as f32 * rotate_speed, ); let qy = glam::Quat::from_rotation_x( (drag.screen_pos.y - last_mouse_pos[1]) as f32 * rotate_speed, ); - example.camera.rot = (drag.rotation * qx * qy).into(); + example.camera.rot = (qx * drag.rotation * qy).into(); example.debug.mouse_pos = None; } }