wgpu/api/buffer.rs
1use alloc::{boxed::Box, sync::Arc, vec::Vec};
2use core::{
3 error, fmt,
4 ops::{Bound, Deref, DerefMut, Range, RangeBounds},
5};
6
7use parking_lot::Mutex;
8
9use crate::*;
10
11/// Handle to a GPU-accessible buffer.
12///
13/// Created with [`Device::create_buffer`] or
14/// [`DeviceExt::create_buffer_init`](util::DeviceExt::create_buffer_init).
15///
16/// Corresponds to [WebGPU `GPUBuffer`](https://gpuweb.github.io/gpuweb/#buffer-interface).
17///
18/// A `Buffer`'s bytes have "interior mutability": functions like
19/// [`Queue::write_buffer`] or [mapping] a buffer for writing only require a
20/// `&Buffer`, not a `&mut Buffer`, even though they modify its contents. `wgpu`
21/// prevents simultaneous reads and writes of buffer contents using run-time
22/// checks.
23///
24/// [mapping]: Buffer#mapping-buffers
25///
26/// # Mapping buffers
27///
28/// If a `Buffer` is created with the appropriate [`usage`], it can be *mapped*:
29/// you can make its contents accessible to the CPU as an ordinary `&[u8]` or
30/// `&mut [u8]` slice of bytes. Buffers created with the
31/// [`mapped_at_creation`][mac] flag set are also mapped initially.
32///
33/// Depending on the hardware, the buffer could be memory shared between CPU and
34/// GPU, so that the CPU has direct access to the same bytes the GPU will
35/// consult; or it may be ordinary CPU memory, whose contents the system must
36/// copy to/from the GPU as needed. This crate's API is designed to work the
37/// same way in either case: at any given time, a buffer is either mapped and
38/// available to the CPU, or unmapped and ready for use by the GPU, but never
39/// both. This makes it impossible for either side to observe changes by the
40/// other immediately, and any necessary transfers can be carried out when the
41/// buffer transitions from one state to the other.
42///
43/// There are two ways to map a buffer:
44///
45/// - If [`BufferDescriptor::mapped_at_creation`] is `true`, then the entire
46/// buffer is mapped when it is created. This is the easiest way to initialize
47/// a new buffer. You can set `mapped_at_creation` on any kind of buffer,
48/// regardless of its [`usage`] flags.
49///
50/// - If the buffer's [`usage`] includes the [`MAP_READ`] or [`MAP_WRITE`]
51/// flags, then you can call `buffer.slice(range).map_async(mode, callback)`
52/// to map the portion of `buffer` given by `range`. This waits for the GPU to
53/// finish using the buffer, and invokes `callback` as soon as the buffer is
54/// safe for the CPU to access.
55///
56/// Once a buffer is mapped:
57///
58/// - You can call `buffer.slice(range).get_mapped_range()` to obtain a
59/// [`BufferView`], which dereferences to a `&[u8]` that you can use to read
60/// the buffer's contents.
61///
62/// - Or, you can call `buffer.slice(range).get_mapped_range_mut()` to obtain a
63/// [`BufferViewMut`], which dereferences to a `&mut [u8]` that you can use to
64/// read and write the buffer's contents.
65///
66/// The given `range` must fall within the mapped portion of the buffer. If you
67/// attempt to access overlapping ranges, even for shared access only, these
68/// methods panic.
69///
70/// While a buffer is mapped, you may not submit any commands to the GPU that
71/// access it. You may record command buffers that use the buffer, but if you
72/// submit them while the buffer is mapped, submission will panic.
73///
74/// When you are done using the buffer on the CPU, you must call
75/// [`Buffer::unmap`] to make it available for use by the GPU again. All
76/// [`BufferView`] and [`BufferViewMut`] views referring to the buffer must be
77/// dropped before you unmap it; otherwise, [`Buffer::unmap`] will panic.
78///
79/// # Example
80///
81/// If `buffer` was created with [`BufferUsages::MAP_WRITE`], we could fill it
82/// with `f32` values like this:
83///
84/// ```
85/// # #[cfg(feature = "noop")]
86/// # let (device, _queue) = wgpu::Device::noop(&wgpu::DeviceDescriptor::default());
87/// # #[cfg(not(feature = "noop"))]
88/// # let device: wgpu::Device = { return; };
89/// #
90/// # let buffer = device.create_buffer(&wgpu::BufferDescriptor {
91/// # label: None,
92/// # size: 400,
93/// # usage: wgpu::BufferUsages::MAP_WRITE,
94/// # mapped_at_creation: false,
95/// # });
96/// let capturable = buffer.clone();
97/// buffer.map_async(wgpu::MapMode::Write, .., move |result| {
98/// if result.is_ok() {
99/// let mut view = capturable.get_mapped_range_mut(..);
100/// let floats: &mut [f32] = bytemuck::cast_slice_mut(&mut view);
101/// floats.fill(42.0);
102/// drop(view);
103/// capturable.unmap();
104/// }
105/// });
106/// ```
107///
108/// This code takes the following steps:
109///
110/// - First, it makes a cloned handle to the buffer for capture by
111/// the callback passed to [`map_async`]. Since a [`map_async`] callback may be
112/// invoked from another thread, interaction between the callback and the
113/// thread calling [`map_async`] generally requires some sort of shared heap
114/// data like this. In real code, there might be an [`Arc`] to some larger
115/// structure that itself owns `buffer`.
116///
117/// - Then, it calls [`Buffer::slice`] to make a [`BufferSlice`] referring to
118/// the buffer's entire contents.
119///
120/// - Next, it calls [`BufferSlice::map_async`] to request that the bytes to
121/// which the slice refers be made accessible to the CPU ("mapped"). This may
122/// entail waiting for previously enqueued operations on `buffer` to finish.
123/// Although [`map_async`] itself always returns immediately, it saves the
124/// callback function to be invoked later.
125///
126/// - When some later call to [`Device::poll`] or [`Instance::poll_all`] (not
127/// shown in this example) determines that the buffer is mapped and ready for
128/// the CPU to use, it invokes the callback function.
129///
130/// - The callback function calls [`Buffer::slice`] and then
131/// [`BufferSlice::get_mapped_range_mut`] to obtain a [`BufferViewMut`], which
132/// dereferences to a `&mut [u8]` slice referring to the buffer's bytes.
133///
134/// - It then uses the [`bytemuck`] crate to turn the `&mut [u8]` into a `&mut
135/// [f32]`, and calls the slice [`fill`] method to fill the buffer with a
136/// useful value.
137///
138/// - Finally, the callback drops the view and calls [`Buffer::unmap`] to unmap
139/// the buffer. In real code, the callback would also need to do some sort of
140/// synchronization to let the rest of the program know that it has completed
141/// its work.
142///
143/// If using [`map_async`] directly is awkward, you may find it more convenient to
144/// use [`Queue::write_buffer`] and [`util::DownloadBuffer::read_buffer`].
145/// However, those each have their own tradeoffs; the asynchronous nature of GPU
146/// execution makes it hard to avoid friction altogether.
147///
148/// [`Arc`]: std::sync::Arc
149/// [`map_async`]: BufferSlice::map_async
150/// [`bytemuck`]: https://crates.io/crates/bytemuck
151/// [`fill`]: slice::fill
152///
153/// ## Mapping buffers on the web
154///
155/// When compiled to WebAssembly and running in a browser content process,
156/// `wgpu` implements its API in terms of the browser's WebGPU implementation.
157/// In this context, `wgpu` is further isolated from the GPU:
158///
159/// - Depending on the browser's WebGPU implementation, mapping and unmapping
160/// buffers probably entails copies between WebAssembly linear memory and the
161/// graphics driver's buffers.
162///
163/// - All modern web browsers isolate web content in its own sandboxed process,
164/// which can only interact with the GPU via interprocess communication (IPC).
165/// Although most browsers' IPC systems use shared memory for large data
166/// transfers, there will still probably need to be copies into and out of the
167/// shared memory buffers.
168///
169/// All of these copies contribute to the cost of buffer mapping in this
170/// configuration.
171///
172/// [`usage`]: BufferDescriptor::usage
173/// [mac]: BufferDescriptor::mapped_at_creation
174/// [`MAP_READ`]: BufferUsages::MAP_READ
175/// [`MAP_WRITE`]: BufferUsages::MAP_WRITE
176#[derive(Debug, Clone)]
177pub struct Buffer {
178 pub(crate) inner: dispatch::DispatchBuffer,
179 pub(crate) map_context: Arc<Mutex<MapContext>>,
180 pub(crate) size: wgt::BufferAddress,
181 pub(crate) usage: BufferUsages,
182 // Todo: missing map_state https://www.w3.org/TR/webgpu/#dom-gpubuffer-mapstate
183}
184#[cfg(send_sync)]
185static_assertions::assert_impl_all!(Buffer: Send, Sync);
186
187crate::cmp::impl_eq_ord_hash_proxy!(Buffer => .inner);
188
189impl Buffer {
190 /// Return the binding view of the entire buffer.
191 pub fn as_entire_binding(&self) -> BindingResource<'_> {
192 BindingResource::Buffer(self.as_entire_buffer_binding())
193 }
194
195 /// Return the binding view of the entire buffer.
196 pub fn as_entire_buffer_binding(&self) -> BufferBinding<'_> {
197 BufferBinding {
198 buffer: self,
199 offset: 0,
200 size: None,
201 }
202 }
203
204 /// Returns the inner hal Buffer using a callback. The hal buffer will be `None` if the
205 /// backend type argument does not match with this wgpu Buffer
206 ///
207 /// # Safety
208 ///
209 /// - The raw handle obtained from the hal Buffer must not be manually destroyed
210 #[cfg(wgpu_core)]
211 pub unsafe fn as_hal<A: wgc::hal_api::HalApi, F: FnOnce(Option<&A::Buffer>) -> R, R>(
212 &self,
213 hal_buffer_callback: F,
214 ) -> R {
215 if let Some(buffer) = self.inner.as_core_opt() {
216 unsafe {
217 buffer
218 .context
219 .buffer_as_hal::<A, F, R>(buffer, hal_buffer_callback)
220 }
221 } else {
222 hal_buffer_callback(None)
223 }
224 }
225
226 /// Returns a [`BufferSlice`] referring to the portion of `self`'s contents
227 /// indicated by `bounds`. Regardless of what sort of data `self` stores,
228 /// `bounds` start and end are given in bytes.
229 ///
230 /// A [`BufferSlice`] can be used to supply vertex and index data, or to map
231 /// buffer contents for access from the CPU. See the [`BufferSlice`]
232 /// documentation for details.
233 ///
234 /// The `range` argument can be half or fully unbounded: for example,
235 /// `buffer.slice(..)` refers to the entire buffer, and `buffer.slice(n..)`
236 /// refers to the portion starting at the `n`th byte and extending to the
237 /// end of the buffer.
238 ///
239 /// # Panics
240 ///
241 /// - If `bounds` is outside of the bounds of `self`.
242 /// - If `bounds` has a length less than 1.
243 pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice<'_> {
244 let (offset, size) = range_to_offset_size(bounds);
245 check_buffer_bounds(self.size, offset, size);
246 BufferSlice {
247 buffer: self,
248 offset,
249 size,
250 }
251 }
252
253 /// Unmaps the buffer from host memory.
254 ///
255 /// This terminates the effect of all previous [`map_async()`](Self::map_async) operations and
256 /// makes the buffer available for use by the GPU again.
257 pub fn unmap(&self) {
258 self.map_context.lock().reset();
259 self.inner.unmap();
260 }
261
262 /// Destroy the associated native resources as soon as possible.
263 pub fn destroy(&self) {
264 self.inner.destroy();
265 }
266
267 /// Returns the length of the buffer allocation in bytes.
268 ///
269 /// This is always equal to the `size` that was specified when creating the buffer.
270 pub fn size(&self) -> BufferAddress {
271 self.size
272 }
273
274 /// Returns the allowed usages for this `Buffer`.
275 ///
276 /// This is always equal to the `usage` that was specified when creating the buffer.
277 pub fn usage(&self) -> BufferUsages {
278 self.usage
279 }
280
281 /// Map the buffer to host (CPU) memory, making it available for reading or writing
282 /// via [`get_mapped_range()`](Self::get_mapped_range).
283 /// It is available once the `callback` is called with an [`Ok`] response.
284 ///
285 /// For the callback to complete, either `queue.submit(..)`, `instance.poll_all(..)`, or `device.poll(..)`
286 /// must be called elsewhere in the runtime, possibly integrated into an event loop or run on a separate thread.
287 ///
288 /// The callback will be called on the thread that first calls the above functions after the GPU work
289 /// has completed. There are no restrictions on the code you can run in the callback, however on native the
290 /// call to the function will not complete until the callback returns, so prefer keeping callbacks short
291 /// and used to set flags, send messages, etc.
292 ///
293 /// As long as a buffer is mapped, it is not available for use by any other commands;
294 /// at all times, either the GPU or the CPU has exclusive access to the contents of the buffer.
295 ///
296 /// This can also be performed using [`BufferSlice::map_async()`].
297 ///
298 /// # Panics
299 ///
300 /// - If the buffer is already mapped.
301 /// - If the buffer’s [`BufferUsages`] do not allow the requested [`MapMode`].
302 /// - If `bounds` is outside of the bounds of `self`.
303 /// - If `bounds` has a length less than 1.
304 /// - If the start and end of `bounds` are not be aligned to [`MAP_ALIGNMENT`].
305 pub fn map_async<S: RangeBounds<BufferAddress>>(
306 &self,
307 mode: MapMode,
308 bounds: S,
309 callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static,
310 ) {
311 self.slice(bounds).map_async(mode, callback)
312 }
313
314 /// Gain read-only access to the bytes of a [mapped] [`Buffer`].
315 ///
316 /// Returns a [`BufferView`] referring to the buffer range represented by
317 /// `self`. See the documentation for [`BufferView`] for details.
318 ///
319 /// `bounds` may be less than the bounds passed to [`Self::map_async()`],
320 /// and multiple views may be obtained and used simultaneously as long as they do not overlap.
321 ///
322 /// This can also be performed using [`BufferSlice::get_mapped_range()`].
323 ///
324 /// # Panics
325 ///
326 /// - If `bounds` is outside of the bounds of `self`.
327 /// - If `bounds` has a length less than 1.
328 /// - If the start and end of `bounds` are not aligned to [`MAP_ALIGNMENT`].
329 /// - If the buffer to which `self` refers is not currently [mapped].
330 /// - If you try to create overlapping views of a buffer, mutable or otherwise.
331 ///
332 /// [mapped]: Buffer#mapping-buffers
333 pub fn get_mapped_range<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferView<'_> {
334 self.slice(bounds).get_mapped_range()
335 }
336
337 /// Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
338 /// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will fail.
339 ///
340 /// This is useful when targeting WebGPU and you want to pass mapped data directly to js.
341 /// Unlike `get_mapped_range` which unconditionally copies mapped data into the wasm heap,
342 /// this function directly hands you the ArrayBuffer that we mapped the data into in js.
343 ///
344 /// This is only available on WebGPU, on any other backends this will return `None`.
345 ///
346 /// `bounds` may be less than the bounds passed to [`Self::map_async()`],
347 /// and multiple views may be obtained and used simultaneously as long as they do not overlap.
348 ///
349 /// This can also be performed using [`BufferSlice::get_mapped_range_as_array_buffer()`].
350 ///
351 /// # Panics
352 ///
353 /// - If `bounds` is outside of the bounds of `self`.
354 /// - If `bounds` has a length less than 1.
355 /// - If the start and end of `bounds` are not aligned to [`MAP_ALIGNMENT`].
356 #[cfg(webgpu)]
357 pub fn get_mapped_range_as_array_buffer<S: RangeBounds<BufferAddress>>(
358 &self,
359 bounds: S,
360 ) -> Option<js_sys::ArrayBuffer> {
361 self.slice(bounds).get_mapped_range_as_array_buffer()
362 }
363
364 /// Gain write access to the bytes of a [mapped] [`Buffer`].
365 ///
366 /// Returns a [`BufferViewMut`] referring to the buffer range represented by
367 /// `self`. See the documentation for [`BufferViewMut`] for more details.
368 ///
369 /// `bounds` may be less than the bounds passed to [`Self::map_async()`],
370 /// and multiple views may be obtained and used simultaneously as long as they do not overlap.
371 ///
372 /// This can also be performed using [`BufferSlice::get_mapped_range_mut()`].
373 ///
374 /// # Panics
375 ///
376 /// - If `bounds` is outside of the bounds of `self`.
377 /// - If `bounds` has a length less than 1.
378 /// - If the start and end of `bounds` are not aligned to [`MAP_ALIGNMENT`].
379 /// - If the buffer to which `self` refers is not currently [mapped].
380 /// - If you try to create overlapping views of a buffer, mutable or otherwise.
381 ///
382 /// [mapped]: Buffer#mapping-buffers
383 pub fn get_mapped_range_mut<S: RangeBounds<BufferAddress>>(
384 &self,
385 bounds: S,
386 ) -> BufferViewMut<'_> {
387 self.slice(bounds).get_mapped_range_mut()
388 }
389}
390
391/// A slice of a [`Buffer`], to be mapped, used for vertex or index data, or the like.
392///
393/// You can create a `BufferSlice` by calling [`Buffer::slice`]:
394///
395/// ```no_run
396/// # let buffer: wgpu::Buffer = todo!();
397/// let slice = buffer.slice(10..20);
398/// ```
399///
400/// This returns a slice referring to the second ten bytes of `buffer`. To get a
401/// slice of the entire `Buffer`:
402///
403/// ```no_run
404/// # let buffer: wgpu::Buffer = todo!();
405/// let whole_buffer_slice = buffer.slice(..);
406/// ```
407///
408/// You can pass buffer slices to methods like [`RenderPass::set_vertex_buffer`]
409/// and [`RenderPass::set_index_buffer`] to indicate which portion of the buffer
410/// a draw call should consult. You can also convert it to a [`BufferBinding`]
411/// with `.into()`.
412///
413/// To access the slice's contents on the CPU, you must first [map] the buffer,
414/// and then call [`BufferSlice::get_mapped_range`] or
415/// [`BufferSlice::get_mapped_range_mut`] to obtain a view of the slice's
416/// contents. See the documentation on [mapping][map] for more details,
417/// including example code.
418///
419/// Unlike a Rust shared slice `&[T]`, whose existence guarantees that
420/// nobody else is modifying the `T` values to which it refers, a
421/// [`BufferSlice`] doesn't guarantee that the buffer's contents aren't
422/// changing. You can still record and submit commands operating on the
423/// buffer while holding a [`BufferSlice`]. A [`BufferSlice`] simply
424/// represents a certain range of the buffer's bytes.
425///
426/// The `BufferSlice` type is unique to the Rust API of `wgpu`. In the WebGPU
427/// specification, an offset and size are specified as arguments to each call
428/// working with the [`Buffer`], instead.
429///
430/// [map]: Buffer#mapping-buffers
431#[derive(Copy, Clone, Debug, PartialEq)]
432pub struct BufferSlice<'a> {
433 pub(crate) buffer: &'a Buffer,
434 pub(crate) offset: BufferAddress,
435 pub(crate) size: Option<BufferSize>,
436}
437#[cfg(send_sync)]
438static_assertions::assert_impl_all!(BufferSlice<'_>: Send, Sync);
439
440impl<'a> BufferSlice<'a> {
441 /// Return another [`BufferSlice`] referring to the portion of `self`'s contents
442 /// indicated by `bounds`.
443 ///
444 /// The `range` argument can be half or fully unbounded: for example,
445 /// `buffer.slice(..)` refers to the entire buffer, and `buffer.slice(n..)`
446 /// refers to the portion starting at the `n`th byte and extending to the
447 /// end of the buffer.
448 ///
449 /// # Panics
450 ///
451 /// - If `bounds` is outside of the bounds of `self`.
452 /// - If `bounds` has a length less than 1.
453 pub fn slice<S: RangeBounds<BufferAddress>>(&self, bounds: S) -> BufferSlice<'a> {
454 let (offset, size) = range_to_offset_size(bounds);
455 check_buffer_bounds(
456 match self.size {
457 Some(size) => size.get(),
458 None => self.buffer.size(),
459 },
460 offset,
461 size,
462 );
463 BufferSlice {
464 buffer: self.buffer,
465 offset: self.offset + offset, // check_buffer_bounds ensures this does not overflow
466 size: size.or(self.size), // check_buffer_bounds ensures this is essentially min()
467 }
468 }
469
470 /// Map the buffer to host (CPU) memory, making it available for reading or writing
471 /// via [`get_mapped_range()`](Self::get_mapped_range).
472 /// It is available once the `callback` is called with an [`Ok`] response.
473 ///
474 /// For the callback to complete, either `queue.submit(..)`, `instance.poll_all(..)`, or `device.poll(..)`
475 /// must be called elsewhere in the runtime, possibly integrated into an event loop or run on a separate thread.
476 ///
477 /// The callback will be called on the thread that first calls the above functions after the GPU work
478 /// has completed. There are no restrictions on the code you can run in the callback, however on native the
479 /// call to the function will not complete until the callback returns, so prefer keeping callbacks short
480 /// and used to set flags, send messages, etc.
481 ///
482 /// As long as a buffer is mapped, it is not available for use by any other commands;
483 /// at all times, either the GPU or the CPU has exclusive access to the contents of the buffer.
484 ///
485 /// This can also be performed using [`Buffer::map_async()`].
486 ///
487 /// # Panics
488 ///
489 /// - If the buffer is already mapped.
490 /// - If the buffer’s [`BufferUsages`] do not allow the requested [`MapMode`].
491 /// - If the endpoints of this slice are not aligned to [`MAP_ALIGNMENT`] within the buffer.
492 pub fn map_async(
493 &self,
494 mode: MapMode,
495 callback: impl FnOnce(Result<(), BufferAsyncError>) + WasmNotSend + 'static,
496 ) {
497 let mut mc = self.buffer.map_context.lock();
498 assert_eq!(mc.initial_range, 0..0, "Buffer is already mapped");
499 let end = match self.size {
500 Some(s) => self.offset + s.get(),
501 None => mc.total_size,
502 };
503 mc.initial_range = self.offset..end;
504
505 self.buffer
506 .inner
507 .map_async(mode, self.offset..end, Box::new(callback));
508 }
509
510 /// Gain read-only access to the bytes of a [mapped] [`Buffer`].
511 ///
512 /// Returns a [`BufferView`] referring to the buffer range represented by
513 /// `self`. See the documentation for [`BufferView`] for details.
514 ///
515 /// Multiple views may be obtained and used simultaneously as long as they are from
516 /// non-overlapping slices.
517 ///
518 /// This can also be performed using [`Buffer::get_mapped_range()`].
519 ///
520 /// # Panics
521 ///
522 /// - If the endpoints of this slice are not aligned to [`MAP_ALIGNMENT`] within the buffer.
523 /// - If the buffer to which `self` refers is not currently [mapped].
524 /// - If you try to create overlapping views of a buffer, mutable or otherwise.
525 ///
526 /// [mapped]: Buffer#mapping-buffers
527 pub fn get_mapped_range(&self) -> BufferView<'a> {
528 let end = self.buffer.map_context.lock().add(self.offset, self.size);
529 let range = self.buffer.inner.get_mapped_range(self.offset..end);
530 BufferView {
531 slice: *self,
532 inner: range,
533 }
534 }
535
536 /// Synchronously and immediately map a buffer for reading. If the buffer is not immediately mappable
537 /// through [`BufferDescriptor::mapped_at_creation`] or [`BufferSlice::map_async`], will fail.
538 ///
539 /// This is useful when targeting WebGPU and you want to pass mapped data directly to js.
540 /// Unlike `get_mapped_range` which unconditionally copies mapped data into the wasm heap,
541 /// this function directly hands you the ArrayBuffer that we mapped the data into in js.
542 ///
543 /// This is only available on WebGPU, on any other backends this will return `None`.
544 ///
545 /// Multiple views may be obtained and used simultaneously as long as they are from
546 /// non-overlapping slices.
547 ///
548 /// This can also be performed using [`Buffer::get_mapped_range_as_array_buffer()`].
549 ///
550 /// # Panics
551 ///
552 /// - If the endpoints of this slice are not aligned to [`MAP_ALIGNMENT`] within the buffer.
553 #[cfg(webgpu)]
554 pub fn get_mapped_range_as_array_buffer(&self) -> Option<js_sys::ArrayBuffer> {
555 let end = self.buffer.map_context.lock().add(self.offset, self.size);
556
557 self.buffer
558 .inner
559 .get_mapped_range_as_array_buffer(self.offset..end)
560 }
561
562 /// Gain write access to the bytes of a [mapped] [`Buffer`].
563 ///
564 /// Returns a [`BufferViewMut`] referring to the buffer range represented by
565 /// `self`. See the documentation for [`BufferViewMut`] for more details.
566 ///
567 /// Multiple views may be obtained and used simultaneously as long as they are from
568 /// non-overlapping slices.
569 ///
570 /// This can also be performed using [`Buffer::get_mapped_range_mut()`].
571 ///
572 /// # Panics
573 ///
574 /// - If the endpoints of this slice are not aligned to [`MAP_ALIGNMENT`].
575 /// - If the buffer to which `self` refers is not currently [mapped].
576 /// - If you try to create overlapping views of a buffer, mutable or otherwise.
577 ///
578 /// [mapped]: Buffer#mapping-buffers
579 pub fn get_mapped_range_mut(&self) -> BufferViewMut<'a> {
580 let end = self.buffer.map_context.lock().add(self.offset, self.size);
581 let range = self.buffer.inner.get_mapped_range(self.offset..end);
582 BufferViewMut {
583 slice: *self,
584 inner: range,
585 readable: self.buffer.usage.contains(BufferUsages::MAP_READ),
586 }
587 }
588
589 /// Returns the buffer this is a slice of.
590 ///
591 /// You should usually not need to call this, and if you received the buffer from code you
592 /// do not control, you should refrain from accessing the buffer outside the bounds of the
593 /// slice. Nevertheless, it’s possible to get this access, so this method makes it simple.
594 pub fn buffer(&self) -> &'a Buffer {
595 self.buffer
596 }
597
598 /// Returns the offset in [`Self::buffer()`] this slice starts at.
599 pub fn offset(&self) -> BufferAddress {
600 self.offset
601 }
602
603 /// Returns the size of this slice.
604 pub fn size(&self) -> BufferSize {
605 self.size.unwrap_or_else(|| {
606 (|| BufferSize::new(self.buffer.size().checked_sub(self.offset)?))()
607 .expect("can't happen: slice has incorrect size for its buffer")
608 })
609 }
610}
611
612impl<'a> From<BufferSlice<'a>> for crate::BufferBinding<'a> {
613 /// Convert a [`BufferSlice`] to an equivalent [`BufferBinding`],
614 /// provided that it will be used without a dynamic offset.
615 fn from(value: BufferSlice<'a>) -> Self {
616 BufferBinding {
617 buffer: value.buffer,
618 offset: value.offset,
619 size: value.size,
620 }
621 }
622}
623
624impl<'a> From<BufferSlice<'a>> for crate::BindingResource<'a> {
625 /// Convert a [`BufferSlice`] to an equivalent [`BindingResource::Buffer`],
626 /// provided that it will be used without a dynamic offset.
627 fn from(value: BufferSlice<'a>) -> Self {
628 crate::BindingResource::Buffer(crate::BufferBinding::from(value))
629 }
630}
631
632/// The mapped portion of a buffer, if any, and its outstanding views.
633///
634/// This ensures that views fall within the mapped range and don't overlap, and
635/// also takes care of turning `Option<BufferSize>` sizes into actual buffer
636/// offsets.
637#[derive(Debug)]
638pub(crate) struct MapContext {
639 /// The overall size of the buffer.
640 ///
641 /// This is just a convenient copy of [`Buffer::size`].
642 pub(crate) total_size: BufferAddress,
643
644 /// The range of the buffer that is mapped.
645 ///
646 /// This is `0..0` if the buffer is not mapped. This becomes non-empty when
647 /// the buffer is mapped at creation time, and when you call `map_async` on
648 /// some [`BufferSlice`] (so technically, it indicates the portion that is
649 /// *or has been requested to be* mapped.)
650 ///
651 /// All [`BufferView`]s and [`BufferViewMut`]s must fall within this range.
652 pub(crate) initial_range: Range<BufferAddress>,
653
654 /// The ranges covered by all outstanding [`BufferView`]s and
655 /// [`BufferViewMut`]s. These are non-overlapping, and are all contained
656 /// within `initial_range`.
657 sub_ranges: Vec<Range<BufferAddress>>,
658}
659
660impl MapContext {
661 pub(crate) fn new(total_size: BufferAddress) -> Self {
662 Self {
663 total_size,
664 initial_range: 0..0,
665 sub_ranges: Vec::new(),
666 }
667 }
668
669 /// Record that the buffer is no longer mapped.
670 fn reset(&mut self) {
671 self.initial_range = 0..0;
672
673 assert!(
674 self.sub_ranges.is_empty(),
675 "You cannot unmap a buffer that still has accessible mapped views"
676 );
677 }
678
679 /// Record that the `size` bytes of the buffer at `offset` are now viewed.
680 ///
681 /// Return the byte offset within the buffer of the end of the viewed range.
682 ///
683 /// # Panics
684 ///
685 /// This panics if the given range overlaps with any existing range.
686 fn add(&mut self, offset: BufferAddress, size: Option<BufferSize>) -> BufferAddress {
687 let end = match size {
688 Some(s) => offset + s.get(),
689 None => self.initial_range.end,
690 };
691 assert!(self.initial_range.start <= offset && end <= self.initial_range.end);
692 // This check is essential for avoiding undefined behavior: it is the
693 // only thing that ensures that `&mut` references to the buffer's
694 // contents don't alias anything else.
695 for sub in self.sub_ranges.iter() {
696 assert!(
697 end <= sub.start || offset >= sub.end,
698 "Intersecting map range with {sub:?}"
699 );
700 }
701 self.sub_ranges.push(offset..end);
702 end
703 }
704
705 /// Record that the `size` bytes of the buffer at `offset` are no longer viewed.
706 ///
707 /// # Panics
708 ///
709 /// This panics if the given range does not exactly match one previously
710 /// passed to [`add`].
711 ///
712 /// [`add]`: MapContext::add
713 fn remove(&mut self, offset: BufferAddress, size: Option<BufferSize>) {
714 let end = match size {
715 Some(s) => offset + s.get(),
716 None => self.initial_range.end,
717 };
718
719 let index = self
720 .sub_ranges
721 .iter()
722 .position(|r| *r == (offset..end))
723 .expect("unable to remove range from map context");
724 self.sub_ranges.swap_remove(index);
725 }
726}
727
728/// Describes a [`Buffer`].
729///
730/// For use with [`Device::create_buffer`].
731///
732/// Corresponds to [WebGPU `GPUBufferDescriptor`](
733/// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferdescriptor).
734pub type BufferDescriptor<'a> = wgt::BufferDescriptor<Label<'a>>;
735static_assertions::assert_impl_all!(BufferDescriptor<'_>: Send, Sync);
736
737/// Error occurred when trying to async map a buffer.
738#[derive(Clone, PartialEq, Eq, Debug)]
739pub struct BufferAsyncError;
740static_assertions::assert_impl_all!(BufferAsyncError: Send, Sync);
741
742impl fmt::Display for BufferAsyncError {
743 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
744 write!(f, "Error occurred when trying to async map a buffer")
745 }
746}
747
748impl error::Error for BufferAsyncError {}
749
750/// Type of buffer mapping.
751#[derive(Debug, Clone, Copy, Eq, PartialEq)]
752pub enum MapMode {
753 /// Map only for reading
754 Read,
755 /// Map only for writing
756 Write,
757}
758static_assertions::assert_impl_all!(MapMode: Send, Sync);
759
760/// A read-only view of a mapped buffer's bytes.
761///
762/// To get a `BufferView`, first [map] the buffer, and then
763/// call `buffer.slice(range).get_mapped_range()`.
764///
765/// `BufferView` dereferences to `&[u8]`, so you can use all the usual Rust
766/// slice methods to access the buffer's contents. It also implements
767/// `AsRef<[u8]>`, if that's more convenient.
768///
769/// Before the buffer can be unmapped, all `BufferView`s observing it
770/// must be dropped. Otherwise, the call to [`Buffer::unmap`] will panic.
771///
772/// For example code, see the documentation on [mapping buffers][map].
773///
774/// [map]: Buffer#mapping-buffers
775/// [`map_async`]: BufferSlice::map_async
776#[derive(Debug)]
777pub struct BufferView<'a> {
778 slice: BufferSlice<'a>,
779 inner: dispatch::DispatchBufferMappedRange,
780}
781
782impl core::ops::Deref for BufferView<'_> {
783 type Target = [u8];
784
785 #[inline]
786 fn deref(&self) -> &[u8] {
787 self.inner.slice()
788 }
789}
790
791impl AsRef<[u8]> for BufferView<'_> {
792 #[inline]
793 fn as_ref(&self) -> &[u8] {
794 self.inner.slice()
795 }
796}
797
798/// A write-only view of a mapped buffer's bytes.
799///
800/// To get a `BufferViewMut`, first [map] the buffer, and then
801/// call `buffer.slice(range).get_mapped_range_mut()`.
802///
803/// `BufferViewMut` dereferences to `&mut [u8]`, so you can use all the usual
804/// Rust slice methods to access the buffer's contents. It also implements
805/// `AsMut<[u8]>`, if that's more convenient.
806///
807/// It is possible to read the buffer using this view, but doing so is not
808/// recommended, as it is likely to be slow.
809///
810/// Before the buffer can be unmapped, all `BufferViewMut`s observing it
811/// must be dropped. Otherwise, the call to [`Buffer::unmap`] will panic.
812///
813/// For example code, see the documentation on [mapping buffers][map].
814///
815/// [map]: Buffer#mapping-buffers
816#[derive(Debug)]
817pub struct BufferViewMut<'a> {
818 slice: BufferSlice<'a>,
819 inner: dispatch::DispatchBufferMappedRange,
820 readable: bool,
821}
822
823impl AsMut<[u8]> for BufferViewMut<'_> {
824 #[inline]
825 fn as_mut(&mut self) -> &mut [u8] {
826 self.inner.slice_mut()
827 }
828}
829
830impl Deref for BufferViewMut<'_> {
831 type Target = [u8];
832
833 fn deref(&self) -> &Self::Target {
834 if !self.readable {
835 log::warn!("Reading from a BufferViewMut is slow and not recommended.");
836 }
837
838 self.inner.slice()
839 }
840}
841
842impl DerefMut for BufferViewMut<'_> {
843 fn deref_mut(&mut self) -> &mut Self::Target {
844 self.inner.slice_mut()
845 }
846}
847
848impl Drop for BufferView<'_> {
849 fn drop(&mut self) {
850 self.slice
851 .buffer
852 .map_context
853 .lock()
854 .remove(self.slice.offset, self.slice.size);
855 }
856}
857
858impl Drop for BufferViewMut<'_> {
859 fn drop(&mut self) {
860 self.slice
861 .buffer
862 .map_context
863 .lock()
864 .remove(self.slice.offset, self.slice.size);
865 }
866}
867
868fn check_buffer_bounds(
869 buffer_size: BufferAddress,
870 offset: BufferAddress,
871 size: Option<BufferSize>,
872) {
873 // A slice of length 0 is invalid, so the offset must not be equal to or greater than the buffer size.
874 if offset >= buffer_size {
875 panic!(
876 "slice offset {} is out of range for buffer of size {}",
877 offset, buffer_size
878 );
879 }
880
881 if let Some(size) = size {
882 // Detect integer overflow.
883 let end = offset.checked_add(size.get());
884 if end.is_none_or(|end| end > buffer_size) {
885 panic!(
886 "slice offset {} size {} is out of range for buffer of size {}",
887 offset, size, buffer_size
888 );
889 }
890 }
891}
892
893fn range_to_offset_size<S: RangeBounds<BufferAddress>>(
894 bounds: S,
895) -> (BufferAddress, Option<BufferSize>) {
896 let offset = match bounds.start_bound() {
897 Bound::Included(&bound) => bound,
898 Bound::Excluded(&bound) => bound + 1,
899 Bound::Unbounded => 0,
900 };
901 let size = match bounds.end_bound() {
902 Bound::Included(&bound) => Some(bound + 1 - offset),
903 Bound::Excluded(&bound) => Some(bound - offset),
904 Bound::Unbounded => None,
905 }
906 .map(|size| BufferSize::new(size).expect("Buffer slices can not be empty"));
907
908 (offset, size)
909}
910
911#[cfg(test)]
912mod tests {
913 use super::{check_buffer_bounds, range_to_offset_size, BufferSize};
914
915 #[test]
916 fn range_to_offset_size_works() {
917 assert_eq!(range_to_offset_size(0..2), (0, BufferSize::new(2)));
918 assert_eq!(range_to_offset_size(2..5), (2, BufferSize::new(3)));
919 assert_eq!(range_to_offset_size(..), (0, None));
920 assert_eq!(range_to_offset_size(21..), (21, None));
921 assert_eq!(range_to_offset_size(0..), (0, None));
922 assert_eq!(range_to_offset_size(..21), (0, BufferSize::new(21)));
923 }
924
925 #[test]
926 #[should_panic]
927 fn range_to_offset_size_panics_for_empty_range() {
928 range_to_offset_size(123..123);
929 }
930
931 #[test]
932 #[should_panic]
933 fn range_to_offset_size_panics_for_unbounded_empty_range() {
934 range_to_offset_size(..0);
935 }
936
937 #[test]
938 #[should_panic]
939 fn check_buffer_bounds_panics_for_offset_at_size() {
940 check_buffer_bounds(100, 100, None);
941 }
942
943 #[test]
944 fn check_buffer_bounds_works_for_end_in_range() {
945 check_buffer_bounds(200, 100, BufferSize::new(50));
946 check_buffer_bounds(200, 100, BufferSize::new(100));
947 check_buffer_bounds(u64::MAX, u64::MAX - 100, BufferSize::new(100));
948 check_buffer_bounds(u64::MAX, 0, BufferSize::new(u64::MAX));
949 check_buffer_bounds(u64::MAX, 1, BufferSize::new(u64::MAX - 1));
950 }
951
952 #[test]
953 #[should_panic]
954 fn check_buffer_bounds_panics_for_end_over_size() {
955 check_buffer_bounds(200, 100, BufferSize::new(101));
956 }
957
958 #[test]
959 #[should_panic]
960 fn check_buffer_bounds_panics_for_end_wraparound() {
961 check_buffer_bounds(u64::MAX, 1, BufferSize::new(u64::MAX));
962 }
963}