pub struct Buffer {
pub(crate) context: Arc<dyn DynContext>,
pub(crate) id: ObjectId,
pub(crate) data: Box<dyn Any + Sync + Send>,
pub(crate) map_context: Mutex<RawMutex, MapContext>,
pub(crate) size: u64,
pub(crate) usage: BufferUsages,
}
Expand description
Handle to a GPU-accessible buffer.
Created with Device::create_buffer
or
DeviceExt::create_buffer_init
.
Corresponds to WebGPU GPUBuffer
.
A Buffer
’s bytes have “interior mutability”: functions like
Queue::write_buffer
or mapping a buffer for writing only require a
&Buffer
, not a &mut Buffer
, even though they modify its contents. wgpu
prevents simultaneous reads and writes of buffer contents using run-time
checks.
§Mapping buffers
If a Buffer
is created with the appropriate usage
, it can be mapped:
you can make its contents accessible to the CPU as an ordinary &[u8]
or
&mut [u8]
slice of bytes. Buffers created with the
mapped_at_creation
flag set are also mapped initially.
Depending on the hardware, the buffer could be memory shared between CPU and GPU, so that the CPU has direct access to the same bytes the GPU will consult; or it may be ordinary CPU memory, whose contents the system must copy to/from the GPU as needed. This crate’s API is designed to work the same way in either case: at any given time, a buffer is either mapped and available to the CPU, or unmapped and ready for use by the GPU, but never both. This makes it impossible for either side to observe changes by the other immediately, and any necessary transfers can be carried out when the buffer transitions from one state to the other.
There are two ways to map a buffer:
-
If [
BufferDescriptor::mapped_at_creation
] istrue
, then the entire buffer is mapped when it is created. This is the easiest way to initialize a new buffer. You can setmapped_at_creation
on any kind of buffer, regardless of itsusage
flags. -
If the buffer’s
usage
includes theMAP_READ
orMAP_WRITE
flags, then you can callbuffer.slice(range).map_async(mode, callback)
to map the portion ofbuffer
given byrange
. This waits for the GPU to finish using the buffer, and invokescallback
as soon as the buffer is safe for the CPU to access.
Once a buffer is mapped:
-
You can call
buffer.slice(range).get_mapped_range()
to obtain aBufferView
, which dereferences to a&[u8]
that you can use to read the buffer’s contents. -
Or, you can call
buffer.slice(range).get_mapped_range_mut()
to obtain aBufferViewMut
, which dereferences to a&mut [u8]
that you can use to read and write the buffer’s contents.
The given range
must fall within the mapped portion of the buffer. If you
attempt to access overlapping ranges, even for shared access only, these
methods panic.
While a buffer is mapped, you may not submit any commands to the GPU that access it. You may record command buffers that use the buffer, but if you submit them while the buffer is mapped, submission will panic.
When you are done using the buffer on the CPU, you must call
Buffer::unmap
to make it available for use by the GPU again. All
BufferView
and BufferViewMut
views referring to the buffer must be
dropped before you unmap it; otherwise, Buffer::unmap
will panic.
§Example
If buffer
was created with BufferUsages::MAP_WRITE
, we could fill it
with f32
values like this:
let buffer = std::sync::Arc::new(buffer);
let capturable = buffer.clone();
buffer.slice(..).map_async(wgpu::MapMode::Write, move |result| {
if result.is_ok() {
let mut view = capturable.slice(..).get_mapped_range_mut();
let floats: &mut [f32] = bytemuck::cast_slice_mut(&mut view);
floats.fill(42.0);
drop(view);
capturable.unmap();
}
});
This code takes the following steps:
-
First, it moves
buffer
into anArc
, and makes a clone for capture by the callback passed tomap_async
. Since amap_async
callback may be invoked from another thread, interaction between the callback and the thread callingmap_async
generally requires some sort of shared heap data like this. In real code, theArc
would probably own some larger structure that itself ownsbuffer
. -
Then, it calls
Buffer::slice
to make aBufferSlice
referring to the buffer’s entire contents. -
Next, it calls
BufferSlice::map_async
to request that the bytes to which the slice refers be made accessible to the CPU (“mapped”). This may entail waiting for previously enqueued operations onbuffer
to finish. Althoughmap_async
itself always returns immediately, it saves the callback function to be invoked later. -
When some later call to
Device::poll
orInstance::poll_all
(not shown in this example) determines that the buffer is mapped and ready for the CPU to use, it invokes the callback function. -
The callback function calls
Buffer::slice
and thenBufferSlice::get_mapped_range_mut
to obtain aBufferViewMut
, which dereferences to a&mut [u8]
slice referring to the buffer’s bytes. -
It then uses the
bytemuck
crate to turn the&mut [u8]
into a&mut [f32]
, and calls the slicefill
method to fill the buffer with a useful value. -
Finally, the callback drops the view and calls
Buffer::unmap
to unmap the buffer. In real code, the callback would also need to do some sort of synchronization to let the rest of the program know that it has completed its work.
If using map_async
directly is awkward, you may find it more convenient to
use Queue::write_buffer
and util::DownloadBuffer::read_buffer
.
However, those each have their own tradeoffs; the asynchronous nature of GPU
execution makes it hard to avoid friction altogether.
§Mapping buffers on the web
When compiled to WebAssembly and running in a browser content process,
wgpu
implements its API in terms of the browser’s WebGPU implementation.
In this context, wgpu
is further isolated from the GPU:
-
Depending on the browser’s WebGPU implementation, mapping and unmapping buffers probably entails copies between WebAssembly linear memory and the graphics driver’s buffers.
-
All modern web browsers isolate web content in its own sandboxed process, which can only interact with the GPU via interprocess communication (IPC). Although most browsers’ IPC systems use shared memory for large data transfers, there will still probably need to be copies into and out of the shared memory buffers.
All of these copies contribute to the cost of buffer mapping in this configuration.
Fields§
§context: Arc<dyn DynContext>
§id: ObjectId
§data: Box<dyn Any + Sync + Send>
§map_context: Mutex<RawMutex, MapContext>
§size: u64
§usage: BufferUsages
Implementations§
§impl Buffer
impl Buffer
pub fn as_entire_binding(&self) -> BindingResource<'_>
pub fn as_entire_binding(&self) -> BindingResource<'_>
Return the binding view of the entire buffer.
pub fn as_entire_buffer_binding(&self) -> BufferBinding<'_>
pub fn as_entire_buffer_binding(&self) -> BufferBinding<'_>
Return the binding view of the entire buffer.
pub unsafe fn as_hal<A, F, R>(&self, hal_buffer_callback: F) -> R
pub unsafe fn as_hal<A, F, R>(&self, hal_buffer_callback: F) -> R
Returns the inner hal Buffer using a callback. The hal buffer will be None
if the
backend type argument does not match with this wgpu Buffer
§Safety
- The raw handle obtained from the hal Buffer must not be manually destroyed
pub fn slice<S>(&self, bounds: S) -> BufferSlice<'_>where
S: RangeBounds<u64>,
pub fn slice<S>(&self, bounds: S) -> BufferSlice<'_>where
S: RangeBounds<u64>,
Return a slice of a Buffer
’s bytes.
Return a BufferSlice
referring to the portion of self
’s contents
indicated by bounds
. Regardless of what sort of data self
stores,
bounds
start and end are given in bytes.
A BufferSlice
can be used to supply vertex and index data, or to map
buffer contents for access from the CPU. See the BufferSlice
documentation for details.
The range
argument can be half or fully unbounded: for example,
buffer.slice(..)
refers to the entire buffer, and buffer.slice(n..)
refers to the portion starting at the n
th byte and extending to the
end of the buffer.
pub fn unmap(&self)
pub fn unmap(&self)
Flushes any pending write operations and unmaps the buffer from host memory.
pub fn destroy(&self)
pub fn destroy(&self)
Destroy the associated native resources as soon as possible.
pub fn size(&self) -> u64
pub fn size(&self) -> u64
Returns the length of the buffer allocation in bytes.
This is always equal to the size
that was specified when creating the buffer.
pub fn usage(&self) -> BufferUsages
pub fn usage(&self) -> BufferUsages
Returns the allowed usages for this Buffer
.
This is always equal to the usage
that was specified when creating the buffer.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Buffer
impl !RefUnwindSafe for Buffer
impl Send for Buffer
impl Sync for Buffer
impl Unpin for Buffer
impl !UnwindSafe for Buffer
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CheckedAs for T
impl<T> CheckedAs for T
source§fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
source§impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
source§fn checked_cast_from(src: Src) -> Option<Dst>
fn checked_cast_from(src: Src) -> Option<Dst>
§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
source§impl<T> IntoEither for T
impl<T> IntoEither for T
source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moresource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T
in a tonic::Request