mod range;
pub(crate) mod write;
use {
crate::{memory::Memory, util::fits_usize},
gfx_hal::{Backend, Device as _},
std::{ops::Range, ptr::NonNull},
};
pub(crate) use self::range::{
mapped_fitting_range, mapped_slice, mapped_slice_mut, mapped_sub_range,
};
use self::write::{Write, WriteCoherent, WriteFlush};
#[derive(Clone, Copy, Debug)]
pub struct NonCoherent;
#[derive(Clone, Copy, Debug)]
pub struct Coherent;
#[derive(Clone, Copy, Debug)]
pub struct MaybeCoherent(bool);
#[derive(Debug)]
pub struct MappedRange<'a, B: Backend, C = MaybeCoherent> {
memory: &'a Memory<B>,
ptr: NonNull<u8>,
range: Range<u64>,
coherent: C,
}
impl<'a, B> MappedRange<'a, B>
where
B: Backend,
{
pub unsafe fn from_raw(memory: &'a Memory<B>, ptr: NonNull<u8>, range: Range<u64>) -> Self {
assert!(
range.start < range.end,
"Memory mapping region must have valid size"
);
MappedRange {
ptr,
range,
memory,
coherent: MaybeCoherent(memory.host_coherent()),
}
}
pub fn ptr(&self) -> NonNull<u8> {
self.ptr
}
pub fn range(&self) -> Range<u64> {
self.range.clone()
}
pub unsafe fn read<'b, T>(
&'b mut self,
device: &B::Device,
range: Range<u64>,
) -> Result<&'b [T], gfx_hal::mapping::Error>
where
'a: 'b,
T: Copy,
{
assert!(
range.start < range.end,
"Memory mapping region must have valid size"
);
assert!(
fits_usize(range.end - range.start),
"Range length must fit in usize"
);
let (ptr, range) = mapped_sub_range(self.ptr, self.range.clone(), range)
.ok_or_else(|| gfx_hal::mapping::Error::OutOfBounds)?;
let size = (range.end - range.start) as usize;
if self.coherent.0 {
device
.invalidate_mapped_memory_ranges(Some((self.memory.raw(), self.range.clone())))?;
}
let slice = mapped_slice::<T>(ptr, size);
Ok(slice)
}
pub unsafe fn write<'b, T: 'b>(
&'b mut self,
device: &'b B::Device,
range: Range<u64>,
) -> Result<impl Write<T> + 'b, gfx_hal::mapping::Error>
where
'a: 'b,
T: Copy,
{
assert!(
range.start < range.end,
"Memory mapping region must have valid size"
);
assert!(
fits_usize(range.end - range.start),
"Range length must fit in usize"
);
let (ptr, range) = mapped_sub_range(self.ptr, self.range.clone(), range)
.ok_or_else(|| gfx_hal::mapping::Error::OutOfBounds)?;
let size = (range.end - range.start) as usize;
if !self.coherent.0 {
device
.invalidate_mapped_memory_ranges(Some((self.memory.raw(), self.range.clone())))?;
}
let slice = mapped_slice_mut::<T>(ptr, size);
let ref memory = self.memory;
Ok(WriteFlush {
slice,
flush: if !self.coherent.0 {
Some(move || {
device
.flush_mapped_memory_ranges(Some((memory.raw(), range)))
.expect("Should flush successfully");
})
} else {
None
},
})
}
pub fn coherent(self) -> Result<MappedRange<'a, B, Coherent>, MappedRange<'a, B, NonCoherent>> {
if self.coherent.0 {
Ok(MappedRange {
memory: self.memory,
ptr: self.ptr,
range: self.range,
coherent: Coherent,
})
} else {
Err(MappedRange {
memory: self.memory,
ptr: self.ptr,
range: self.range,
coherent: NonCoherent,
})
}
}
}
impl<'a, B> From<MappedRange<'a, B, Coherent>> for MappedRange<'a, B>
where
B: Backend,
{
fn from(range: MappedRange<'a, B, Coherent>) -> Self {
MappedRange {
memory: range.memory,
ptr: range.ptr,
range: range.range,
coherent: MaybeCoherent(true),
}
}
}
impl<'a, B> From<MappedRange<'a, B, NonCoherent>> for MappedRange<'a, B>
where
B: Backend,
{
fn from(range: MappedRange<'a, B, NonCoherent>) -> Self {
MappedRange {
memory: range.memory,
ptr: range.ptr,
range: range.range,
coherent: MaybeCoherent(false),
}
}
}
impl<'a, B> MappedRange<'a, B, Coherent>
where
B: Backend,
{
pub unsafe fn write<'b, U: 'b>(
&'b mut self,
range: Range<u64>,
) -> Result<impl Write<U> + 'b, gfx_hal::mapping::Error>
where
U: Copy,
{
assert!(
range.start < range.end,
"Memory mapping region must have valid size"
);
assert!(
fits_usize(range.end - range.start),
"Range length must fit in usize"
);
let (ptr, range) = mapped_sub_range(self.ptr, self.range.clone(), range)
.ok_or_else(|| gfx_hal::mapping::Error::OutOfBounds)?;
let size = (range.end - range.start) as usize;
let slice = mapped_slice_mut::<U>(ptr, size);
Ok(WriteCoherent { slice })
}
}