use {
crate::{memory::Memory, Size},
hal::{device::Device as _, Backend},
std::{iter, ops::Range, ptr::NonNull, slice},
};
#[derive(Debug)]
struct Flush<'a, B: Backend> {
device: &'a B::Device,
memory: &'a B::Memory,
segment: hal::memory::Segment,
}
#[derive(Debug)]
pub struct Writer<'a, 'b, T, B: Backend> {
pub slice: &'a mut [T],
flush: Option<Flush<'b, B>>,
}
impl<T, B: Backend> Writer<'_, '_, T, B> {
pub fn forget(mut self) -> (*mut T, Option<hal::memory::Segment>) {
(
self.slice.as_mut_ptr(),
self.flush.take().map(|f| f.segment),
)
}
}
impl<'a, 'b, T, B: Backend> Drop for Writer<'a, 'b, T, B> {
fn drop(&mut self) {
if let Some(f) = self.flush.take() {
unsafe {
f.device
.flush_mapped_memory_ranges(iter::once((f.memory, f.segment)))
.expect("Should flush successfully")
};
}
}
}
#[derive(Debug)]
pub struct MappedRange<'a, B: Backend> {
memory: &'a Memory<B>,
ptr: NonNull<u8>,
mapping_range: Range<Size>,
requested_range: Range<Size>,
}
impl<'a, B: Backend> MappedRange<'a, B> {
pub(crate) unsafe fn from_raw(
memory: &'a Memory<B>,
ptr: *mut u8,
mapping_range: Range<Size>,
requested_range: Range<Size>,
) -> Self {
debug_assert!(
mapping_range.start < mapping_range.end,
"Memory mapping region must have valid size"
);
debug_assert!(
requested_range.start < requested_range.end,
"Memory mapping region must have valid size"
);
match memory.non_coherent_atom_size {
Some(atom) => {
debug_assert_eq!((mapping_range.start % atom.get(), mapping_range.end % atom.get()), (0, 0),
"Bounds of non-coherent memory mapping ranges must be multiple of `Limits::non_coherent_atom_size`",
);
debug_assert!(
crate::is_sub_range(&requested_range, &mapping_range),
"Requested {:?} must be sub-range of mapping {:?}",
requested_range,
mapping_range,
);
}
None => {
debug_assert_eq!(mapping_range, requested_range);
}
};
MappedRange {
ptr: NonNull::new_unchecked(ptr),
mapping_range,
requested_range,
memory,
}
}
pub fn ptr(&self) -> NonNull<u8> {
let offset = (self.requested_range.start - self.mapping_range.start) as isize;
unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }
}
pub fn range(&self) -> Range<Size> {
self.requested_range.clone()
}
pub fn is_coherent(&self) -> bool {
self.memory.non_coherent_atom_size.is_none()
}
pub unsafe fn read<'b, T>(
&'b mut self,
device: &B::Device,
segment: hal::memory::Segment,
) -> Result<&'b [T], hal::device::MapError>
where
'a: 'b,
T: Copy,
{
let sub_range = crate::segment_to_sub_range(segment, &self.requested_range)?;
if let Some(atom) = self.memory.non_coherent_atom_size {
let aligned_range = crate::align_range(&sub_range, atom);
let segment = hal::memory::Segment {
offset: aligned_range.start,
size: Some(aligned_range.end - aligned_range.start),
};
device.invalidate_mapped_memory_ranges(iter::once((self.memory.raw(), segment)))?;
}
let ptr = self
.ptr
.as_ptr()
.offset((sub_range.start - self.mapping_range.start) as isize);
let size = (sub_range.end - sub_range.start) as usize;
let (_pre, slice, _post) = slice::from_raw_parts(ptr, size).align_to();
Ok(slice)
}
pub unsafe fn write<'b, T: 'b>(
&'b mut self,
device: &'b B::Device,
segment: hal::memory::Segment,
) -> Result<Writer<'a, 'b, T, B>, hal::device::MapError>
where
'a: 'b,
T: Copy,
{
let sub_range = crate::segment_to_sub_range(segment, &self.requested_range)?;
let ptr = self
.ptr
.as_ptr()
.offset((sub_range.start - self.mapping_range.start) as isize);
let size = (sub_range.end - sub_range.start) as usize;
let (_pre, slice, _post) = slice::from_raw_parts_mut(ptr, size).align_to_mut();
let memory = self.memory.raw();
let flush = self.memory.non_coherent_atom_size.map(|atom| Flush {
device,
memory,
segment: {
let range = crate::align_range(&sub_range, atom);
hal::memory::Segment {
offset: range.start,
size: Some(range.end - range.start),
}
},
});
Ok(Writer { slice, flush })
}
}