Skip to content

Commit

Permalink
Add getters and From implementations to BufferSlice. (gfx-rs#7148)
Browse files Browse the repository at this point in the history
* Add getters to `BufferSlice` to obtain its parts.

* Add conversions from `BufferSlice` to `BufferBinding` and `BindingResource`.
  • Loading branch information
kpreid authored and Marc Pabst committed Feb 19, 2025
1 parent bfc34d2 commit d78f8c6
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 16 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand Down
71 changes: 57 additions & 14 deletions tests/validation_tests/api/buffer.rs
Original file line number Diff line number Diff line change
@@ -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));
}
Expand All @@ -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 doesn’t 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());
}
}
45 changes: 44 additions & 1 deletion wgpu/src/api/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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, it’s 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.
Expand Down

0 comments on commit d78f8c6

Please sign in to comment.