render: simplify light buffer updating

This commit is contained in:
SeanOMik 2024-06-15 23:52:46 -04:00
parent 7576979797
commit 6182a4b9c8
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
2 changed files with 22 additions and 79 deletions

View File

@ -1,13 +1,13 @@
{ {
"rdocCaptureSettings": 1, "rdocCaptureSettings": 1,
"settings": { "settings": {
"autoStart": true, "autoStart": false,
"commandLine": "", "commandLine": "",
"environment": [ "environment": [
], ],
"executable": "/media/data_drive/Development/Rust/lyra-engine/target/debug/testbed", "executable": "/media/data_drive/Development/Rust/lyra-engine/target/debug/testbed",
"inject": false, "inject": false,
"numQueuedFrames": 1, "numQueuedFrames": 0,
"options": { "options": {
"allowFullscreen": true, "allowFullscreen": true,
"allowVSync": true, "allowVSync": true,
@ -22,7 +22,7 @@
"softMemoryLimit": 0, "softMemoryLimit": 0,
"verifyBufferAccess": false "verifyBufferAccess": false
}, },
"queuedFrameCap": 5, "queuedFrameCap": 0,
"workingDir": "/media/data_drive/Development/Rust/lyra-engine/examples/testbed" "workingDir": "/media/data_drive/Development/Rust/lyra-engine/examples/testbed"
} }
} }

View File

@ -5,6 +5,7 @@ pub mod spotlight;
use lyra_ecs::{Entity, Tick, World, query::{Entities, TickOf}}; use lyra_ecs::{Entity, Tick, World, query::{Entities, TickOf}};
pub use point::*; pub use point::*;
pub use spotlight::*; pub use spotlight::*;
use tracing::debug;
use std::{collections::{HashMap, VecDeque}, marker::PhantomData, mem, rc::Rc}; use std::{collections::{HashMap, VecDeque}, marker::PhantomData, mem, rc::Rc};
@ -99,12 +100,9 @@ impl<U: Default + bytemuck::Pod + bytemuck::Zeroable> LightBuffer<U> {
pub(crate) struct LightUniformBuffers { pub(crate) struct LightUniformBuffers {
pub buffer: Rc<wgpu::Buffer>, pub buffer: Rc<wgpu::Buffer>,
//pub bind_group_pair: BindGroupPair,
pub bind_group: Rc<wgpu::BindGroup>, pub bind_group: Rc<wgpu::BindGroup>,
pub bind_group_layout: Rc<wgpu::BindGroupLayout>, pub bind_group_layout: Rc<wgpu::BindGroupLayout>,
pub light_indexes: HashMap<Entity, u32>, max_light_count: u64,
dead_indices: VecDeque<u32>,
pub current_light_idx: u32,
} }
impl LightUniformBuffers { impl LightUniformBuffers {
@ -161,90 +159,35 @@ impl LightUniformBuffers {
buffer: Rc::new(buffer), buffer: Rc::new(buffer),
bind_group: Rc::new(bindgroup), bind_group: Rc::new(bindgroup),
bind_group_layout: Rc::new(bindgroup_layout), bind_group_layout: Rc::new(bindgroup_layout),
light_indexes: Default::default(), max_light_count: max_buffer_sizes / mem::size_of::<LightUniform>() as u64,
current_light_idx: 0,
dead_indices: VecDeque::new(),
} }
} }
/// Returns the index for the entity, and if this index is new
fn get_index_for(&mut self, missed: &mut HashMap<Entity, u32>, entity: Entity) -> (bool, u32) {
let idx = missed.remove(&entity)
.map(|v| (false, v))
.or_else(||
self.dead_indices.pop_front()
.map(|v| (true, v))
)
.unwrap_or_else(|| {
let t = self.current_light_idx;
self.current_light_idx += 1;
(true, t)
});
idx
}
pub fn update_lights(&mut self, queue: &wgpu::Queue, world_tick: Tick, world: &World) { pub fn update_lights(&mut self, queue: &wgpu::Queue, world_tick: Tick, world: &World) {
// used to detect what lights were removed let _ = world_tick;
let mut missed_lights: HashMap<Entity, u32> = self.light_indexes.drain().collect(); let mut lights = vec![];
for (entity, point_light, transform, light_epoch, transform_epoch)
in world.view_iter::<(Entities, &PointLight, &Transform, TickOf<PointLight>, TickOf<Transform>)>() {
let (new, idx) = self.get_index_for(&mut missed_lights, entity); for (point_light, transform) in world.view_iter::<(&PointLight, &Transform)>() {
self.light_indexes.insert(entity, idx); let uniform = LightUniform::from_point_light_bundle(&point_light, &transform);
lights.push(uniform);
if new || light_epoch == world_tick || transform_epoch == world_tick {
let uniform = LightUniform::from_point_light_bundle(&point_light, &transform);
let offset = mem::size_of::<u32>() * 4 + mem::size_of::<LightUniform>() * idx as usize;
queue.write_buffer(&self.buffer, offset as _, bytemuck::cast_slice(&[uniform]));
}
} }
for (entity, spot_light, transform, light_epoch, transform_epoch) for (spot_light, transform) in world.view_iter::<(&SpotLight, &Transform)>() {
in world.view_iter::<(Entities, &SpotLight, &Transform, TickOf<SpotLight>, TickOf<Transform>)>() { let uniform = LightUniform::from_spot_light_bundle(&spot_light, &transform);
lights.push(uniform);
let (new, idx) = self.get_index_for(&mut missed_lights, entity);
self.light_indexes.insert(entity, idx);
if new || light_epoch == world_tick || transform_epoch == world_tick {
let uniform = LightUniform::from_spot_light_bundle(&spot_light, &transform);
let offset = mem::size_of::<u32>() * 4 + mem::size_of::<LightUniform>() * idx as usize;
queue.write_buffer(&self.buffer, offset as _, bytemuck::cast_slice(&[uniform]));
}
} }
for (entity, dir_light, transform, light_epoch, transform_epoch) for (dir_light, transform) in world.view_iter::<(&DirectionalLight, &Transform)>() {
in world.view_iter::<(Entities, &DirectionalLight, &Transform, TickOf<DirectionalLight>, TickOf<Transform>)>() { let uniform = LightUniform::from_directional_bundle(&dir_light, &transform);
lights.push(uniform);
let (new, idx) = self.get_index_for(&mut missed_lights, entity);
self.light_indexes.insert(entity, idx);
if new || light_epoch == world_tick || transform_epoch == world_tick {
let uniform = LightUniform::from_directional_bundle(&dir_light, &transform);
let offset = mem::size_of::<u32>() * 4 + mem::size_of::<LightUniform>() * idx as usize;
queue.write_buffer(&self.buffer, offset as _, bytemuck::cast_slice(&[uniform]));
}
} }
// anything left in missed_lights were lights that were deleted assert!(lights.len() < self.max_light_count as _); // ensure we dont overwrite the buffer
let len = missed_lights.len();
self.dead_indices.reserve(len);
for (_, v) in missed_lights.drain() { // write the amount of lights to the buffer, and right after that the list of lights.
// write zeros in place of this now dead light, the enabled boolean will be set to false queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[lights.len()]));
let mut zeros = Vec::new(); // the size of u32 is multiplied by 4 because of gpu alignment requirements
zeros.resize(mem::size_of::<LightUniform>(), 0u32); queue.write_buffer(&self.buffer, mem::size_of::<u32>() as u64 * 4, bytemuck::cast_slice(lights.as_slice()));
let offset = mem::size_of::<u32>() * 4 + mem::size_of::<LightUniform>() * v as usize;
queue.write_buffer(&self.buffer, offset as _, bytemuck::cast_slice(zeros.as_slice()));
self.dead_indices.push_back(v);
}
// update the amount of lights, then the array of lights
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[self.current_light_idx as u32]));
} }
} }