diff --git a/src/main.rs b/src/main.rs index 84a07ad..eca7b28 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ use vulkanalia::bytecode::Bytecode; use std::collections::HashSet; use std::ffi::CStr; +use std::time::{Duration, SystemTime}; use std::os::raw::c_void; // extension imports @@ -182,6 +183,7 @@ struct App { scene_handler: scene::Scene, show_frame_rate: bool, synchronized: usize, + appstart: Instant, } impl App { @@ -244,7 +246,8 @@ impl App { cur_pos: cur_pos, scene_handler, show_frame_rate: false, - synchronized: 0 + synchronized: 0, + appstart: Instant::now(), }) } @@ -276,7 +279,14 @@ impl App { self.data.images_in_flight[image_index] = in_flight_fence; self.update_uniform_buffer(image_index)?; + let time = self.appstart.elapsed().as_secs_f32() / 1.0; + self.scene_handler.point_lights[0].borrow_mut().set_pos(cgmath::vec3((10.0 + 64.0) as f32 + time.sin(), (10.0 + 64.0) as f32 + time.cos(), 11.0)); + self.synchronized = 0; + if self.synchronized < MAX_FRAMES_IN_FLIGHT { + if self.scene_handler.is_dirty() { + self.scene_handler.update_memory(&mut self.data, true) + } buffer::update_storage_buffer(&self.instance, &self.device, &self.data, image_index, &self.scene_handler)?; self.synchronized += 1 } diff --git a/src/scene/empty_volume.rs b/src/scene/empty_volume.rs index b7f2cb9..f3d851a 100644 --- a/src/scene/empty_volume.rs +++ b/src/scene/empty_volume.rs @@ -17,6 +17,7 @@ use super::AppData; use super::LightsIter; use super::Scene; +#[derive(Clone, Debug)] pub struct EmptyVolume { pub memory_start: usize, @@ -49,6 +50,9 @@ pub struct EmptyVolume { pub neighbor_front: Vec<Option<Rc<RefCell<Self>>>>, pub scale: f32, + + old_memory_size: u32, + dirty: bool, } impl EmptyVolume { @@ -304,6 +308,8 @@ impl EmptyVolume { neighbor_back: vec![], neighbor_front: vec![], scale: tree.borrow().scale, + old_memory_size: 0, + dirty: true, }; println!("adding neighbor references"); // MARK: fill in info in the neighbor octtree @@ -1274,7 +1280,7 @@ impl Memorizable for EmptyVolume { mem_size } // MARK: insert into Memory - fn insert_into_memory(&self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { + fn insert_into_memory(&mut self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { let mut mem_index = self.memory_start; //pos v[mem_index] = u32::from_ne_bytes(self.real_position.x.to_ne_bytes()); @@ -1591,6 +1597,9 @@ impl Memorizable for EmptyVolume { v[mem_index] = 0; mem_index += 1; } + + self.dirty = false; + self.old_memory_size = self.get_buffer_mem_size(data); //println!("last memory index of volume was {}, equivalent to {}kB", mem_index, mem_index * 32 / 8 / 1024); v } @@ -1602,6 +1611,13 @@ impl Memorizable for EmptyVolume { fn set_memory_start(&mut self, memory_start: usize) { self.memory_start = memory_start; } + + fn get_prev_buffer_mem_size(&self) -> u32 { + self.old_memory_size + } + fn is_dirty(&self) -> bool { + self.dirty + } } impl PartialEq for EmptyVolume { diff --git a/src/scene/generators.rs b/src/scene/generators.rs index 9461344..3527dd0 100644 --- a/src/scene/generators.rs +++ b/src/scene/generators.rs @@ -91,9 +91,9 @@ pub fn generate_test_scene(scene: &mut Scene, data: &mut AppData) -> Result<(Poi }; oct_tree2.set_cube(cube.clone()); - scene.point_lights.push(Rc::new(RefCell::new(PointLight { pos: vec3(11.0 + grid_size as f32, 11.0 + grid_size as f32, 11.0) * scale, color: vec3(2.0, 2.0, 2.0), memory_start: 0 }))); - scene.point_lights.push(Rc::new(RefCell::new(PointLight { pos: vec3(9.0 + grid_size as f32, 9.0 + grid_size as f32, 11.0) * scale, color: vec3(0.5, 0.5, 0.5), memory_start: 0 }))); - scene.directional_lights.push(Rc::new(RefCell::new(DirectionalLight { direction: vec3(1.0, 1.0, -1.0), color: vec3(0.1, 0.1, 0.1), memory_start: 0 }))); + scene.point_lights.push(Rc::new(RefCell::new(PointLight::init(vec3(11.0 + grid_size as f32, 11.0 + grid_size as f32, 11.0) * scale, vec3(2.0, 2.0, 2.0))))); + scene.point_lights.push(Rc::new(RefCell::new(PointLight::init(vec3(9.0 + grid_size as f32, 9.0 + grid_size as f32, 11.0) * scale, vec3(0.5, 0.5, 0.5))))); + scene.directional_lights.push(Rc::new(RefCell::new(DirectionalLight::init(vec3(1.0, 1.0, -1.0), vec3(0.1, 0.1, 0.1))))); let cube = Cuboid { pos: vec3(11.0 + grid_size as f32, 11.0 + grid_size as f32, 11.0) * scale, @@ -204,7 +204,7 @@ pub fn generate_test_scene2(scene: &mut Scene, data: &mut AppData, chunk_num_x: let center_x = rng.gen_range(0..max_x) as f32; let center_y = rng.gen_range(0..max_y) as f32; let final_height = height_map[center_x.floor() as usize][center_y.floor() as usize] + height; - scene.point_lights.push(Rc::new(RefCell::new(PointLight { pos: vec3(center_x, center_y, final_height), color: vec3(1.0, 1.0, 1.0), memory_start: 0 }))); + scene.point_lights.push(Rc::new(RefCell::new(PointLight::init(vec3(center_x, center_y, final_height), vec3(1.0, 1.0, 1.0))))); let cube = Cuboid { pos: vec3(center_x, center_y, final_height), diff --git a/src/scene/light.rs b/src/scene/light.rs index 9c64389..b15e77b 100644 --- a/src/scene/light.rs +++ b/src/scene/light.rs @@ -22,9 +22,21 @@ pub trait LightSource: Light + Memorizable {} #[derive(Clone, Debug, PartialEq)] pub struct PointLight{ - pub pos: vertex::Vec3, - pub color: vertex::Vec3, + pos: vertex::Vec3, + color: vertex::Vec3, pub memory_start: usize, + dirty: bool, +} + +impl PointLight { + pub fn init(pos: vertex::Vec3, color: vertex::Vec3) -> Self { + Self { pos: pos, color: color, memory_start: 0, dirty: true } + } + + pub fn set_pos(&mut self, pos: vertex::Vec3) { + self.pos = pos; + self.dirty = true; + } } impl Memorizable for PointLight { @@ -32,7 +44,7 @@ impl Memorizable for PointLight { 1 + 3 + 3 } - fn insert_into_memory(&self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { + fn insert_into_memory(&mut self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { v[self.memory_start] = LightType::POINT as u32; v[self.memory_start + 1] = u32::from_ne_bytes(self.pos.x.to_ne_bytes()); @@ -42,6 +54,9 @@ impl Memorizable for PointLight { v[self.memory_start + 4] = (self.color.x * 255.0) as u32; v[self.memory_start + 5] = (self.color.y * 255.0) as u32; v[self.memory_start + 6] = (self.color.z * 255.0) as u32; + + self.dirty = false; + v } @@ -52,6 +67,13 @@ impl Memorizable for PointLight { fn set_memory_start(&mut self, memory_start: usize) { self.memory_start = memory_start; } + + fn get_prev_buffer_mem_size(&self) -> u32 { + 1 + 3 + 3 + } + fn is_dirty(&self) -> bool { + self.dirty + } } impl Light for PointLight { @@ -120,9 +142,16 @@ impl LightSource for PointLight {} #[derive(Clone, Debug, PartialEq)] pub struct DirectionalLight{ - pub direction: vertex::Vec3, - pub color: vertex::Vec3, + direction: vertex::Vec3, + color: vertex::Vec3, pub memory_start: usize, + dirty: bool, +} + +impl DirectionalLight { + pub fn init(direction: vertex::Vec3, color: vertex::Vec3) -> Self { + Self { direction: direction, color: color, memory_start: 0, dirty: true } + } } impl Memorizable for DirectionalLight { @@ -130,7 +159,7 @@ impl Memorizable for DirectionalLight { 1 + 3 + 3 } - fn insert_into_memory(&self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { + fn insert_into_memory(&mut self, mut v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32> { v[self.memory_start] = LightType::DIRECTION as u32; v[self.memory_start + 1] = u32::from_ne_bytes(self.direction.x.to_ne_bytes()); @@ -140,6 +169,10 @@ impl Memorizable for DirectionalLight { v[self.memory_start + 4] = (self.color.x * 255.0) as u32; v[self.memory_start + 5] = (self.color.y * 255.0) as u32; v[self.memory_start + 6] = (self.color.z * 255.0) as u32; + + self.dirty = false; + + v } @@ -150,6 +183,13 @@ impl Memorizable for DirectionalLight { fn set_memory_start(&mut self, memory_start: usize) { self.memory_start = memory_start; } + + fn get_prev_buffer_mem_size(&self) -> u32 { + 1 + 3 + 3 + } + fn is_dirty(&self) -> bool { + self.dirty + } } impl Light for DirectionalLight { @@ -176,7 +216,7 @@ mod test { #[test] fn test_memorizable() { - let p = PointLight {pos: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0}; + let mut p = PointLight::init(vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}); let data= AppData::default(); let scene = Scene::default(); @@ -184,13 +224,15 @@ mod test { assert!(mem_size == 7); let mut memory = vec![0; 7]; + assert!(!p.dirty); p.insert_into_memory(memory, &data, &scene); + assert!(p.dirty); } #[test] #[should_panic] fn test_mem_size() { - let p = PointLight {pos: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0}; + let mut p = PointLight::init(vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}); let data= AppData::default(); let scene = Scene::default(); @@ -198,12 +240,14 @@ mod test { assert!(mem_size == 7); let mut memory = vec![0; 6]; + assert!(!p.dirty); p.insert_into_memory(memory, &data, &scene); + assert!(p.dirty); } #[test] fn test_memorizable_directional_light() { - let p = DirectionalLight {direction: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0}; + let mut p = DirectionalLight::init(vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}); let data= AppData::default(); let scene = Scene::default(); @@ -211,13 +255,15 @@ mod test { assert!(mem_size == 7); let mut memory = vec![0; 7]; + assert!(!p.dirty); p.insert_into_memory(memory, &data, &scene); + assert!(p.dirty); } #[test] #[should_panic] fn test_mem_size_directional_light() { - let p = DirectionalLight {direction: vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, color: vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}, memory_start: 0}; + let mut p = DirectionalLight::init(vertex::Vec3 { x: 1.0, y: 2.0, z: 3.0}, vertex::Vec3 { x: 0.0, y: 1.0, z: 0.0}); let data= AppData::default(); let scene = Scene::default(); @@ -225,6 +271,8 @@ mod test { assert!(mem_size == 7); let mut memory = vec![0; 6]; + assert!(!p.dirty); p.insert_into_memory(memory, &data, &scene); + assert!(p.dirty); } } \ No newline at end of file diff --git a/src/scene/memorizable.rs b/src/scene/memorizable.rs index 22d8519..2551a58 100644 --- a/src/scene/memorizable.rs +++ b/src/scene/memorizable.rs @@ -2,9 +2,11 @@ use super::light::LightSource; use super::AppData; use super::Scene; -pub trait Memorizable { +pub trait Memorizable: core::fmt::Debug { fn get_buffer_mem_size(&self, data: &AppData) -> u32; - fn insert_into_memory(&self, v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32>; + fn get_prev_buffer_mem_size(&self) -> u32; + fn is_dirty(&self) -> bool; + fn insert_into_memory(&mut self, v: Vec<u32>, data: &AppData, scene: &Scene) -> Vec<u32>; fn get_memory_start(&self) -> usize; fn set_memory_start(&mut self, memory_start: usize); } \ No newline at end of file diff --git a/src/scene/mod.rs b/src/scene/mod.rs index b9e7b91..fc72d62 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -59,8 +59,10 @@ pub struct Scene { pub oct_trees: Vec<Vec<Vec<Rc<RefCell<OctTree<Cube>>>>>>, - point_lights: Vec<Rc<RefCell<PointLight>>>, - directional_lights: Vec<Rc<RefCell<DirectionalLight>>>, + pub point_lights: Vec<Rc<RefCell<PointLight>>>, + pub directional_lights: Vec<Rc<RefCell<DirectionalLight>>>, + + pub memorizables: Vec<Rc<RefCell<dyn Memorizable>>>, } impl Scene { @@ -121,48 +123,27 @@ impl Scene { z_index += 1; } println!("number of empty volumes is {}", empty_volumes.len()); - - let mut memory_index = 6; - // 0 - location for the maximum number of lights referenced per chunk (also will be the invalid memory allocation for pointing to a nonexistant neighbor) - // 1 - location for the max iterations per light - // 2 - diffuse raster samples (2*n + 1) * (2*n + 1) so as to always have at least the central fragment covered - // 3 - diffuse raster size - // 4 - max recursive rays - // 5 - diffuse rays per hit - for light in LightsIter::new(self) { - light.borrow_mut().set_memory_start(memory_index); - memory_index += light.borrow_mut().get_buffer_mem_size(data) as usize; + + for light in &self.point_lights { + self.memorizables.push(light.clone()); + } + + for light in &self.directional_lights { + self.memorizables.push(light.clone()); } for volume in &empty_volumes { - volume.borrow_mut().set_memory_start(memory_index); - memory_index += volume.borrow().get_buffer_mem_size(data) as usize; - + self.memorizables.push(volume.clone()); } + + self.update_memory(data, false); + for volume in &empty_volumes { let quads = volume.borrow().to_quads(); for quad in quads { quad.draw(&data.topology, self.rt_vertices.len(), self); } } - println!("Memory size is {} kB, max indes is {}", memory_index * 32 / 8 /1024 + 1, memory_index); - let mut volume_vec = vec![data.num_lights_per_volume; memory_index]; - volume_vec[1] = data.max_iterations_per_light; - volume_vec[2] = data.diffuse_raster_steps; - volume_vec[3] = u32::from_ne_bytes(data.diffuse_raster_size.to_ne_bytes()); - volume_vec[4] = data.max_recursive_rays; - volume_vec[5] = data.diffuse_rays_per_hit; - - for volume in &empty_volumes { - volume_vec = volume.borrow().insert_into_memory(volume_vec, data, &self); - } - for light in LightsIter::new(self) { - volume_vec = light.borrow().insert_into_memory(volume_vec, data, &self); - } - //println!("volume_vec print {:?}", volume_vec); - - self.rt_memory = volume_vec; - data.scene_rt_memory_size = (self.rt_memory.len() * 4) as u64; // size of the needed buffer size in bytes if self.vertices.len() != 0 { (self.vertex_buffer_cube, self.vertex_buffer_memory_cube) = buffer::create_vertex_buffer(instance, device, &data, &self.vertices)?; @@ -184,6 +165,55 @@ impl Scene { } + pub fn is_dirty(&self) -> bool { + for memorizable in &self.memorizables { + if memorizable.borrow().is_dirty() { + return true + } + } + return false + } + + pub fn update_memory(&mut self, data: &mut AppData, reuse_memory: bool) { + // reuse_memory controls whether a fresh data vector is created or the existing one is used if it is the right size + let mut memory_index = 6; + // 0 - location for the maximum number of lights referenced per chunk (also will be the invalid memory allocation for pointing to a nonexistant neighbor) + // 1 - location for the max iterations per light + // 2 - diffuse raster samples (2*n + 1) * (2*n + 1) so as to always have at least the central fragment covered + // 3 - diffuse raster size + // 4 - max recursive rays + // 5 - diffuse rays per hit + for memorizable in &self.memorizables { + memorizable.borrow_mut().set_memory_start(memory_index); + memory_index += memorizable.borrow_mut().get_buffer_mem_size(data) as usize; + } + + //println!("Memory size is {} kB, max indes is {}", memory_index * 32 / 8 /1024 + 1, memory_index); + let mut volume_vec; + let needs_overwrite; + if !reuse_memory || memory_index != self.rt_memory.len() { + volume_vec = vec![data.num_lights_per_volume; memory_index]; + needs_overwrite = true; + } else { + needs_overwrite = false; + volume_vec = self.rt_memory.clone(); + } + volume_vec[1] = data.max_iterations_per_light; + volume_vec[2] = data.diffuse_raster_steps; + volume_vec[3] = u32::from_ne_bytes(data.diffuse_raster_size.to_ne_bytes()); + volume_vec[4] = data.max_recursive_rays; + volume_vec[5] = data.diffuse_rays_per_hit; + + for memorizable in &self.memorizables { + if needs_overwrite || memorizable.borrow().is_dirty() { + volume_vec = memorizable.borrow_mut().insert_into_memory(volume_vec, data, &self); + } + } + + self.rt_memory = volume_vec; + data.scene_rt_memory_size = (self.rt_memory.len() * 4) as u64; // size of the needed buffer size in bytes + } + pub unsafe fn destroy(&mut self, device: &vulkanalia::Device) { device.destroy_buffer(self.index_buffer_cube, None); device.free_memory(self.index_buffer_memory_cube, None);