Only create changed buffer if it already exists (#13242)

# Objective

- `DynamicUniformBuffer` tries to create a buffer as soon as the changed
flag is set to true. This doesn't work correctly when the buffer wasn't
already created. This currently creates a crash because it's trying to
create a buffer of size 0 if the flag is set but there's no buffer yet.

## Solution

- Don't create a changed buffer until there's data that needs to be
written to a buffer.

## Testing

- run `cargo run --example scene_viewer` and see that it doesn't crash
anymore

Fixes #13235
This commit is contained in:
IceSentry 2024-05-05 18:16:11 -04:00 committed by GitHub
parent 088960f597
commit a22ecede49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 10 additions and 9 deletions

View file

@ -43,7 +43,7 @@ pub struct RawBufferVec<T: NoUninit> {
item_size: usize, item_size: usize,
buffer_usage: BufferUsages, buffer_usage: BufferUsages,
label: Option<String>, label: Option<String>,
label_changed: bool, changed: bool,
} }
impl<T: NoUninit> RawBufferVec<T> { impl<T: NoUninit> RawBufferVec<T> {
@ -55,7 +55,7 @@ impl<T: NoUninit> RawBufferVec<T> {
item_size: std::mem::size_of::<T>(), item_size: std::mem::size_of::<T>(),
buffer_usage, buffer_usage,
label: None, label: None,
label_changed: false, changed: false,
} }
} }
@ -93,7 +93,7 @@ impl<T: NoUninit> RawBufferVec<T> {
let label = label.map(str::to_string); let label = label.map(str::to_string);
if label != self.label { if label != self.label {
self.label_changed = true; self.changed = true;
} }
self.label = label; self.label = label;
@ -115,16 +115,16 @@ impl<T: NoUninit> RawBufferVec<T> {
/// the `RawBufferVec` was created, the buffer on the [`RenderDevice`] /// the `RawBufferVec` was created, the buffer on the [`RenderDevice`]
/// is marked as [`BufferUsages::COPY_DST`](BufferUsages). /// is marked as [`BufferUsages::COPY_DST`](BufferUsages).
pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) { pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
if capacity > self.capacity || self.label_changed { let size = self.item_size * capacity;
if capacity > self.capacity || (self.changed && size > 0) {
self.capacity = capacity; self.capacity = capacity;
let size = self.item_size * capacity;
self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor { self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
label: self.label.as_deref(), label: self.label.as_deref(),
size: size as BufferAddress, size: size as BufferAddress,
usage: BufferUsages::COPY_DST | self.buffer_usage, usage: BufferUsages::COPY_DST | self.buffer_usage,
mapped_at_creation: false, mapped_at_creation: false,
})); }));
self.label_changed = false; self.changed = false;
} }
} }

View file

@ -250,7 +250,7 @@ impl<T: ShaderType + WriteInto> DynamicStorageBuffer<T> {
let capacity = self.buffer.as_deref().map(wgpu::Buffer::size).unwrap_or(0); let capacity = self.buffer.as_deref().map(wgpu::Buffer::size).unwrap_or(0);
let size = self.scratch.as_ref().len() as u64; let size = self.scratch.as_ref().len() as u64;
if capacity < size || self.changed { if capacity < size || (self.changed && size > 0) {
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
label: self.label.as_deref(), label: self.label.as_deref(),
usage: self.buffer_usage, usage: self.buffer_usage,

View file

@ -295,7 +295,7 @@ impl<T: ShaderType + WriteInto> DynamicUniformBuffer<T> {
.checked_mul(max_count as u64) .checked_mul(max_count as u64)
.unwrap(); .unwrap();
if capacity < size || self.changed { if capacity < size || (self.changed && size > 0) {
let buffer = device.create_buffer(&BufferDescriptor { let buffer = device.create_buffer(&BufferDescriptor {
label: self.label.as_deref(), label: self.label.as_deref(),
usage: self.buffer_usage, usage: self.buffer_usage,
@ -336,7 +336,7 @@ impl<T: ShaderType + WriteInto> DynamicUniformBuffer<T> {
let capacity = self.buffer.as_deref().map(wgpu::Buffer::size).unwrap_or(0); let capacity = self.buffer.as_deref().map(wgpu::Buffer::size).unwrap_or(0);
let size = self.scratch.as_ref().len() as u64; let size = self.scratch.as_ref().len() as u64;
if capacity < size || self.changed { if capacity < size || (self.changed && size > 0) {
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
label: self.label.as_deref(), label: self.label.as_deref(),
usage: self.buffer_usage, usage: self.buffer_usage,

View file

@ -429,6 +429,7 @@ pub struct ViewUniforms {
impl FromWorld for ViewUniforms { impl FromWorld for ViewUniforms {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let mut uniforms = DynamicUniformBuffer::default(); let mut uniforms = DynamicUniformBuffer::default();
uniforms.set_label(Some("view_uniforms_buffer"));
let render_device = world.resource::<RenderDevice>(); let render_device = world.resource::<RenderDevice>();
if render_device.limits().max_storage_buffers_per_shader_stage > 0 { if render_device.limits().max_storage_buffers_per_shader_stage > 0 {