diff --git a/src/render/renderer.rs b/src/render/renderer.rs index ecfaf81..5994977 100755 --- a/src/render/renderer.rs +++ b/src/render/renderer.rs @@ -57,12 +57,16 @@ struct TransformBufferIndices { } struct TransformBuffers { + //transform_layout: wgpu::BindGroupLayout, /// A vector storing the EntityId and just_updated: HashMap, not_updated: HashMap, dead_indices: VecDeque, 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 { @@ -72,25 +76,31 @@ impl TransformBuffers { .expect("Use 'insert_entity' for new entities"); 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)); } /// 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 { // get a dead index, or create a new one - let indices = if let Some(index) = self.dead_indices.pop_front() { - index + let (indices, buffer) = if let Some(index) = self.dead_indices.pop_front() { + let (_, buffer, _) = self.buffer_bindgroups.get(index.buffer_index).unwrap(); + (index, &*buffer) } else { - // TODO: Create new buffer if this one is full 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; - 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)); self.just_updated.insert(entity, indices); @@ -112,6 +122,15 @@ impl TransformBuffers { fn get_offset_for(limits: &Limits, indices: TransformBufferIndices) -> 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 { @@ -280,7 +299,8 @@ impl BasicRenderer { // create create the transform buffer storage //let transforms = AVec::new(render_limits.min_uniform_buffer_offset_alignment as usize); 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::() as u32) as usize, + buffer_bindgroups: vec![( 0, transform_buffer, transform_bind_group )], just_updated: HashMap::new(), not_updated: HashMap::new(), dead_indices: VecDeque::new(), @@ -438,6 +458,42 @@ impl BasicRenderer { 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::(); + 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 { @@ -448,15 +504,25 @@ impl Renderer for BasicRenderer { let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform.transform, None); 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, entity, transform.transform.calculate_mat4()); + // create the mesh's buffers let buffers = self.create_model_buffers(model, indices); self.buffer_storage.insert(entity, buffers); } else { + // update entity transforms self.transform_buffers.update_entity(&self.queue, &self.render_limits, 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. 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); render_pass.set_bind_group(1, bindgroup, &[ offset as u32, ]);