Add getters and From implementations to BufferSlice. (#7148)

* Add getters to `BufferSlice` to obtain its parts.

* Add conversions from `BufferSlice` to `BufferBinding` and `BindingResource`.
This commit is contained in:
Kevin Reid 2025-02-17 02:06:13 -08:00 committed by GitHub
parent 16977225d1
commit 9da04c2b0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 104 additions and 16 deletions

View File

@ -121,7 +121,9 @@ By @cwfitzgerald in [#7030](https://github.com/gfx-rs/wgpu/pull/7030).
By @kpreid in [#7063](https://github.com/gfx-rs/wgpu/pull/7063).
- Added `Buffer` methods corresponding to `BufferSlice` methods, so you can skip creating a `BufferSlice` when it offers no benefit, and `BufferSlice::slice()` for sub-slicing a slice. By @kpreid in [#7123](https://github.com/gfx-rs/wgpu/pull/7123).
- Add `Buffer` methods corresponding to `BufferSlice` methods, so you can skip creating a `BufferSlice` when it offers no benefit, and `BufferSlice::slice()` for sub-slicing a slice. By @kpreid in [#7123](https://github.com/gfx-rs/wgpu/pull/7123).
- Add `BufferSlice::buffer()`, `BufferSlice::offset()` and `BufferSlice::size()`. By @kpreid in [#7148](https://github.com/gfx-rs/wgpu/pull/7148).
- Add `impl From<BufferSlice> for BufferBinding` and `impl From<BufferSlice> for BindingResource`, allowing `BufferSlice`s to be easily used in creating bind groups. By @kpreid in [#7148](https://github.com/gfx-rs/wgpu/pull/7148).
- Add `util::StagingBelt::allocate()` so the staging belt can be used to write textures. By @kpreid in [#6900](https://github.com/gfx-rs/wgpu/pull/6900).
- Added `CommandEncoder::transition_resources()` for native API interop, and allowing users to slightly optimize barriers. By @JMS55 in [#6678](https://github.com/gfx-rs/wgpu/pull/6678).

View File

@ -1,16 +1,21 @@
//! Tests of [`wgpu::Buffer`] and related.
use core::num::NonZero;
mod buffer_slice {
use super::*;
const ARBITRARY_DESC: &wgpu::BufferDescriptor = &wgpu::BufferDescriptor {
label: None,
size: 100,
usage: wgpu::BufferUsages::VERTEX,
mapped_at_creation: false,
};
#[test]
fn reslice_success() {
let (device, _queue) = crate::request_noop_device();
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: 100,
usage: wgpu::BufferUsages::VERTEX,
mapped_at_creation: false,
});
let buffer = device.create_buffer(ARBITRARY_DESC);
assert_eq!(buffer.slice(10..90).slice(10..70), buffer.slice(20..80));
}
@ -19,14 +24,52 @@ mod buffer_slice {
#[should_panic = "slice offset 10 size 80 is out of range for buffer of size 80"]
fn reslice_out_of_bounds() {
let (device, _queue) = crate::request_noop_device();
let buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: None,
size: 100,
usage: wgpu::BufferUsages::VERTEX,
mapped_at_creation: false,
});
let buffer = device.create_buffer(ARBITRARY_DESC);
buffer.slice(10..90).slice(10..90);
}
#[test]
fn getters() {
let (device, _queue) = crate::request_noop_device();
let buffer = device.create_buffer(ARBITRARY_DESC);
let slice_with_size = buffer.slice(10..90);
assert_eq!(
(
slice_with_size.buffer(),
slice_with_size.offset(),
slice_with_size.size()
),
(&buffer, 10, NonZero::new(80).unwrap())
);
let slice_without_size = buffer.slice(10..);
assert_eq!(
(
slice_without_size.buffer(),
slice_without_size.offset(),
slice_without_size.size()
),
(&buffer, 10, NonZero::new(90).unwrap())
);
}
#[test]
fn into_buffer_binding() {
let (device, _queue) = crate::request_noop_device();
let buffer = device.create_buffer(ARBITRARY_DESC);
// BindingResource doesnt implement PartialEq, so use matching
let wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer: b,
offset: 50,
size: Some(size),
}) = wgpu::BindingResource::from(buffer.slice(50..80))
else {
panic!("didn't match")
};
assert_eq!(b, &buffer);
assert_eq!(size, NonZero::new(30).unwrap());
}
}

View File

@ -360,7 +360,8 @@ impl Buffer {
///
/// You can pass buffer slices to methods like [`RenderPass::set_vertex_buffer`]
/// and [`RenderPass::set_index_buffer`] to indicate which portion of the buffer
/// a draw call should consult.
/// a draw call should consult. You can also convert it to a [`BufferBinding`]
/// with `.into()`.
///
/// To access the slice's contents on the CPU, you must first [map] the buffer,
/// and then call [`BufferSlice::get_mapped_range`] or
@ -506,6 +507,48 @@ impl<'a> BufferSlice<'a> {
readable: self.buffer.usage.contains(BufferUsages::MAP_READ),
}
}
/// Returns the buffer this is a slice of.
///
/// You should usually not need to call this, and if you received the buffer from code you
/// do not control, you should refrain from accessing the buffer outside the bounds of the
/// slice. Nevertheless, its possible to get this access, so this method makes it simple.
pub fn buffer(&self) -> &'a Buffer {
self.buffer
}
/// Returns the offset in [`Self::buffer()`] this slice starts at.
pub fn offset(&self) -> BufferAddress {
self.offset
}
/// Returns the size of this slice.
pub fn size(&self) -> BufferSize {
self.size.unwrap_or_else(|| {
(|| BufferSize::new(self.buffer.size().checked_sub(self.offset)?))()
.expect("can't happen: slice has incorrect size for its buffer")
})
}
}
impl<'a> From<BufferSlice<'a>> for crate::BufferBinding<'a> {
/// Convert a [`BufferSlice`] to an equivalent [`BufferBinding`],
/// provided that it will be used without a dynamic offset.
fn from(value: BufferSlice<'a>) -> Self {
BufferBinding {
buffer: value.buffer,
offset: value.offset,
size: value.size,
}
}
}
impl<'a> From<BufferSlice<'a>> for crate::BindingResource<'a> {
/// Convert a [`BufferSlice`] to an equivalent [`BindingResource::Buffer`],
/// provided that it will be used without a dynamic offset.
fn from(value: BufferSlice<'a>) -> Self {
crate::BindingResource::Buffer(crate::BufferBinding::from(value))
}
}
/// The mapped portion of a buffer, if any, and its outstanding views.