wgpu/api/buffer.rs
1use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
2use core::{
3 error, fmt,
4 num::NonZero,
5 ops::{Bound, Range, RangeBounds},
6};
7
8use crate::util::Mutex;
9use crate::*;
10
11/// Handle to a GPU-accessible buffer.
12///
13/// A `Buffer` is a memory allocation for use by the GPU, somewhat analogous to
14/// <code>[Box]<[\[u8\]][primitive@slice]></code> in Rust.
15/// The contents of buffers are untyped bytes; it is up to the application to
16/// specify the interpretation of the bytes when the buffer is used, in ways
17/// such as [`VertexBufferLayout`].
18/// A single buffer can be used to hold multiple independent pieces of data at
19/// different offsets (e.g. both vertices and indices for one or more meshes).
20///
21/// A `Buffer`'s bytes have "interior mutability": functions like
22/// [`Queue::write_buffer`] or [mapping] a buffer for writing only require a
23/// `&Buffer`, not a `&mut Buffer`, even though they modify its contents. `wgpu`
24/// prevents simultaneous reads and writes of buffer contents using run-time
25/// checks.
26///
27/// Created with [`Device::create_buffer()`] or
28/// [`DeviceExt::create_buffer_init()`].
29///
30/// Corresponds to [WebGPU `GPUBuffer`](https://gpuweb.github.io/gpuweb/#buffer-interface).
31///
32/// [mapping]: Buffer#mapping-buffers
33///
34/// # How to get your data into a buffer
35///
36/// Every `Buffer` starts with all bytes zeroed.
37/// There are many ways to load data into a `Buffer`:
38///
39/// - When creating a buffer, you may set the [`mapped_at_creation`][mac] flag,
40/// then write to its [`get_mapped_range_mut()`][Buffer::get_mapped_range_mut].
41/// This only works when the buffer is created and has not yet been used by
42/// the GPU, but it is all you need for buffers whose contents do not change
43/// after creation.
44/// - You may use [`DeviceExt::create_buffer_init()`] as a convenient way to
45/// do that and copy data from a `&[u8]` you provide.
46/// - After creation, you may use [`Buffer::map_async()`] to map it again;
47/// however, you then need to wait until the GPU is no longer using the buffer
48/// before you begin writing.
49/// - You may use [`CommandEncoder::copy_buffer_to_buffer()`] to copy data into
50/// this buffer from another buffer.
51/// - You may use [`Queue::write_buffer()`] to copy data into the buffer from a
52/// `&[u8]`. This uses a temporary “staging” buffer managed by `wgpu` to hold
53/// the data.
54/// - [`Queue::write_buffer_with()`] allows you to write directly into temporary
55/// storage instead of providing a slice you already prepared, which may
56/// allow *your* code to save the allocation of a [`Vec`] or such.
57/// - You may use [`util::StagingBelt`] to manage a set of temporary buffers.
58/// This may be more efficient than [`Queue::write_buffer_with()`] when you
59/// have many small copies to perform, but requires more steps to use, and
60/// tuning of the belt buffer size.
61/// - You may write your own staging buffer management customized to your
62/// application, based on mapped buffers and
63/// [`CommandEncoder::copy_buffer_to_buffer()`].
64/// - A GPU computation’s results can be stored in a buffer:
65/// - A [compute shader][ComputePipeline] may write to a buffer bound as a
66/// [storage buffer][BufferBindingType::Storage].
67/// - A render pass may render to a texture which is then copied to a buffer
68/// using [`CommandEncoder::copy_texture_to_buffer()`].
69///
70/// # Mapping buffers
71///
72/// If a `Buffer` is created with the appropriate [`usage`], it can be *mapped*:
73/// you can make its contents accessible to the CPU as an ordinary `&[u8]` or
74/// `&mut [u8]` slice of bytes. Buffers created with the
75/// [`mapped_at_creation`][mac] flag set are also mapped initially.
76///
77/// Depending on the hardware, the buffer could be memory shared between CPU and
78/// GPU, so that the CPU has direct access to the same bytes the GPU will
79/// consult; or it may be ordinary CPU memory, whose contents the system must
80/// copy to/from the GPU as needed. This crate's API is designed to work the
81/// same way in either case: at any given time, a buffer is either mapped and
82/// available to the CPU, or unmapped and ready for use by the GPU, but never
83/// both. This makes it impossible for either side to observe changes by the
84/// other immediately, and any necessary transfers can be carried out when the
85/// buffer transitions from one state to the other.
86///
87/// There are two ways to map a buffer:
88///
89/// - If [`BufferDescriptor::mapped_at_creation`] is `true`, then the entire
90/// buffer is mapped when it is created. This is the easiest way to initialize
91/// a new buffer. You can set `mapped_at_creation` on any kind of buffer,
92/// regardless of its [`usage`] flags.
93///
94/// - If the buffer's [`usage`] includes the [`MAP_READ`] or [`MAP_WRITE`]
95/// flags, then you can call `buffer.slice(range).map_async(mode, callback)`
96/// to map the portion of `buffer` given by `range`. This waits for the GPU to
97/// finish using the buffer, and invokes `callback` as soon as the buffer is
98/// safe for the CPU to access.
99///
100/// Once a buffer is mapped:
101///
102/// - You can call `buffer.slice(range).get_mapped_range()` to obtain a
103/// [`BufferView`], which dereferences to a `&[u8]` that you can use to read
104/// the buffer's contents.
105///
106/// - Or, you can call `buffer.slice(range).get_mapped_range_mut()` to obtain a
107/// [`BufferViewMut`], which dereferences to a `&mut [u8]` that you can use to
108/// read and write the buffer's contents.
109///
110/// The given `range` must fall within the mapped portion of the buffer. If you
111/// attempt to access overlapping ranges, even for shared access only, these
112/// methods panic.
113///
114/// While a buffer is mapped, you may not submit any commands to the GPU that
115/// access it. You may record command buffers that use the buffer, but if you
116/// submit them while the buffer is mapped, submission will panic.
117///
118/// When you are done using the buffer on the CPU, you must call
119/// [`Buffer::unmap`] to make it available for use by the GPU again. All
120/// [`BufferView`] and [`BufferViewMut`] views referring to the buffer must be
121/// dropped before you unmap it; otherwise, [`Buffer::unmap`] will panic.
122///
123/// # Example
124///
125/// If `buffer` was created with [`BufferUsages::MAP_WRITE`], we could fill it
126/// with `f32` values like this:
127///
128/// ```
129/// # #[cfg(feature = "noop")]
130/// # let (device, _queue) = wgpu::Device::noop(&wgpu::DeviceDescriptor::default());
131/// # #[cfg(not(feature = "noop"))]
132/// # let device: wgpu::Device = { return; };
133/// #
134/// # let buffer = device.create_buffer(&wgpu::BufferDescriptor {
135/// # label: None,
136/// # size: 400,
137/// # usage: wgpu::BufferUsages::MAP_WRITE,
138/// # mapped_at_creation: false,
139/// # });
140/// let capturable = buffer.clone();
141/// buffer.map_async(wgpu::MapMode::Write, .., move |result| {
142/// if result.is_ok() {
143/// let mut view = capturable.get_mapped_range_mut(..).unwrap();
144/// let mut floats: wgpu::WriteOnly<[[u8; 4]]> = view.slice(..).into_chunks::<4>().0;
145/// floats.fill(42.0f32.to_ne_bytes());
146/// drop(view);
147/// capturable.unmap();
148/// }
149/// });
150/// ```
151///
152/// This code takes the following steps:
153///
154/// - First, it makes a cloned handle to the buffer for capture by
155/// the callback passed to [`map_async`]. Since a [`map_async`] callback may be
156/// invoked from another thread, interaction between the callback and the
157/// thread calling [`map_async`] generally requires some sort of shared heap
158/// data like this. In real code, there might be an [`Arc`] to some larger
159/// structure that itself owns `buffer`.
160///
161/// - Then, it calls [`Buffer::slice`] to make a [`BufferSlice`] referring to
162/// the buffer's entire contents.
163///
164/// - Next, it calls [`BufferSlice::map_async`] to request that the bytes to
165/// which the slice refers be made accessible to the CPU ("mapped"). This may
166/// entail waiting for previously enqueued operations on `buffer` to finish.
167/// Although [`map_async`] itself always returns immediately, it saves the
168/// callback function to be invoked later.
169///
170/// - When some later call to [`Device::poll`] or [`Instance::poll_all`] (not
171/// shown in this example) determines that the buffer is mapped and ready for
172/// the CPU to use, it invokes the callback function.
173///
174/// - The callback function calls [`Buffer::slice`] and then
175/// [`BufferSlice::get_mapped_range_mut`] to obtain a [`BufferViewMut`], which
176/// dereferences to a `&mut [u8]` slice referring to the buffer's bytes.
177///
178/// - It then uses the [`bytemuck`] crate to turn the `&mut [u8]` into a `&mut
179/// [f32]`, and calls the slice [`fill`] method to fill the buffer with a
180/// useful value.
181///
182/// - Finally, the callback drops the view and calls [`Buffer::unmap`] to unmap
183/// the buffer. In real code, the callback would also need to do some sort of
184/// synchronization to let the rest of the program know that it has completed
185/// its work.
186///
187/// If using [`map_async`] directly is awkward, you may find it more convenient to
188/// use [`Queue::write_buffer`] and [`util::DownloadBuffer::read_buffer`].
189/// However, those each have their own tradeoffs; the asynchronous nature of GPU
190/// execution makes it hard to avoid friction altogether.
191///
192/// [`Arc`]: std::sync::Arc
193/// [`map_async`]: BufferSlice::map_async
194/// [`bytemuck`]: https://crates.io/crates/bytemuck
195/// [`fill`]: slice::fill
196///
197/// ## Mapping buffers on the web
198///
199/// When compiled to WebAssembly and running in a browser content process,
200/// `wgpu` implements its API in terms of the browser's WebGPU implementation.
201/// In this context, `wgpu` is further isolated from the GPU:
202///
203/// - Depending on the browser's WebGPU implementation, mapping and unmapping
204/// buffers probably entails copies between WebAssembly linear memory and the
205/// graphics driver's buffers.
206///
207/// - All modern web browsers isolate web content in its own sandboxed process,
208/// which can only interact with the GPU via interprocess communication (IPC).
209/// Although most browsers' IPC systems use shared memory for large data
210/// transfers, there will still probably need to be copies into and out of the
211/// shared memory buffers.
212///
213/// All of these copies contribute to the cost of buffer mapping in this
214/// configuration.
215///
216/// [`usage`]: BufferDescriptor::usage
217/// [mac]: BufferDescriptor::mapped_at_creation
218/// [`MAP_READ`]: BufferUsages::MAP_READ
219/// [`MAP_WRITE`]: BufferUsages::MAP_WRITE
220/// [`DeviceExt::create_buffer_init()`]: util::DeviceExt::create_buffer_init
221#[derive(Debug, Clone)]
222pub struct Buffer {
223 pub(crate) inner: dispatch::DispatchBuffer,
224 pub(crate) map_context: Arc<Mutex<MapContext>>,
225 pub(crate) size: wgt::BufferAddress,
226 pub(crate) usage: BufferUsages,
227 // Todo: missing map_state https://www.w3.org/TR/webgpu/#dom-gpubuffer-mapstate
228}
229#[cfg(send_sync)]
230static_assertions::assert_impl_all!(Buffer: Send, Sync);
231
232crate::cmp::impl_eq_ord_hash_proxy!(Buffer => .inner);
233
234impl Buffer {
235 /// Return the binding view of the entire buffer.
236 pub fn as_entire_binding(&self) -> BindingResource<'_> {
237 BindingResource::Buffer(self.as_entire_buffer_binding())
238 }
239
240 /// Return the binding view of the entire buffer.
241 pub fn as_entire_buffer_binding(&self) -> BufferBinding<'_> {
242 BufferBinding {
243 buffer: self,
244 offset: 0,
245 size: None,
246 }
247 }
248
249 /// Get the [`wgpu_hal`] buffer from this `Buffer`.
250 ///
251 /// Find the Api struct corresponding to the active backend in [`wgpu_hal::api`],
252 /// and pass that struct to the to the `A` type parameter.
253 ///
254 /// Returns a guard that dereferences to the type of the hal backend
255 /// which implements [`A::Buffer`].
256 ///
257 /// # Types
258 ///
259 /// The returned type depends on the backend:
260 ///
261 #[doc = crate::macros::hal_type_vulkan!("Buffer")]
262 #[doc = crate::macros::hal_type_metal!("Buffer")]
263 #[doc = crate::macros::hal_type_dx12!("Buffer")]
264 #[doc = crate::macros::hal_type_gles!("Buffer")]
265 ///
266 /// # Deadlocks
267 ///
268 /// - The returned guard holds a read-lock on a device-local "destruction"
269 /// lock, which will cause all calls to `destroy` to block until the
270 /// guard is released.
271 ///
272 /// # Errors
273 ///
274 /// This method will return None if:
275 /// - The buffer is not from the backend specified by `A`.
276 /// - The buffer is from [`Backend::BrowserWebGpu`].
277 /// (Use `Buffer::as_webgpu()` instead.)
278 /// - The buffer is from a custom backend.
279 /// - The buffer has had [`Self::destroy()`] called on it.
280 ///
281 /// # Safety
282 ///
283 /// - The returned resource must not be destroyed unless the guard
284 /// is the last reference to it and it is not in use by the GPU.
285 /// The guard and handle may be dropped at any time however.
286 /// - All the safety requirements of wgpu-hal must be upheld.
287 ///
288 /// [`A::Buffer`]: hal::Api::Buffer
289 #[cfg(wgpu_core)]
290 pub unsafe fn as_hal<A: hal::Api>(
291 &self,
292 ) -> Option<impl core::ops::Deref<Target = A::Buffer> + WasmNotSendSync> {
293 let buffer = self.inner.as_core_opt()?;
294 unsafe { buffer.context.buffer_as_hal::<A>(buffer) }
295 }
296
297 /// Returns a [`BufferSlice`] referring to the portion of `self`'s contents
298 /// indicated by `bounds`. Regardless of what sort of data `self` stores,
299 /// `bounds` start and end are given in bytes.
300 ///
301 /// A [`BufferSlice`] can be used to supply vertex and index data, or to map
302 /// buffer contents for access from the CPU. See the [`BufferSlice`]
303 /// documentation for details.
304 ///
305 /// The `range` argument can be half or fully unbounded: for example,
306 /// `buffer.slice(..)` refers to the entire buffer, and `buffer.slice(n..)`
307 /// refers to the portion starting at the `n`th byte and extending to the
308 /// end of the buffer.
309 ///
310 /// # Panics
311 ///
312 /// - If `bounds` is outside of the bounds of `self`.
313 #[track_caller]
314 pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice<'_> {
315 let (offset, size) = range_to_offset_size(bounds, self.size);
316 check_buffer_bounds(self.size, offset, size);
317 BufferSlice {
318 buffer: self,
319 offset,
320 size,
321 }
322 }
323
324 /// Unmaps the buffer from host memory.
325 ///
326 /// This terminates the effect of all previous [`map_async()`](Self::map_async) operations and
327 /// makes the buffer available for use by the GPU again.
328 pub fn unmap(&self) {
329 self.map_context.lock().reset();
330 self.inner.unmap();
331 }
332
333 /// Destroy the associated native resources as soon as possible.
334 pub fn destroy(&self) {
335 self.inner.destroy();
336 }
337
338 /// Returns the length of the buffer allocation in bytes.
339 ///
340 /// This is always equal to the `size` that was specified when creating the buffer.
341 pub fn size(&self) -> BufferAddress {
342 self.size
343 }
344
345 /// Returns the allowed usages for this `Buffer`.
346 ///
347 /// This is always equal to the `usage` that was specified when creating the buffer.
348 pub fn usage(&self) -> BufferUsages {
349 self.usage
350 }
351
352 /// Map the buffer to host (CPU) memory, making it available for reading or writing via
353 /// [`get_mapped_range()`](Self::get_mapped_range). The buffer becomes accessible once the
354 /// `callback` is invoked with [`Ok`].
355 ///
356 /// Use this when you want to map the buffer immediately. If you need to submit GPU work that
357 /// uses the buffer before mapping it, use `map_buffer_on_submit` on
358 /// [`CommandEncoder`][CEmbos], [`CommandBuffer`][CBmbos], [`RenderPass`][RPmbos], or
359 /// [`ComputePass`][CPmbos] to schedule the mapping after submission. This avoids extra calls to
360 /// [`Buffer::map_async()`] or [`BufferSlice::map_async()`] and lets you initiate mapping from a
361 /// more convenient place.
362 ///
363 /// For the callback to run, either [`queue.submit(..)`][q::s], [`instance.poll_all(..)`][i::p_a],
364 /// or [`device.poll(..)`][d::p] must be called elsewhere in the runtime, possibly integrated into
365 /// an event loop or run on a separate thread.
366 ///
367 /// The callback runs on the thread that first calls one of the above functions after the GPU work
368 /// completes. There are no restrictions on the code you can run in the callback; however, on native
369 /// the polling call will not return until the callback finishes, so keep callbacks short (set flags,
370 /// send messages, etc.).
371 ///
372 /// While a buffer is mapped, it cannot be used by other commands; at any time, either the GPU or
373 /// the CPU has exclusive access to the buffer’s contents.
374 ///
375 /// This can also be performed using [`BufferSlice::map_async()`].
376 ///
377 /// # Panics
378 ///
379 /// - If the buffer is already mapped.
380 /// - If the buffer’s [`BufferUsages`] do not allow the requested [`MapMode`].
381 /// - If `bounds` is outside of the bounds of `self`.
382 /// - If `bounds` does not start at a multiple of [`MAP_ALIGNMENT`].
383 /// - If `bounds` has a length that is not a multiple of 4 greater than 0.
384 ///
385 /// [CEmbos]: CommandEncoder::map_buffer_on_submit
386 /// [CBmbos]: CommandBuffer::map_buffer_on_submit
387 /// [RPmbos]: RenderPass::map_buffer_on_submit
388 /// [CPmbos]: ComputePass::map_buffer_on_submit
389 /// [q::s]: Queue::submit
390 /// [i::p_a]: Instance::poll_all
391 /// [d::p]: Device::poll
392 pub fn map_async<S: RangeBounds<BufferAddress>>(
393 &self,
394 mode: MapMode,
395 bounds: S,
396 callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static,
397 ) {
398 self.slice(bounds).map_async(mode, callback)
399 }
400
401 /// Gain read-only access to the bytes of a [mapped] [`Buffer`].
402 ///
403 /// Returns a [`BufferView`] referring to the buffer range represented by
404 /// `self`. See the documentation for [`BufferView`] for details.
405 ///
406 /// `bounds` may be less than the bounds passed to [`Self::map_async()`],
407 /// and multiple views may be obtained and used simultaneously as long as they do not overlap.
408 ///
409 /// This can also be performed using [`BufferSlice::get_mapped_range()`].
410 ///
411 /// # Errors
412 ///
413 /// - If `bounds` is outside of the bounds of `self`.
414 /// - If `bounds` does not start at a multiple of [`MAP_ALIGNMENT`].
415 /// - If `bounds` has a length that is not a multiple of 4 greater than 0.
416 /// - If the buffer to which `self` refers is not currently [mapped].
417 /// - If you try to create a view which overlaps an existing [`BufferViewMut`].
418 ///
419 /// [mapped]: Buffer#mapping-buffers
420 #[track_caller]
421 pub fn get_mapped_range<S: RangeBounds<BufferAddress>>(
422 &self,
423 bounds: S,
424 ) -> Result<BufferView, MapRangeError> {
425 self.slice(bounds).get_mapped_range()
426 }
427
428 /// Gain write access to the bytes of a [mapped] [`Buffer`].
429 ///
430 /// Returns a [`BufferViewMut`] referring to the buffer range represented by
431 /// `self`. See the documentation for [`BufferViewMut`] for more details.
432 ///
433 /// `bounds` may be less than the bounds passed to [`Self::map_async()`],
434 /// and multiple views may be obtained and used simultaneously as long as they do not overlap.
435 ///
436 /// This can also be performed using [`BufferSlice::get_mapped_range_mut()`].
437 ///
438 /// # Errors
439 ///
440 /// - If `bounds` is outside of the bounds of `self`.
441 /// - If `bounds` does not start at a multiple of [`MAP_ALIGNMENT`].
442 /// - If `bounds` has a length that is not a multiple of 4 greater than 0.
443 /// - If the buffer to which `self` refers is not currently [mapped].
444 /// - If you try to create a view which overlaps an existing [`BufferView`] or [`BufferViewMut`].
445 ///
446 /// [mapped]: Buffer#mapping-buffers
447 #[track_caller]
448 pub fn get_mapped_range_mut<S: RangeBounds<BufferAddress>>(
449 &self,
450 bounds: S,
451 ) -> Result<BufferViewMut, MapRangeError> {
452 self.slice(bounds).get_mapped_range_mut()
453 }
454
455 #[cfg(custom)]
456 /// Returns custom implementation of Buffer (if custom backend and is internally T)
457 pub fn as_custom<T: custom::BufferInterface>(&self) -> Option<&T> {
458 self.inner.as_custom()
459 }
460
461 /// Returns the underlying [`webgpu::GpuBuffer`] handle if this `Buffer`
462 /// is on the WebGPU backend, otherwise `None`.
463 #[cfg(webgpu)]
464 pub fn as_webgpu(&self) -> Option<&webgpu::GpuBuffer> {
465 self.inner.as_webgpu_opt().map(|wb| &wb.inner)
466 }
467}
468
469/// A slice of a [`Buffer`], to be mapped, used for vertex or index data, or the like.
470///
471/// You can create a `BufferSlice` by calling [`Buffer::slice`]:
472///
473/// ```no_run
474/// # let buffer: wgpu::Buffer = todo!();
475/// let slice = buffer.slice(10..20);
476/// ```
477///
478/// This returns a slice referring to the second ten bytes of `buffer`. To get a
479/// slice of the entire `Buffer`:
480///
481/// ```no_run
482/// # let buffer: wgpu::Buffer = todo!();
483/// let whole_buffer_slice = buffer.slice(..);
484/// ```
485///
486/// You can pass buffer slices to methods like [`RenderPass::set_vertex_buffer`]
487/// and [`RenderPass::set_index_buffer`] to indicate which portion of the buffer
488/// a draw call should consult. You can also convert it to a [`BufferBinding`]
489/// with `.try_into()`, which fails if the slice length is 0.
490///
491/// To access the slice's contents on the CPU, you must first [map] the buffer,
492/// and then call [`BufferSlice::get_mapped_range`] or
493/// [`BufferSlice::get_mapped_range_mut`] to obtain a view of the slice's
494/// contents. See the documentation on [mapping][map] for more details,
495/// including example code.
496///
497/// Unlike a Rust shared slice `&[T]`, whose existence guarantees that
498/// nobody else is modifying the `T` values to which it refers, a
499/// [`BufferSlice`] doesn't guarantee that the buffer's contents aren't
500/// changing. You can still record and submit commands operating on the
501/// buffer while holding a [`BufferSlice`]. A [`BufferSlice`] simply
502/// represents a certain range of the buffer's bytes.
503///
504/// The `BufferSlice` type is unique to the Rust API of `wgpu`. In the WebGPU
505/// specification, an offset and size are specified as arguments to each call
506/// working with the [`Buffer`], instead.
507///
508/// [map]: Buffer#mapping-buffers
509#[derive(Copy, Clone, Debug, PartialEq)]
510pub struct BufferSlice<'a> {
511 pub(crate) buffer: &'a Buffer,
512 pub(crate) offset: BufferAddress,
513 pub(crate) size: BufferAddress,
514}
515#[cfg(send_sync)]
516static_assertions::assert_impl_all!(BufferSlice<'_>: Send, Sync);
517
518impl<'a> BufferSlice<'a> {
519 /// Return another [`BufferSlice`] referring to the portion of `self`'s contents
520 /// indicated by `bounds`.
521 ///
522 /// The `range` argument can be half or fully unbounded: for example,
523 /// `buffer.slice(..)` refers to the entire buffer, and `buffer.slice(n..)`
524 /// refers to the portion starting at the `n`th byte and extending to the
525 /// end of the buffer.
526 ///
527 /// # Panics
528 ///
529 /// - If `bounds` is outside of the bounds of `self`.
530 #[track_caller]
531 pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice<'a> {
532 let (offset, size) = range_to_offset_size(bounds, self.size);
533 check_buffer_bounds(self.size, offset, size);
534 BufferSlice {
535 buffer: self.buffer,
536 offset: self.offset + offset, // check_buffer_bounds ensures this does not overflow
537 size, // check_buffer_bounds ensures this is essentially min()
538 }
539 }
540
541 /// Map the buffer to host (CPU) memory, making it available for reading or writing via
542 /// [`get_mapped_range()`](Self::get_mapped_range). The buffer becomes accessible once the
543 /// `callback` is invoked with [`Ok`].
544 ///
545 /// Use this when you want to map the buffer immediately. If you need to submit GPU work that
546 /// uses the buffer before mapping it, use `map_buffer_on_submit` on
547 /// [`CommandEncoder`][CEmbos], [`CommandBuffer`][CBmbos], [`RenderPass`][RPmbos], or
548 /// [`ComputePass`][CPmbos] to schedule the mapping after submission. This avoids extra calls to
549 /// [`Buffer::map_async()`] or [`BufferSlice::map_async()`] and lets you initiate mapping from a
550 /// more convenient place.
551 ///
552 /// For the callback to run, either [`queue.submit(..)`][q::s], [`instance.poll_all(..)`][i::p_a],
553 /// or [`device.poll(..)`][d::p] must be called elsewhere in the runtime, possibly integrated into
554 /// an event loop or run on a separate thread.
555 ///
556 /// The callback runs on the thread that first calls one of the above functions after the GPU work
557 /// completes. There are no restrictions on the code you can run in the callback; however, on native
558 /// the polling call will not return until the callback finishes, so keep callbacks short (set flags,
559 /// send messages, etc.).
560 ///
561 /// While a buffer is mapped, it cannot be used by other commands; at any time, either the GPU or
562 /// the CPU has exclusive access to the buffer’s contents.
563 ///
564 /// This can also be performed using [`Buffer::map_async()`].
565 ///
566 /// # Panics
567 ///
568 /// - If the buffer’s [`BufferUsages`] do not allow the requested [`MapMode`].
569 /// - If the beginning of this slice is not aligned to [`MAP_ALIGNMENT`] within the buffer.
570 /// - If the length of this slice is not a multiple of 4.
571 ///
572 /// [CEmbos]: CommandEncoder::map_buffer_on_submit
573 /// [CBmbos]: CommandBuffer::map_buffer_on_submit
574 /// [RPmbos]: RenderPass::map_buffer_on_submit
575 /// [CPmbos]: ComputePass::map_buffer_on_submit
576 /// [q::s]: Queue::submit
577 /// [i::p_a]: Instance::poll_all
578 /// [d::p]: Device::poll
579 pub fn map_async(
580 &self,
581 mode: MapMode,
582 callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static,
583 ) {
584 let mut mc = self.buffer.map_context.lock();
585 if mc.mapped_range.is_some() {
586 // Buffer is already mapped; fail
587 drop(mc);
588 callback(Err(BufferAsyncError));
589 return;
590 }
591
592 let end = self.offset + self.size;
593 mc.mapped_range = Some(self.offset..end);
594 drop(mc); // release the lock of map_context as callback can call lock it again
595
596 self.buffer
597 .inner
598 .map_async(mode, self.offset..end, Box::new(callback));
599 }
600
601 /// Gain read-only access to the bytes of a [mapped] [`Buffer`].
602 ///
603 /// Returns a [`BufferView`] referring to the buffer range represented by
604 /// `self`. See the documentation for [`BufferView`] for details.
605 ///
606 /// Multiple views may be obtained and used simultaneously as long as they are from
607 /// non-overlapping slices.
608 ///
609 /// This can also be performed using [`Buffer::get_mapped_range()`].
610 ///
611 /// # Errors
612 ///
613 /// - If the beginning of this slice is not aligned to [`MAP_ALIGNMENT`] within the buffer.
614 /// - If the length of this slice is not a multiple of 4.
615 /// - If the buffer to which `self` refers is not currently [mapped].
616 /// - If you try to create a view which overlaps an existing [`BufferViewMut`].
617 ///
618 /// [mapped]: Buffer#mapping-buffers
619 #[track_caller]
620 pub fn get_mapped_range(&self) -> Result<BufferView, MapRangeError> {
621 let subrange = Subrange::new(self.offset, self.size, RangeMappingKind::Immutable);
622 let range = self.buffer.inner.get_mapped_range(subrange.index.clone())?;
623 self.buffer.map_context.lock().validate_and_add(subrange)?;
624 Ok(BufferView {
625 buffer: self.buffer.clone(),
626 size: self.size,
627 offset: self.offset,
628 inner: range,
629 })
630 }
631
632 /// Gain write-only access to the bytes of a [mapped] [`Buffer`].
633 ///
634 /// Returns a [`BufferViewMut`] referring to the buffer range represented by
635 /// `self`. See the documentation for [`BufferViewMut`] for more details.
636 ///
637 /// Multiple views may be obtained and used simultaneously as long as they are from
638 /// non-overlapping slices.
639 ///
640 /// This can also be performed using [`Buffer::get_mapped_range_mut()`].
641 ///
642 /// # Errors
643 ///
644 /// - If the beginning of this slice is not aligned to [`MAP_ALIGNMENT`] within the buffer.
645 /// - If the length of this slice is not a multiple of 4.
646 /// - If the buffer to which `self` refers is not currently [mapped].
647 /// - If you try to create a view which overlaps an existing [`BufferView`] or [`BufferViewMut`].
648 ///
649 /// [mapped]: Buffer#mapping-buffers
650 #[track_caller]
651 pub fn get_mapped_range_mut(&self) -> Result<BufferViewMut, MapRangeError> {
652 let subrange = Subrange::new(self.offset, self.size, RangeMappingKind::Mutable);
653 let range = self.buffer.inner.get_mapped_range(subrange.index.clone())?;
654 self.buffer.map_context.lock().validate_and_add(subrange)?;
655 Ok(BufferViewMut {
656 buffer: self.buffer.clone(),
657 size: self.size,
658 offset: self.offset,
659 inner: range,
660 })
661 }
662
663 /// Returns the buffer this is a slice of.
664 ///
665 /// You should usually not need to call this, and if you received the buffer from code you
666 /// do not control, you should refrain from accessing the buffer outside the bounds of the
667 /// slice. Nevertheless, it’s possible to get this access, so this method makes it simple.
668 pub fn buffer(&self) -> &'a Buffer {
669 self.buffer
670 }
671
672 /// Returns the offset in [`Self::buffer()`] this slice starts at.
673 pub fn offset(&self) -> BufferAddress {
674 self.offset
675 }
676
677 /// Returns the size of this slice.
678 pub fn size(&self) -> BufferAddress {
679 self.size
680 }
681
682 pub(crate) fn size_expect_nonzero(&self) -> BufferSize {
683 BufferSize::new(self.size).expect("buffer slice can not be empty")
684 }
685}
686
687impl<'a> TryFrom<BufferSlice<'a>> for crate::BufferBinding<'a> {
688 type Error = ();
689
690 /// Convert a [`BufferSlice`] to an equivalent [`BufferBinding`],
691 /// provided that it will be used without a dynamic offset.
692 fn try_from(value: BufferSlice<'a>) -> Result<Self, Self::Error> {
693 Ok(BufferBinding {
694 buffer: value.buffer,
695 offset: value.offset,
696 size: Some(NonZero::new(value.size()).ok_or(())?),
697 })
698 }
699}
700
701impl<'a> TryFrom<BufferSlice<'a>> for crate::BindingResource<'a> {
702 type Error = ();
703
704 /// Convert a [`BufferSlice`] to an equivalent [`BindingResource::Buffer`],
705 /// provided that it will be used without a dynamic offset.
706 fn try_from(value: BufferSlice<'a>) -> Result<Self, Self::Error> {
707 Ok(crate::BindingResource::Buffer(
708 crate::BufferBinding::try_from(value)?,
709 ))
710 }
711}
712
713fn range_overlaps(a: &Range<BufferAddress>, b: &Range<BufferAddress>) -> bool {
714 a.start < b.end && b.start < a.end
715}
716
717fn range_contains(a: &Range<BufferAddress>, b: &Range<BufferAddress>) -> bool {
718 a.start <= b.start && a.end >= b.end
719}
720
721#[derive(Debug, Copy, Clone)]
722enum RangeMappingKind {
723 Mutable,
724 Immutable,
725}
726
727impl RangeMappingKind {
728 /// Returns true if a range of this kind can touch the same bytes as a range of the other kind.
729 ///
730 /// This is Rust's Mutable XOR Shared rule.
731 fn allowed_concurrently_with(self, other: Self) -> bool {
732 matches!(
733 (self, other),
734 (RangeMappingKind::Immutable, RangeMappingKind::Immutable)
735 )
736 }
737}
738
739#[derive(Debug, Clone)]
740struct Subrange {
741 index: Range<BufferAddress>,
742 kind: RangeMappingKind,
743}
744
745impl Subrange {
746 fn new(offset: BufferAddress, size: BufferAddress, kind: RangeMappingKind) -> Self {
747 Self {
748 index: offset..(offset + size),
749 kind,
750 }
751 }
752}
753
754impl fmt::Display for Subrange {
755 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
756 write!(
757 f,
758 "{}..{} ({:?})",
759 self.index.start, self.index.end, self.kind
760 )
761 }
762}
763
764/// The mapped portion of a buffer, if any, and its outstanding views.
765///
766/// This ensures that views fall within the mapped range and don't overlap.
767#[derive(Debug)]
768pub(crate) struct MapContext {
769 /// The range of the buffer that is mapped.
770 ///
771 /// This becomes Some(...) when the buffer is mapped at creation time, and
772 /// when you call `map_async` on some [`BufferSlice`] (so technically, it
773 /// indicates the portion that is *or has been requested to be* mapped.)
774 ///
775 /// All [`BufferView`]s and [`BufferViewMut`]s must fall within this range.
776 mapped_range: Option<Range<BufferAddress>>,
777
778 /// The ranges covered by all outstanding [`BufferView`]s and
779 /// [`BufferViewMut`]s. These are non-overlapping, and are all contained
780 /// within `mapped_range`.
781 sub_ranges: Vec<Subrange>,
782}
783
784impl MapContext {
785 /// Creates a new `MapContext`.
786 ///
787 /// For [`mapped_at_creation`] buffers, pass the full buffer range in the
788 /// `mapped_range` argument. For other buffers, pass `None`.
789 ///
790 /// [`mapped_at_creation`]: BufferDescriptor::mapped_at_creation
791 pub(crate) fn new(mapped_range: Option<Range<BufferAddress>>) -> Self {
792 Self {
793 mapped_range,
794 sub_ranges: Vec::new(),
795 }
796 }
797
798 /// Record that the buffer is no longer mapped.
799 fn reset(&mut self) {
800 self.mapped_range = None;
801
802 assert!(
803 self.sub_ranges.is_empty(),
804 "You cannot unmap a buffer that still has accessible mapped views"
805 );
806 }
807
808 /// Record that the `size` bytes of the buffer at `offset` are now viewed.
809 ///
810 /// # Errors
811 ///
812 /// This returns an error if the given range is invalid.
813 fn validate_and_add(&mut self, new_sub: Subrange) -> Result<(), MapRangeError> {
814 if self.mapped_range.is_none() {
815 return Err(MapRangeError(
816 "tried to call get_mapped_range(_mut) on an unmapped buffer".into(),
817 ));
818 }
819 let mapped_range = self.mapped_range.as_ref().unwrap();
820 if !range_contains(mapped_range, &new_sub.index) {
821 return Err(MapRangeError(alloc::format!(
822 "tried to call get_mapped_range(_mut) on a range that is not entirely mapped. \
823 Attempted to get range {}, but the mapped range is {}..{}",
824 new_sub,
825 mapped_range.start,
826 mapped_range.end
827 )));
828 }
829 // This check is essential for avoiding undefined behavior: it is the
830 // only thing that ensures that `&mut` references to the buffer's
831 // contents don't alias anything else.
832 for sub in self.sub_ranges.iter() {
833 if range_overlaps(&sub.index, &new_sub.index)
834 && !sub.kind.allowed_concurrently_with(new_sub.kind)
835 {
836 return Err(MapRangeError(alloc::format!(
837 "tried to call get_mapped_range(_mut) on a range that has already \
838 been mapped and would break Rust memory aliasing rules. Attempted \
839 to get range {}, and the conflicting range is {}",
840 new_sub,
841 sub
842 )));
843 }
844 }
845 self.sub_ranges.push(new_sub);
846 Ok(())
847 }
848
849 /// Record that the `size` bytes of the buffer at `offset` are no longer viewed.
850 ///
851 /// # Panics
852 ///
853 /// This panics if the given range does not exactly match one previously
854 /// passed to [`MapContext::validate_and_add`].
855 pub(crate) fn remove(&mut self, offset: BufferAddress, size: BufferAddress) {
856 let end = offset + size;
857
858 let index = self
859 .sub_ranges
860 .iter()
861 .position(|r| r.index == (offset..end))
862 .expect("unable to remove range from map context");
863 self.sub_ranges.swap_remove(index);
864 }
865}
866
867/// Describes a [`Buffer`].
868///
869/// For use with [`Device::create_buffer`].
870///
871/// Corresponds to [WebGPU `GPUBufferDescriptor`](
872/// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferdescriptor).
873pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
874static_assertions::assert_impl_all!(BufferDescriptor<'_>: Send, Sync);
875
876/// Error occurred when trying to async map a buffer.
877#[derive(Clone, PartialEq, Eq, Debug)]
878pub struct BufferAsyncError;
879static_assertions::assert_impl_all!(BufferAsyncError: Send, Sync);
880
881impl fmt::Display for BufferAsyncError {
882 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
883 write!(f, "Error occurred when trying to async map a buffer")
884 }
885}
886
887impl error::Error for BufferAsyncError {}
888
889/// Error returned by [`BufferSlice::get_mapped_range`] and [`BufferSlice::get_mapped_range_mut`].
890///
891/// Corresponds to the `OperationError` thrown by
892/// [`getMappedRange()`](https://gpuweb.github.io/gpuweb/#dom-gpubuffer-getmappedrange)
893/// in the WebGPU spec.
894#[derive(Clone, Debug)]
895pub struct MapRangeError(pub(crate) String);
896static_assertions::assert_impl_all!(MapRangeError: Send, Sync);
897
898impl fmt::Display for MapRangeError {
899 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
900 write!(f, "Buffer view error: {}", self.0)
901 }
902}
903
904impl error::Error for MapRangeError {}
905
906/// Type of buffer mapping.
907#[derive(Debug, Clone, Copy, Eq, PartialEq)]
908pub enum MapMode {
909 /// Map only for reading
910 Read,
911 /// Map only for writing
912 Write,
913}
914static_assertions::assert_impl_all!(MapMode: Send, Sync);
915
916/// A read-only view of a mapped buffer's bytes.
917///
918/// To get a `BufferView`, first [map] the buffer, and then
919/// call `buffer.slice(range).get_mapped_range()`.
920///
921/// `BufferView` dereferences to `&[u8]`, so you can use all the usual Rust
922/// slice methods to access the buffer's contents. It also implements
923/// `AsRef<[u8]>`, if that's more convenient.
924///
925/// Before the buffer can be unmapped, all `BufferView`s observing it
926/// must be dropped. Otherwise, the call to [`Buffer::unmap`] will panic.
927///
928/// For example code, see the documentation on [mapping buffers][map].
929///
930/// [map]: Buffer#mapping-buffers
931/// [`map_async`]: BufferSlice::map_async
932#[derive(Debug)]
933pub struct BufferView {
934 // `buffer, offset, size` are similar to `BufferSlice`, except that they own the buffer.
935 buffer: Buffer,
936 offset: BufferAddress,
937 size: BufferAddress,
938 inner: dispatch::DispatchBufferMappedRange,
939}
940
941/// A write-only view of a mapped buffer's bytes.
942///
943/// To get a `BufferViewMut`, first [map] the buffer, and then
944/// call `buffer.slice(range).get_mapped_range_mut()`.
945///
946/// Because Rust has no write-only reference type
947/// (`&[u8]` is read-only and `&mut [u8]` is read-write),
948/// this type does not dereference to a slice in the way that [`BufferView`] does.
949/// Instead, [`.slice()`][BufferViewMut::slice] returns a special [`WriteOnly`] pointer type,
950/// and there are also a few convenience methods such as [`BufferViewMut::copy_from_slice()`].
951///
952/// Before the buffer can be unmapped, all `BufferViewMut`s observing it
953/// must be dropped. Otherwise, the call to [`Buffer::unmap`] will panic.
954///
955/// For example code, see the documentation on [mapping buffers][map].
956///
957/// [map]: Buffer#mapping-buffers
958#[derive(Debug)]
959pub struct BufferViewMut {
960 // `buffer, offset, size` are similar to `BufferSlice`, except that they own the buffer.
961 buffer: Buffer,
962 offset: BufferAddress,
963 size: BufferAddress,
964 inner: dispatch::DispatchBufferMappedRange,
965}
966
967// `BufferView` simply dereferences. `BufferViewMut` cannot, because mapped memory may be
968// write-combining memory <https://en.wikipedia.org/wiki/Write_combining>,
969// and not support the expected behavior of atomic accesses.
970// Further context: <https://github.com/gfx-rs/wgpu/issues/8897>
971
972impl core::ops::Deref for BufferView {
973 type Target = [u8];
974
975 #[inline]
976 fn deref(&self) -> &[u8] {
977 // SAFETY: this is a read mapping
978 unsafe { self.inner.read_slice() }
979 }
980}
981
982impl AsRef<[u8]> for BufferView {
983 #[inline]
984 fn as_ref(&self) -> &[u8] {
985 self
986 }
987}
988
989impl Drop for BufferView {
990 fn drop(&mut self) {
991 self.buffer
992 .map_context
993 .lock()
994 .remove(self.offset, self.size);
995 }
996}
997
998impl Drop for BufferViewMut {
999 fn drop(&mut self) {
1000 self.buffer
1001 .map_context
1002 .lock()
1003 .remove(self.offset, self.size);
1004 }
1005}
1006
1007#[cfg(webgpu)]
1008impl BufferView {
1009 /// Provides the same data as dereferencing the view, but as a `Uint8Array` in js.
1010 /// This can be MUCH faster than dereferencing the view which copies the data into
1011 /// the Rust / wasm heap.
1012 pub fn as_uint8array(&self) -> &js_sys::Uint8Array {
1013 self.inner.as_uint8array()
1014 }
1015}
1016
1017/// These methods are equivalent to the methods of the same names on [`WriteOnly`].
1018impl BufferViewMut {
1019 /// Returns the length of this view; the number of bytes to be written.
1020 pub fn len(&self) -> usize {
1021 // cannot fail because we can't actually map more than isize::MAX bytes
1022 usize::try_from(self.size).unwrap()
1023 }
1024
1025 /// Returns `true` if the view has a length of 0.
1026 ///
1027 /// Note that this is currently impossible.
1028 pub fn is_empty(&self) -> bool {
1029 self.len() == 0
1030 }
1031
1032 /// Returns a [`WriteOnly`] reference to a portion of this.
1033 ///
1034 /// `.slice(..)` can be used to access the whole data.
1035 pub fn slice<'a, S: RangeBounds<usize>>(&'a mut self, bounds: S) -> WriteOnly<'a, [u8]> {
1036 // SAFETY: this is a write mapping
1037 unsafe { self.inner.write_slice() }.into_slice(bounds)
1038 }
1039
1040 /// Copies all elements from src into `self`.
1041 ///
1042 /// The length of `src` must be the same as `self`.
1043 ///
1044 /// This method is equivalent to
1045 /// [`self.slice(..).copy_from_slice(src)`][WriteOnly::copy_from_slice].
1046 pub fn copy_from_slice(&mut self, src: &[u8]) {
1047 self.slice(..).copy_from_slice(src)
1048 }
1049}
1050
1051#[track_caller]
1052fn check_buffer_bounds(
1053 whole_size: BufferAddress,
1054 slice_offset: BufferAddress,
1055 slice_size: BufferAddress,
1056) {
1057 if slice_offset > whole_size {
1058 panic!(
1059 "slice offset {} is out of range for buffer of size {}",
1060 slice_offset, whole_size
1061 );
1062 }
1063
1064 // Detect integer overflow.
1065 let end = slice_offset.checked_add(slice_size);
1066 if end.is_none_or(|end| end > whole_size) {
1067 panic!(
1068 "slice offset {} size {} is out of range for buffer of size {}",
1069 slice_offset, slice_size, whole_size
1070 );
1071 }
1072}
1073
1074#[track_caller]
1075pub(crate) fn range_to_offset_size<S: RangeBounds<BufferAddress>>(
1076 bounds: S,
1077 whole_size: BufferAddress,
1078) -> (BufferAddress, BufferAddress) {
1079 let offset = match bounds.start_bound() {
1080 Bound::Included(&bound) => bound,
1081 Bound::Excluded(&bound) => bound + 1,
1082 Bound::Unbounded => 0,
1083 };
1084 let size = match bounds.end_bound() {
1085 Bound::Included(&bound) => bound + 1 - offset,
1086 Bound::Excluded(&bound) => bound - offset,
1087 Bound::Unbounded => whole_size - offset,
1088 };
1089
1090 (offset, size)
1091}
1092
1093#[cfg(test)]
1094mod tests {
1095 use super::{check_buffer_bounds, range_overlaps, range_to_offset_size};
1096
1097 #[test]
1098 fn range_to_offset_size_works() {
1099 let whole = 100;
1100
1101 assert_eq!(range_to_offset_size(0..2, whole), (0, 2));
1102 assert_eq!(range_to_offset_size(2..5, whole), (2, 3));
1103 assert_eq!(range_to_offset_size(.., whole), (0, whole));
1104 assert_eq!(range_to_offset_size(21.., whole), (21, whole - 21));
1105 assert_eq!(range_to_offset_size(0.., whole), (0, whole));
1106 assert_eq!(range_to_offset_size(..21, whole), (0, 21));
1107 }
1108
1109 #[test]
1110 fn check_buffer_bounds_works_for_end_in_range() {
1111 check_buffer_bounds(200, 100, 50);
1112 check_buffer_bounds(200, 100, 100);
1113 check_buffer_bounds(u64::MAX, u64::MAX - 100, 100);
1114 check_buffer_bounds(u64::MAX, 0, u64::MAX);
1115 check_buffer_bounds(u64::MAX, 1, u64::MAX - 1);
1116 // Test empty buffer slices
1117 check_buffer_bounds(0, 0, 0);
1118 check_buffer_bounds(u64::MAX, u64::MAX, 0);
1119 }
1120
1121 #[test]
1122 #[should_panic]
1123 fn check_buffer_bounds_panics_for_end_over_size() {
1124 check_buffer_bounds(200, 100, 101);
1125 }
1126
1127 #[test]
1128 #[should_panic]
1129 fn check_buffer_bounds_panics_for_end_wraparound() {
1130 check_buffer_bounds(u64::MAX, 1, u64::MAX);
1131 }
1132
1133 #[test]
1134 fn range_overlapping() {
1135 // First range to the left
1136 assert_eq!(range_overlaps(&(0..1), &(1..3)), false);
1137 // First range overlaps left edge
1138 assert_eq!(range_overlaps(&(0..2), &(1..3)), true);
1139 // First range completely inside second
1140 assert_eq!(range_overlaps(&(1..2), &(0..3)), true);
1141 // First range completely surrounds second
1142 assert_eq!(range_overlaps(&(0..3), &(1..2)), true);
1143 // First range overlaps right edge
1144 assert_eq!(range_overlaps(&(1..3), &(0..2)), true);
1145 // First range entirely to the right
1146 assert_eq!(range_overlaps(&(2..3), &(0..2)), false);
1147 }
1148}