render: simplify light buffer updating
This commit is contained in:
parent
7576979797
commit
6182a4b9c8
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"rdocCaptureSettings": 1,
|
||||
"settings": {
|
||||
"autoStart": true,
|
||||
"autoStart": false,
|
||||
"commandLine": "",
|
||||
"environment": [
|
||||
],
|
||||
"executable": "/media/data_drive/Development/Rust/lyra-engine/target/debug/testbed",
|
||||
"inject": false,
|
||||
"numQueuedFrames": 1,
|
||||
"numQueuedFrames": 0,
|
||||
"options": {
|
||||
"allowFullscreen": true,
|
||||
"allowVSync": true,
|
||||
|
@ -22,7 +22,7 @@
|
|||
"softMemoryLimit": 0,
|
||||
"verifyBufferAccess": false
|
||||
},
|
||||
"queuedFrameCap": 5,
|
||||
"queuedFrameCap": 0,
|
||||
"workingDir": "/media/data_drive/Development/Rust/lyra-engine/examples/testbed"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ pub mod spotlight;
|
|||
use lyra_ecs::{Entity, Tick, World, query::{Entities, TickOf}};
|
||||
pub use point::*;
|
||||
pub use spotlight::*;
|
||||
use tracing::debug;
|
||||
|
||||
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 buffer: Rc<wgpu::Buffer>,
|
||||
//pub bind_group_pair: BindGroupPair,
|
||||
pub bind_group: Rc<wgpu::BindGroup>,
|
||||
pub bind_group_layout: Rc<wgpu::BindGroupLayout>,
|
||||
pub light_indexes: HashMap<Entity, u32>,
|
||||
dead_indices: VecDeque<u32>,
|
||||
pub current_light_idx: u32,
|
||||
max_light_count: u64,
|
||||
}
|
||||
|
||||
impl LightUniformBuffers {
|
||||
|
@ -161,90 +159,35 @@ impl LightUniformBuffers {
|
|||
buffer: Rc::new(buffer),
|
||||
bind_group: Rc::new(bindgroup),
|
||||
bind_group_layout: Rc::new(bindgroup_layout),
|
||||
light_indexes: Default::default(),
|
||||
current_light_idx: 0,
|
||||
dead_indices: VecDeque::new(),
|
||||
max_light_count: max_buffer_sizes / mem::size_of::<LightUniform>() as u64,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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) {
|
||||
// used to detect what lights were removed
|
||||
let mut missed_lights: HashMap<Entity, u32> = self.light_indexes.drain().collect();
|
||||
|
||||
for (entity, point_light, transform, light_epoch, transform_epoch)
|
||||
in world.view_iter::<(Entities, &PointLight, &Transform, TickOf<PointLight>, TickOf<Transform>)>() {
|
||||
let _ = world_tick;
|
||||
let mut lights = vec![];
|
||||
|
||||
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_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 (point_light, transform) in world.view_iter::<(&PointLight, &Transform)>() {
|
||||
let uniform = LightUniform::from_point_light_bundle(&point_light, &transform);
|
||||
lights.push(uniform);
|
||||
}
|
||||
|
||||
for (entity, spot_light, transform, light_epoch, transform_epoch)
|
||||
in world.view_iter::<(Entities, &SpotLight, &Transform, TickOf<SpotLight>, TickOf<Transform>)>() {
|
||||
|
||||
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 (spot_light, transform) in world.view_iter::<(&SpotLight, &Transform)>() {
|
||||
let uniform = LightUniform::from_spot_light_bundle(&spot_light, &transform);
|
||||
lights.push(uniform);
|
||||
}
|
||||
|
||||
for (entity, dir_light, transform, light_epoch, transform_epoch)
|
||||
in world.view_iter::<(Entities, &DirectionalLight, &Transform, TickOf<DirectionalLight>, TickOf<Transform>)>() {
|
||||
|
||||
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]));
|
||||
}
|
||||
for (dir_light, transform) in world.view_iter::<(&DirectionalLight, &Transform)>() {
|
||||
let uniform = LightUniform::from_directional_bundle(&dir_light, &transform);
|
||||
lights.push(uniform);
|
||||
}
|
||||
|
||||
// anything left in missed_lights were lights that were deleted
|
||||
let len = missed_lights.len();
|
||||
self.dead_indices.reserve(len);
|
||||
assert!(lights.len() < self.max_light_count as _); // ensure we dont overwrite the buffer
|
||||
|
||||
for (_, v) in missed_lights.drain() {
|
||||
// write zeros in place of this now dead light, the enabled boolean will be set to false
|
||||
let mut zeros = Vec::new();
|
||||
zeros.resize(mem::size_of::<LightUniform>(), 0u32);
|
||||
|
||||
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]));
|
||||
// write the amount of lights to the buffer, and right after that the list of lights.
|
||||
queue.write_buffer(&self.buffer, 0, bytemuck::cast_slice(&[lights.len()]));
|
||||
// the size of u32 is multiplied by 4 because of gpu alignment requirements
|
||||
queue.write_buffer(&self.buffer, mem::size_of::<u32>() as u64 * 4, bytemuck::cast_slice(lights.as_slice()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue