Add write_buffer_range to RawBufferVec and BufferVec (#19775)

# Objective

- Sometimes you only want to write parts of a buffer to the gpu instead
of reuploading the entire buffer. For example when doing data streaming.
- wgpu already supports this and you can do it manually from the user
side but it would be nice if it was built in.

## Solution

- Add `write_buffer_range()` to `RawBufferVec` and `BufferVec` that will
only upload the data contained in the specified range

## Testing

- I did not test it in bevy, but this implementation is copied from
something I used and tested at work
This commit is contained in:
IceSentry 2025-06-23 20:33:41 -04:00 committed by GitHub
parent 7aed3e411d
commit 596eb48d8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -183,6 +183,31 @@ impl<T: NoUninit> RawBufferVec<T> {
}
}
/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
/// and the provided [`RenderQueue`].
///
/// Before queuing the write, a [`reserve`](RawBufferVec::reserve) operation
/// is executed.
///
/// This will only write the data contained in the given range. It is useful if you only want
/// to update a part of the buffer.
pub fn write_buffer_range(
&mut self,
device: &RenderDevice,
render_queue: &RenderQueue,
range: core::ops::Range<usize>,
) {
if self.values.is_empty() {
return;
}
self.reserve(self.values.len(), device);
if let Some(buffer) = &self.buffer {
// Cast only the bytes we need to write
let bytes: &[u8] = must_cast_slice(&self.values[range.start..range.end]);
render_queue.write_buffer(buffer, (range.start * self.item_size) as u64, bytes);
}
}
/// Reduces the length of the buffer.
pub fn truncate(&mut self, len: usize) {
self.values.truncate(len);
@ -389,6 +414,31 @@ where
queue.write_buffer(buffer, 0, &self.data);
}
/// Queues writing of data from system RAM to VRAM using the [`RenderDevice`]
/// and the provided [`RenderQueue`].
///
/// Before queuing the write, a [`reserve`](BufferVec::reserve) operation
/// is executed.
///
/// This will only write the data contained in the given range. It is useful if you only want
/// to update a part of the buffer.
pub fn write_buffer_range(
&mut self,
device: &RenderDevice,
render_queue: &RenderQueue,
range: core::ops::Range<usize>,
) {
if self.data.is_empty() {
return;
}
let item_size = u64::from(T::min_size()) as usize;
self.reserve(self.data.len() / item_size, device);
if let Some(buffer) = &self.buffer {
let bytes = &self.data[range.start..range.end];
render_queue.write_buffer(buffer, (range.start * item_size) as u64, bytes);
}
}
/// Reduces the length of the buffer.
pub fn truncate(&mut self, len: usize) {
self.data.truncate(u64::from(T::min_size()) as usize * len);