Skip to main content

wgpu_hal/noop/
buffer.rs

1use alloc::vec::Vec;
2use core::{cell::UnsafeCell, ops::Range, ptr};
3
4use wgpu_sync::Arc;
5
6#[derive(Clone, Debug)]
7pub struct Buffer {
8    /// This data is potentially accessed mutably in arbitrary non-overlapping slices,
9    /// so we must store it in `UnsafeCell` to avoid making any too-strong no-aliasing claims.
10    storage: Arc<UnsafeCell<[u8]>>,
11}
12
13/// SAFETY:
14/// This shared mutable data will not be accessed in a way which causes data races;
15/// the obligation to do so is on the caller of the HAL API.
16/// For safe code, `wgpu-core` validation manages appropriate access.
17unsafe impl Send for Buffer {}
18unsafe impl Sync for Buffer {}
19
20impl Buffer {
21    pub(super) fn new(
22        desc: &crate::BufferDescriptor,
23    ) -> Result<(Self, wgt::BufferAddress), crate::DeviceError> {
24        let &crate::BufferDescriptor {
25            label: _,
26            size,
27            usage: _,
28            memory_flags: _,
29        } = desc;
30
31        let size = usize::try_from(size).map_err(|_| crate::DeviceError::OutOfMemory)?;
32
33        let mut vector: Vec<u8> = Vec::new();
34        vector
35            .try_reserve_exact(size)
36            .map_err(|_| crate::DeviceError::OutOfMemory)?;
37        vector.resize(size, 0);
38        let storage: Arc<[u8]> = Arc::from(vector);
39        debug_assert_eq!(storage.len(), size);
40
41        // SAFETY: `UnsafeCell<[u8]>` and `[u8]` have the same layout.
42        // This is just adding a wrapper type without changing any layout,
43        // because there is not currently a safe language/`std` way to accomplish this.
44        let storage: Arc<UnsafeCell<[u8]>> =
45            unsafe { Arc::from_raw(Arc::into_raw(storage) as *mut UnsafeCell<[u8]>) };
46
47        Ok((Buffer { storage }, desc.size))
48    }
49
50    /// Returns a pointer to the memory owned by this buffer within the given `range`.
51    ///
52    /// This may be used to create any number of simultaneous pointers;
53    /// aliasing is only a concern when actually reading, writing, or converting the pointer
54    /// to a reference.
55    pub(super) fn get_slice_ptr(&self, range: crate::MemoryRange) -> *mut [u8] {
56        let base_ptr = self.storage.get();
57        let range = range_to_usize(range, self.storage.get().len());
58
59        // We must obtain a slice pointer without ever creating a slice reference
60        // that could alias with another slice.
61        ptr::slice_from_raw_parts_mut(
62            // SAFETY: `range_to_usize` bounds checks this addition.
63            unsafe { base_ptr.cast::<u8>().add(range.start) },
64            range.len(),
65        )
66    }
67}
68
69/// Convert a [`crate::MemoryRange`] to `Range<usize>` and bounds check it.
70fn range_to_usize(range: crate::MemoryRange, upper_bound: usize) -> Range<usize> {
71    // Note: these assertions should be impossible to trigger from safe code.
72    // We're doing them anyway since this entire backend is for testing
73    // (except for when it is an unused placeholder)
74    let start = usize::try_from(range.start).expect("range too large");
75    let end = usize::try_from(range.end).expect("range too large");
76    assert!(start <= end && end <= upper_bound, "range out of bounds");
77    start..end
78}