From c4270332e8046af6f40e99f0c9f3d2d1bc5cdc77 Mon Sep 17 00:00:00 2001 From: StepanTheGreat <117771383+StepanTheGreat@users.noreply.github.com> Date: Sun, 21 Sep 2025 21:30:38 +0200 Subject: [PATCH] Allow updating a part of a buffer --- src/graphics.rs | 10 +++++++++- src/graphics/gl.rs | 14 ++++++++++---- src/graphics/metal.rs | 11 ++++++++--- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/graphics.rs b/src/graphics.rs index dbdfffc6..62a80a7e 100644 --- a/src/graphics.rs +++ b/src/graphics.rs @@ -1280,7 +1280,15 @@ pub trait RenderingBackend { /// ``` fn new_buffer(&mut self, type_: BufferType, usage: BufferUsage, data: BufferSource) -> BufferId; - fn buffer_update(&mut self, buffer: BufferId, data: BufferSource); + + fn buffer_update(&mut self, buffer: BufferId, data: BufferSource) { + self.buffer_update_part(buffer, 0, data); + } + + /// Update only a part of a buffer. + /// + /// The offset is given in bytes + fn buffer_update_part(&mut self, buffer: BufferId, offset: usize, data: BufferSource); /// Size of buffer in bytes. /// For 1 element, u16 buffer this will return 2. diff --git a/src/graphics/gl.rs b/src/graphics/gl.rs index 9c8c9844..04959847 100644 --- a/src/graphics/gl.rs +++ b/src/graphics/gl.rs @@ -1383,11 +1383,12 @@ impl RenderingBackend for GlContext { BufferId(self.buffers.add(buffer)) } - fn buffer_update(&mut self, buffer: BufferId, data: BufferSource) { + fn buffer_update_part(&mut self, buffer: BufferId, offset: usize, data: BufferSource) { let data = match data { BufferSource::Slice(data) => data, - _ => panic!("buffer_update expects BufferSource::slice"), + _ => panic!("buffer_update_part expects BufferSource::slice"), }; + debug_assert!(data.is_slice); let buffer = &self.buffers[buffer.0]; @@ -1398,13 +1399,18 @@ impl RenderingBackend for GlContext { let size = data.size; - assert!(size <= buffer.size); + // Make sure that the offset isn't larger than the buffer's size itself + assert!(offset < buffer.size); + + // And that our data actually fits into the buffer with this offset + assert!(size <= buffer.size-offset); let gl_target = gl_buffer_target(&buffer.buffer_type); self.cache.store_buffer_binding(gl_target); self.cache .bind_buffer(gl_target, buffer.gl_buf, buffer.index_type); - unsafe { glBufferSubData(gl_target, 0, size as _, data.ptr as _) }; + + unsafe { glBufferSubData(gl_target, offset as _, size as _, data.ptr as _) }; self.cache.restore_buffer_binding(gl_target); } diff --git a/src/graphics/metal.rs b/src/graphics/metal.rs index 39004579..9f58ed89 100644 --- a/src/graphics/metal.rs +++ b/src/graphics/metal.rs @@ -634,12 +634,17 @@ impl RenderingBackend for MetalContext { BufferId(self.buffers.len() - 1) } - fn buffer_update(&mut self, buffer: BufferId, data: BufferSource) { + fn buffer_update_part(&mut self, buffer: BufferId, offset: usize, data: BufferSource) { let data = match data { BufferSource::Slice(data) => data, - _ => panic!("buffer_update expects BufferSource::slice"), + _ => panic!("buffer_update_part expects BufferSource::slice"), }; let buffer = &mut self.buffers[buffer.0]; + + // Make sure that the offset isn't larger than the buffer's size itself + assert!(offset < buffer.size); + + // And that our data actually fits into the buffer with this offset assert!(data.size <= buffer.size); unsafe { @@ -647,7 +652,7 @@ impl RenderingBackend for MetalContext { std::ptr::copy(data.ptr, dest, data.size); #[cfg(target_os = "macos")] - msg_send_![buffer.raw[buffer.next_value], didModifyRange:NSRange::new(0, data.size as u64)]; + msg_send_![buffer.raw[buffer.next_value], didModifyRange:NSRange::new(offset as u64, data.size as u64)]; } buffer.value = buffer.next_value; }