Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add getters and From implementations to BufferSlice. #7148

Merged
merged 2 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading