rendy_memory/allocator/
dedicated.rsuse std::{ops::Range, ptr::NonNull};
use {
crate::{
allocator::{Allocator, Kind},
block::Block,
mapping::{mapped_fitting_range, MappedRange},
memory::*,
},
gfx_hal::{device::Device as _, Backend},
};
#[derive(Debug)]
pub struct DedicatedBlock<B: Backend> {
memory: Memory<B>,
mapping: Option<(NonNull<u8>, Range<u64>)>,
}
unsafe impl<B> Send for DedicatedBlock<B> where B: Backend {}
unsafe impl<B> Sync for DedicatedBlock<B> where B: Backend {}
impl<B> DedicatedBlock<B>
where
B: Backend,
{
pub fn unwrap_memory(self) -> Memory<B> {
assert!(self.mapping.is_none());
self.memory
}
pub fn from_memory(memory: Memory<B>) -> Self {
DedicatedBlock {
memory,
mapping: None,
}
}
}
impl<B> Block<B> for DedicatedBlock<B>
where
B: Backend,
{
#[inline]
fn properties(&self) -> gfx_hal::memory::Properties {
self.memory.properties()
}
#[inline]
fn memory(&self) -> &B::Memory {
self.memory.raw()
}
#[inline]
fn range(&self) -> Range<u64> {
0..self.memory.size()
}
fn map<'a>(
&'a mut self,
device: &B::Device,
range: Range<u64>,
) -> Result<MappedRange<'a, B>, gfx_hal::device::MapError> {
assert!(
range.start < range.end,
"Memory mapping region must have valid size"
);
if !self.memory.host_visible() {
return Err(gfx_hal::device::MapError::MappingFailed);
}
unsafe {
if let Some(ptr) = self
.mapping
.clone()
.and_then(|mapping| mapped_fitting_range(mapping.0, mapping.1, range.clone()))
{
Ok(MappedRange::from_raw(&self.memory, ptr, range))
} else {
self.unmap(device);
let ptr = device.map_memory(self.memory.raw(), range.clone())?;
let ptr = NonNull::new(ptr).expect("Memory mapping shouldn't return nullptr");
let mapping = MappedRange::from_raw(&self.memory, ptr, range);
self.mapping = Some((mapping.ptr(), mapping.range()));
Ok(mapping)
}
}
}
fn unmap(&mut self, device: &B::Device) {
if self.mapping.take().is_some() {
unsafe {
device.unmap_memory(self.memory.raw());
}
}
}
}
#[derive(Debug)]
pub struct DedicatedAllocator {
memory_type: gfx_hal::MemoryTypeId,
memory_properties: gfx_hal::memory::Properties,
used: u64,
}
impl DedicatedAllocator {
pub fn properties_required() -> gfx_hal::memory::Properties {
gfx_hal::memory::Properties::empty()
}
pub fn new(
memory_type: gfx_hal::MemoryTypeId,
memory_properties: gfx_hal::memory::Properties,
) -> Self {
DedicatedAllocator {
memory_type,
memory_properties,
used: 0,
}
}
}
impl<B> Allocator<B> for DedicatedAllocator
where
B: Backend,
{
type Block = DedicatedBlock<B>;
fn kind() -> Kind {
Kind::Dedicated
}
#[inline]
fn alloc(
&mut self,
device: &B::Device,
size: u64,
_align: u64,
) -> Result<(DedicatedBlock<B>, u64), gfx_hal::device::AllocationError> {
let memory = unsafe {
Memory::from_raw(
device.allocate_memory(self.memory_type, size)?,
size,
self.memory_properties,
)
};
self.used += size;
Ok((DedicatedBlock::from_memory(memory), size))
}
#[inline]
fn free(&mut self, device: &B::Device, mut block: DedicatedBlock<B>) -> u64 {
block.unmap(device);
let size = block.memory.size();
self.used -= size;
unsafe {
device.free_memory(block.memory.into_raw());
}
size
}
}
impl Drop for DedicatedAllocator {
fn drop(&mut self) {
if self.used > 0 {
log::error!("Not all allocation from DedicatedAllocator was freed");
}
}
}