add a debug label to storage buffers (#5341)

# Objective

- Expose the wgpu debug label on storage buffer types.

## Solution

🐄

- Add an optional cow static string and pass that to the label field of create_buffer_with_data
- This pattern is already used by Bevy for debug tags on bind group and layout descriptors.

---

Example Usage:

A buffer is given a label using the label function. Alternatively a buffer may be labeled when it is created if the default() convention is not used.
![ray_buf](https://user-images.githubusercontent.com/106117615/179366494-f037bd8c-4d65-4b37-8135-01ac0c5c8ee0.png)

Here is the buffer appearing with the correct name in RenderDoc. Previously the buffer would have an anonymous name such as "Buffer223":
![buffer_named](https://user-images.githubusercontent.com/106117615/179366552-faeb6c27-5373-4e4e-a0e2-c04446f95a4b.png)



Co-authored-by: rebelroad-reinhart <reinhart@rebelroad.gg>
This commit is contained in:
Brandon Reinhart 2022-07-28 20:37:49 +00:00
parent 4e2600b788
commit 2d2ea337dd
3 changed files with 115 additions and 17 deletions

View File

@ -33,6 +33,8 @@ pub struct BufferVec<T: Pod> {
capacity: usize, capacity: usize,
item_size: usize, item_size: usize,
buffer_usage: BufferUsages, buffer_usage: BufferUsages,
label: Option<String>,
label_changed: bool,
} }
impl<T: Pod> BufferVec<T> { impl<T: Pod> BufferVec<T> {
@ -43,6 +45,8 @@ impl<T: Pod> BufferVec<T> {
capacity: 0, capacity: 0,
item_size: std::mem::size_of::<T>(), item_size: std::mem::size_of::<T>(),
buffer_usage, buffer_usage,
label: None,
label_changed: false,
} }
} }
@ -72,6 +76,20 @@ impl<T: Pod> BufferVec<T> {
index index
} }
pub fn set_label(&mut self, label: Option<&str>) {
let label = label.map(str::to_string);
if label != self.label {
self.label_changed = true;
}
self.label = label;
}
pub fn get_label(&self) -> Option<&str> {
self.label.as_deref()
}
/// Creates a [`Buffer`](crate::render_resource::Buffer) on the [`RenderDevice`](crate::renderer::RenderDevice) with size /// Creates a [`Buffer`](crate::render_resource::Buffer) on the [`RenderDevice`](crate::renderer::RenderDevice) with size
/// at least `std::mem::size_of::<T>() * capacity`, unless a such a buffer already exists. /// at least `std::mem::size_of::<T>() * capacity`, unless a such a buffer already exists.
/// ///
@ -84,15 +102,16 @@ impl<T: Pod> BufferVec<T> {
/// the `BufferVec` was created, the buffer on the [`RenderDevice`](crate::renderer::RenderDevice) /// the `BufferVec` was created, the buffer on the [`RenderDevice`](crate::renderer::RenderDevice)
/// is marked as [`BufferUsages::COPY_DST`](crate::render_resource::BufferUsages). /// is marked as [`BufferUsages::COPY_DST`](crate::render_resource::BufferUsages).
pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) { pub fn reserve(&mut self, capacity: usize, device: &RenderDevice) {
if capacity > self.capacity { if capacity > self.capacity || self.label_changed {
self.capacity = capacity; self.capacity = capacity;
let size = self.item_size * capacity; let size = self.item_size * capacity;
self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor { self.buffer = Some(device.create_buffer(&wgpu::BufferDescriptor {
label: None, label: self.label.as_deref(),
size: size as wgpu::BufferAddress, size: size as wgpu::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;
} }
} }

View File

@ -32,6 +32,8 @@ pub struct StorageBuffer<T: ShaderType> {
scratch: StorageBufferWrapper<Vec<u8>>, scratch: StorageBufferWrapper<Vec<u8>>,
buffer: Option<Buffer>, buffer: Option<Buffer>,
capacity: usize, capacity: usize,
label: Option<String>,
label_changed: bool,
} }
impl<T: ShaderType> From<T> for StorageBuffer<T> { impl<T: ShaderType> From<T> for StorageBuffer<T> {
@ -41,6 +43,8 @@ impl<T: ShaderType> From<T> for StorageBuffer<T> {
scratch: StorageBufferWrapper::new(Vec::new()), scratch: StorageBufferWrapper::new(Vec::new()),
buffer: None, buffer: None,
capacity: 0, capacity: 0,
label: None,
label_changed: false,
} }
} }
} }
@ -52,6 +56,8 @@ impl<T: ShaderType + Default> Default for StorageBuffer<T> {
scratch: StorageBufferWrapper::new(Vec::new()), scratch: StorageBufferWrapper::new(Vec::new()),
buffer: None, buffer: None,
capacity: 0, capacity: 0,
label: None,
label_changed: false,
} }
} }
} }
@ -81,6 +87,20 @@ impl<T: ShaderType + WriteInto> StorageBuffer<T> {
&mut self.value &mut self.value
} }
pub fn set_label(&mut self, label: Option<&str>) {
let label = label.map(str::to_string);
if label != self.label {
self.label_changed = true;
}
self.label = label;
}
pub fn get_label(&self) -> Option<&str> {
self.label.as_deref()
}
/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`](crate::renderer::RenderDevice) /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`](crate::renderer::RenderDevice)
/// and the provided [`RenderQueue`](crate::renderer::RenderQueue). /// and the provided [`RenderQueue`](crate::renderer::RenderQueue).
/// ///
@ -91,13 +111,14 @@ impl<T: ShaderType + WriteInto> StorageBuffer<T> {
let size = self.scratch.as_ref().len(); let size = self.scratch.as_ref().len();
if self.capacity < size { if self.capacity < size || self.label_changed {
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
label: None, label: self.label.as_deref(),
usage: BufferUsages::COPY_DST | BufferUsages::STORAGE, usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
contents: self.scratch.as_ref(), contents: self.scratch.as_ref(),
})); }));
self.capacity = size; self.capacity = size;
self.label_changed = false;
} else if let Some(buffer) = &self.buffer { } else if let Some(buffer) = &self.buffer {
queue.write_buffer(buffer, 0, self.scratch.as_ref()); queue.write_buffer(buffer, 0, self.scratch.as_ref());
} }
@ -130,6 +151,8 @@ pub struct DynamicStorageBuffer<T: ShaderType> {
scratch: DynamicStorageBufferWrapper<Vec<u8>>, scratch: DynamicStorageBufferWrapper<Vec<u8>>,
buffer: Option<Buffer>, buffer: Option<Buffer>,
capacity: usize, capacity: usize,
label: Option<String>,
label_changed: bool,
} }
impl<T: ShaderType> Default for DynamicStorageBuffer<T> { impl<T: ShaderType> Default for DynamicStorageBuffer<T> {
@ -139,6 +162,8 @@ impl<T: ShaderType> Default for DynamicStorageBuffer<T> {
scratch: DynamicStorageBufferWrapper::new(Vec::new()), scratch: DynamicStorageBufferWrapper::new(Vec::new()),
buffer: None, buffer: None,
capacity: 0, capacity: 0,
label: None,
label_changed: false,
} }
} }
} }
@ -175,17 +200,32 @@ impl<T: ShaderType + WriteInto> DynamicStorageBuffer<T> {
offset offset
} }
pub fn set_label(&mut self, label: Option<&str>) {
let label = label.map(str::to_string);
if label != self.label {
self.label_changed = true;
}
self.label = label;
}
pub fn get_label(&self) -> Option<&str> {
self.label.as_deref()
}
#[inline] #[inline]
pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) { pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
let size = self.scratch.as_ref().len(); let size = self.scratch.as_ref().len();
if self.capacity < size { if self.capacity < size || self.label_changed {
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
label: None, label: self.label.as_deref(),
usage: BufferUsages::COPY_DST | BufferUsages::STORAGE, usage: BufferUsages::COPY_DST | BufferUsages::STORAGE,
contents: self.scratch.as_ref(), contents: self.scratch.as_ref(),
})); }));
self.capacity = size; self.capacity = size;
self.label_changed = false;
} else if let Some(buffer) = &self.buffer { } else if let Some(buffer) = &self.buffer {
queue.write_buffer(buffer, 0, self.scratch.as_ref()); queue.write_buffer(buffer, 0, self.scratch.as_ref());
} }

View File

@ -31,6 +31,8 @@ pub struct UniformBuffer<T: ShaderType> {
value: T, value: T,
scratch: UniformBufferWrapper<Vec<u8>>, scratch: UniformBufferWrapper<Vec<u8>>,
buffer: Option<Buffer>, buffer: Option<Buffer>,
label: Option<String>,
label_changed: bool,
} }
impl<T: ShaderType> From<T> for UniformBuffer<T> { impl<T: ShaderType> From<T> for UniformBuffer<T> {
@ -39,6 +41,8 @@ impl<T: ShaderType> From<T> for UniformBuffer<T> {
value, value,
scratch: UniformBufferWrapper::new(Vec::new()), scratch: UniformBufferWrapper::new(Vec::new()),
buffer: None, buffer: None,
label: None,
label_changed: false,
} }
} }
} }
@ -49,6 +53,8 @@ impl<T: ShaderType + Default> Default for UniformBuffer<T> {
value: T::default(), value: T::default(),
scratch: UniformBufferWrapper::new(Vec::new()), scratch: UniformBufferWrapper::new(Vec::new()),
buffer: None, buffer: None,
label: None,
label_changed: false,
} }
} }
} }
@ -79,6 +85,20 @@ impl<T: ShaderType + WriteInto> UniformBuffer<T> {
&mut self.value &mut self.value
} }
pub fn set_label(&mut self, label: Option<&str>) {
let label = label.map(str::to_string);
if label != self.label {
self.label_changed = true;
}
self.label = label;
}
pub fn get_label(&self) -> Option<&str> {
self.label.as_deref()
}
/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`](crate::renderer::RenderDevice) /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`](crate::renderer::RenderDevice)
/// and the provided [`RenderQueue`](crate::renderer::RenderQueue), if a GPU-side backing buffer already exists. /// and the provided [`RenderQueue`](crate::renderer::RenderQueue), if a GPU-side backing buffer already exists.
/// ///
@ -87,15 +107,15 @@ impl<T: ShaderType + WriteInto> UniformBuffer<T> {
pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) { pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
self.scratch.write(&self.value).unwrap(); self.scratch.write(&self.value).unwrap();
match &self.buffer { if self.label_changed || self.buffer.is_none() {
Some(buffer) => queue.write_buffer(buffer, 0, self.scratch.as_ref()), self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
None => { label: self.label.as_deref(),
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM,
label: None, contents: self.scratch.as_ref(),
usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM, }));
contents: self.scratch.as_ref(), self.label_changed = false;
})); } else if let Some(buffer) = &self.buffer {
} queue.write_buffer(buffer, 0, self.scratch.as_ref());
} }
} }
} }
@ -124,6 +144,8 @@ pub struct DynamicUniformBuffer<T: ShaderType> {
scratch: DynamicUniformBufferWrapper<Vec<u8>>, scratch: DynamicUniformBufferWrapper<Vec<u8>>,
buffer: Option<Buffer>, buffer: Option<Buffer>,
capacity: usize, capacity: usize,
label: Option<String>,
label_changed: bool,
} }
impl<T: ShaderType> Default for DynamicUniformBuffer<T> { impl<T: ShaderType> Default for DynamicUniformBuffer<T> {
@ -133,6 +155,8 @@ impl<T: ShaderType> Default for DynamicUniformBuffer<T> {
scratch: DynamicUniformBufferWrapper::new(Vec::new()), scratch: DynamicUniformBufferWrapper::new(Vec::new()),
buffer: None, buffer: None,
capacity: 0, capacity: 0,
label: None,
label_changed: false,
} }
} }
} }
@ -170,6 +194,20 @@ impl<T: ShaderType + WriteInto> DynamicUniformBuffer<T> {
offset offset
} }
pub fn set_label(&mut self, label: Option<&str>) {
let label = label.map(str::to_string);
if label != self.label {
self.label_changed = true;
}
self.label = label;
}
pub fn get_label(&self) -> Option<&str> {
self.label.as_deref()
}
/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`](crate::renderer::RenderDevice) /// Queues writing of data from system RAM to VRAM using the [`RenderDevice`](crate::renderer::RenderDevice)
/// and the provided [`RenderQueue`](crate::renderer::RenderQueue). /// and the provided [`RenderQueue`](crate::renderer::RenderQueue).
/// ///
@ -179,13 +217,14 @@ impl<T: ShaderType + WriteInto> DynamicUniformBuffer<T> {
pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) { pub fn write_buffer(&mut self, device: &RenderDevice, queue: &RenderQueue) {
let size = self.scratch.as_ref().len(); let size = self.scratch.as_ref().len();
if self.capacity < size { if self.capacity < size || self.label_changed {
self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor { self.buffer = Some(device.create_buffer_with_data(&BufferInitDescriptor {
label: None, label: self.label.as_deref(),
usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM, usage: BufferUsages::COPY_DST | BufferUsages::UNIFORM,
contents: self.scratch.as_ref(), contents: self.scratch.as_ref(),
})); }));
self.capacity = size; self.capacity = size;
self.label_changed = false;
} else if let Some(buffer) = &self.buffer { } else if let Some(buffer) = &self.buffer {
queue.write_buffer(buffer, 0, self.scratch.as_ref()); queue.write_buffer(buffer, 0, self.scratch.as_ref());
} }