Expand transform buffers when they're full

This commit is contained in:
SeanOMik 2023-09-04 14:04:52 -04:00
parent ec960b8f94
commit f339d048b2
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
1 changed files with 78 additions and 12 deletions

View File

@ -57,12 +57,16 @@ struct TransformBufferIndices {
} }
struct TransformBuffers { struct TransformBuffers {
//transform_layout: wgpu::BindGroupLayout,
/// A vector storing the EntityId and /// A vector storing the EntityId and
just_updated: HashMap<EntityId, TransformBufferIndices>, just_updated: HashMap<EntityId, TransformBufferIndices>,
not_updated: HashMap<EntityId, TransformBufferIndices>, not_updated: HashMap<EntityId, TransformBufferIndices>,
dead_indices: VecDeque<TransformBufferIndices>, dead_indices: VecDeque<TransformBufferIndices>,
next_indices: TransformBufferIndices, next_indices: TransformBufferIndices,
buffer_bindgroups: Vec<(wgpu::Buffer, wgpu::BindGroup)>, /// (transform count, buffer, bindgroup)
buffer_bindgroups: Vec<(usize, wgpu::Buffer, wgpu::BindGroup)>,
/// The max amount of transforms in a buffer
max_transform_count: usize,
} }
impl TransformBuffers { impl TransformBuffers {
@ -72,25 +76,31 @@ impl TransformBuffers {
.expect("Use 'insert_entity' for new entities"); .expect("Use 'insert_entity' for new entities");
self.just_updated.insert(entity, indices); self.just_updated.insert(entity, indices);
let (buffer, _) = self.buffer_bindgroups.get(indices.buffer_index).unwrap(); let (_, buffer, _) = self.buffer_bindgroups.get(indices.buffer_index).unwrap();
queue.write_buffer(buffer, indices.transform_index as u64 * limits.min_uniform_buffer_offset_alignment as u64, bytemuck::bytes_of(&transform)); queue.write_buffer(buffer, indices.transform_index as u64 * limits.min_uniform_buffer_offset_alignment as u64, bytemuck::bytes_of(&transform));
} }
/// Insert a new entity into the buffer, returns where it was stored. /// Insert a new entity into the buffer, returns where it was stored.
fn insert_entity(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform: glam::Mat4) -> TransformBufferIndices { fn insert_entity(&mut self, queue: &wgpu::Queue, limits: &Limits, entity: EntityId, transform: glam::Mat4) -> TransformBufferIndices {
// get a dead index, or create a new one // get a dead index, or create a new one
let indices = if let Some(index) = self.dead_indices.pop_front() { let (indices, buffer) = if let Some(index) = self.dead_indices.pop_front() {
index let (_, buffer, _) = self.buffer_bindgroups.get(index.buffer_index).unwrap();
(index, &*buffer)
} else { } else {
// TODO: Create new buffer if this one is full
let indices = &mut self.next_indices; let indices = &mut self.next_indices;
let new = indices.clone(); let this_idx = indices.clone();
let (count, buffer, _) = self.buffer_bindgroups.get_mut(indices.buffer_index).unwrap();
if count.clone() >= self.max_transform_count {
panic!("Transform buffer is filled and 'next_indices' was not incremented! Was a new buffer created?");
}
*count += 1;
indices.transform_index += 1; indices.transform_index += 1;
new (this_idx, &*buffer)
}; };
let (buffer, _) = self.buffer_bindgroups.get(indices.buffer_index).unwrap();
queue.write_buffer(buffer, Self::get_offset_for(limits, indices), bytemuck::bytes_of(&transform)); queue.write_buffer(buffer, Self::get_offset_for(limits, indices), bytemuck::bytes_of(&transform));
self.just_updated.insert(entity, indices); self.just_updated.insert(entity, indices);
@ -112,6 +122,15 @@ impl TransformBuffers {
fn get_offset_for(limits: &Limits, indices: TransformBufferIndices) -> u64 { fn get_offset_for(limits: &Limits, indices: TransformBufferIndices) -> u64 {
indices.transform_index as u64 * limits.min_uniform_buffer_offset_alignment as u64 indices.transform_index as u64 * limits.min_uniform_buffer_offset_alignment as u64
} }
/// Returns whether or not the transform buffers should be expanded
fn should_expand(&self) -> bool {
if let Some(( count, _, _ )) = self.buffer_bindgroups.last() {
count.clone() >= self.max_transform_count
} else {
true
}
}
} }
pub struct BasicRenderer { pub struct BasicRenderer {
@ -280,7 +299,8 @@ impl BasicRenderer {
// create create the transform buffer storage // create create the transform buffer storage
//let transforms = AVec::new(render_limits.min_uniform_buffer_offset_alignment as usize); //let transforms = AVec::new(render_limits.min_uniform_buffer_offset_alignment as usize);
let transform_buffers = TransformBuffers { let transform_buffers = TransformBuffers {
buffer_bindgroups: vec![( transform_buffer, transform_bind_group )], max_transform_count: (render_limits.max_uniform_buffer_binding_size / mem::size_of::<glam::Mat4>() as u32) as usize,
buffer_bindgroups: vec![( 0, transform_buffer, transform_bind_group )],
just_updated: HashMap::new(), just_updated: HashMap::new(),
not_updated: HashMap::new(), not_updated: HashMap::new(),
dead_indices: VecDeque::new(), dead_indices: VecDeque::new(),
@ -438,6 +458,42 @@ impl BasicRenderer {
transform_index: transform_indices transform_index: transform_indices
} }
} }
fn expand_transform_buffers(&mut self) -> TransformBufferIndices {
let buffers = &mut self.transform_buffers;
let transform_buffer = self.device.create_buffer(
&wgpu::BufferDescriptor {
label: Some(&format!("Transform Buffer {}", buffers.buffer_bindgroups.len())),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
size: self.render_limits.max_uniform_buffer_binding_size as u64,
mapped_at_creation: false,
}
);
let stride = self.render_limits.min_uniform_buffer_offset_alignment as usize + mem::size_of::<glam::Mat4>();
let transform_bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &self.transform_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(
wgpu::BufferBinding {
buffer: &transform_buffer,
offset: 0,
size: Some(NonZeroU64::new(stride as u64).unwrap())
}
)
}
],
label: Some("transform_bind_group"),
});
let indices = TransformBufferIndices { buffer_index: buffers.buffer_bindgroups.len(), transform_index: 0 };
buffers.buffer_bindgroups.push(( 0, transform_buffer, transform_bind_group ));
buffers.next_indices = indices;
indices
}
} }
impl Renderer for BasicRenderer { impl Renderer for BasicRenderer {
@ -448,15 +504,25 @@ impl Renderer for BasicRenderer {
let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform.transform, None); let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform.transform, None);
self.render_jobs.push_back(job); self.render_jobs.push_back(job);
if self.buffer_storage.get(&entity).is_none() { if self.buffer_storage.get(&entity).is_none() { // TODO: Delete dead entites from buffer_storage
// check if the transform buffers need to be expanded
if self.transform_buffers.should_expand() {
self.expand_transform_buffers();
}
// insert transform into buffers
let indices = self.transform_buffers.insert_entity(&self.queue, &self.render_limits, let indices = self.transform_buffers.insert_entity(&self.queue, &self.render_limits,
entity, transform.transform.calculate_mat4()); entity, transform.transform.calculate_mat4());
// create the mesh's buffers
let buffers = self.create_model_buffers(model, indices); let buffers = self.create_model_buffers(model, indices);
self.buffer_storage.insert(entity, buffers); self.buffer_storage.insert(entity, buffers);
} else { } else {
// update entity transforms
self.transform_buffers.update_entity(&self.queue, &self.render_limits, self.transform_buffers.update_entity(&self.queue, &self.render_limits,
entity, transform.transform.calculate_mat4()); entity, transform.transform.calculate_mat4());
// TODO: Update model buffers in storage
} }
} }
@ -512,7 +578,7 @@ impl Renderer for BasicRenderer {
// Get the bindgroup for job's transform and bind to it using an offset. // Get the bindgroup for job's transform and bind to it using an offset.
let transform_indices = buffers.transform_index; let transform_indices = buffers.transform_index;
let (_, bindgroup) = self.transform_buffers.buffer_bindgroups.get(transform_indices.buffer_index).unwrap(); let (_, _, bindgroup) = self.transform_buffers.buffer_bindgroups.get(transform_indices.buffer_index).unwrap();
let offset = TransformBuffers::get_offset_for(&self.render_limits, transform_indices); let offset = TransformBuffers::get_offset_for(&self.render_limits, transform_indices);
render_pass.set_bind_group(1, bindgroup, &[ offset as u32, ]); render_pass.set_bind_group(1, bindgroup, &[ offset as u32, ]);