pub struct Buffer { /* private fields */ }
Expand description
Handle to a GPU-accessible buffer.
Created with Device::create_buffer
or
DeviceExt::create_buffer_init
.
Corresponds to WebGPU GPUBuffer
.
§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.
For example:
let slice = buffer.slice(10..20);
slice.map_async(wgpu::MapMode::Read, |result| {
match result {
Ok(()) => {
let view = slice.get_mapped_range();
// read data from `view`, which dereferences to `&[u8]`
}
Err(e) => {
// handle mapping error
}
}
});
This example calls Buffer::slice
to obtain a BufferSlice
referring to
the second ten bytes of buffer
. (To obtain access to the entire buffer,
you could call buffer.slice(..)
.) The code then calls map_async
to wait
for the buffer to be available, and finally calls get_mapped_range
on the
slice to actually get at the bytes.
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.
While a buffer is mapped, you must not submit any commands to the GPU that access it. You may record command buffers that use the buffer, but you must not submit such command buffers.
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.
§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.
Implementations§
source§impl Buffer
impl Buffer
sourcepub fn as_entire_binding(&self) -> BindingResource<'_>
pub fn as_entire_binding(&self) -> BindingResource<'_>
Return the binding view of the entire buffer.
sourcepub fn as_entire_buffer_binding(&self) -> BufferBinding<'_>
pub fn as_entire_buffer_binding(&self) -> BufferBinding<'_>
Return the binding view of the entire buffer.
sourcepub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice<'_>
pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice<'_>
Use only a portion of this Buffer for a given operation. Choosing a range with no end will use the rest of the buffer. Using a totally unbounded range will use the entire buffer.
sourcepub fn unmap(&self)
pub fn unmap(&self)
Flushes any pending write operations and unmaps the buffer from host memory.
sourcepub fn size(&self) -> BufferAddress
pub fn size(&self) -> BufferAddress
Returns the length of the buffer allocation in bytes.
This is always equal to the size
that was specified when creating the buffer.
sourcepub 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.