use crate::device::physical::MemoryType;
use crate::device::Device;
use crate::instance::Instance;
use crate::memory::device_memory::MemoryAllocateInfo;
use crate::memory::DeviceMemory;
use crate::memory::DeviceMemoryAllocationError;
use crate::DeviceSize;
use std::cmp;
use std::ops::Range;
use std::sync::Arc;
use std::sync::Mutex;
#[derive(Debug)]
pub struct StdNonHostVisibleMemoryTypePool {
device: Arc<Device>,
memory_type: u32,
occupied: Mutex<Vec<(Arc<DeviceMemory>, Vec<Range<DeviceSize>>)>>,
}
impl StdNonHostVisibleMemoryTypePool {
#[inline]
pub fn new(
device: Arc<Device>,
memory_type: MemoryType,
) -> Arc<StdNonHostVisibleMemoryTypePool> {
assert_eq!(
&**device.physical_device().instance() as *const Instance,
&**memory_type.physical_device().instance() as *const Instance
);
assert_eq!(
device.physical_device().index(),
memory_type.physical_device().index()
);
Arc::new(StdNonHostVisibleMemoryTypePool {
device: device.clone(),
memory_type: memory_type.id(),
occupied: Mutex::new(Vec::new()),
})
}
pub fn alloc(
me: &Arc<Self>,
size: DeviceSize,
alignment: DeviceSize,
) -> Result<StdNonHostVisibleMemoryTypePoolAlloc, DeviceMemoryAllocationError> {
assert!(size != 0);
assert!(alignment != 0);
#[inline]
fn align(val: DeviceSize, al: DeviceSize) -> DeviceSize {
al * (1 + (val - 1) / al)
}
let mut occupied = me.occupied.lock().unwrap();
for &mut (ref dev_mem, ref mut entries) in occupied.iter_mut() {
for i in 0..entries.len().saturating_sub(1) {
let entry1 = entries[i].clone();
let entry1_end = align(entry1.end, alignment);
let entry2 = entries[i + 1].clone();
if entry1_end + size <= entry2.start {
entries.insert(i + 1, entry1_end..entry1_end + size);
return Ok(StdNonHostVisibleMemoryTypePoolAlloc {
pool: me.clone(),
memory: dev_mem.clone(),
offset: entry1_end,
size: size,
});
}
}
let last_end = entries.last().map(|e| align(e.end, alignment)).unwrap_or(0);
if last_end + size <= dev_mem.allocation_size() {
entries.push(last_end..last_end + size);
return Ok(StdNonHostVisibleMemoryTypePoolAlloc {
pool: me.clone(),
memory: dev_mem.clone(),
offset: last_end,
size: size,
});
}
}
let new_block = {
const MIN_BLOCK_SIZE: DeviceSize = 8 * 1024 * 1024; let allocation_size = cmp::max(MIN_BLOCK_SIZE, size.next_power_of_two());
let new_block = DeviceMemory::allocate(
me.device.clone(),
MemoryAllocateInfo {
allocation_size,
memory_type_index: me.memory_type().id(),
..Default::default()
},
)?;
Arc::new(new_block)
};
occupied.push((new_block.clone(), vec![0..size]));
Ok(StdNonHostVisibleMemoryTypePoolAlloc {
pool: me.clone(),
memory: new_block,
offset: 0,
size: size,
})
}
#[inline]
pub fn device(&self) -> &Arc<Device> {
&self.device
}
#[inline]
pub fn memory_type(&self) -> MemoryType {
self.device
.physical_device()
.memory_type_by_id(self.memory_type)
.unwrap()
}
}
#[derive(Debug)]
pub struct StdNonHostVisibleMemoryTypePoolAlloc {
pool: Arc<StdNonHostVisibleMemoryTypePool>,
memory: Arc<DeviceMemory>,
offset: DeviceSize,
size: DeviceSize,
}
impl StdNonHostVisibleMemoryTypePoolAlloc {
#[inline]
pub fn memory(&self) -> &DeviceMemory {
&self.memory
}
#[inline]
pub fn offset(&self) -> DeviceSize {
self.offset
}
#[inline]
pub fn size(&self) -> DeviceSize {
self.size
}
}
impl Drop for StdNonHostVisibleMemoryTypePoolAlloc {
fn drop(&mut self) {
let mut occupied = self.pool.occupied.lock().unwrap();
let entries = occupied
.iter_mut()
.find(|e| &*e.0 as *const DeviceMemory == &*self.memory)
.unwrap();
entries.1.retain(|e| e.start != self.offset);
}
}