pub use self::host_visible::StdHostVisibleMemoryTypePool;
pub use self::host_visible::StdHostVisibleMemoryTypePoolAlloc;
pub use self::non_host_visible::StdNonHostVisibleMemoryTypePool;
pub use self::non_host_visible::StdNonHostVisibleMemoryTypePoolAlloc;
pub use self::pool::StdMemoryPool;
pub use self::pool::StdMemoryPoolAlloc;
use crate::device::physical::MemoryType;
use crate::device::{Device, DeviceOwned};
use crate::memory::device_memory::MemoryAllocateInfo;
use crate::memory::DedicatedAllocation;
use crate::memory::DeviceMemory;
use crate::memory::DeviceMemoryAllocationError;
use crate::memory::ExternalMemoryHandleTypes;
use crate::memory::MappedDeviceMemory;
use crate::memory::MemoryRequirements;
use crate::DeviceSize;
use std::sync::Arc;
mod host_visible;
mod non_host_visible;
mod pool;
const MAX_POOL_ALLOC: DeviceSize = 256 * 1024 * 1024;
fn choose_allocation_memory_type<'s, F>(
device: &'s Arc<Device>,
requirements: &MemoryRequirements,
mut filter: F,
map: MappingRequirement,
) -> MemoryType<'s>
where
F: FnMut(MemoryType) -> AllocFromRequirementsFilter,
{
let mem_ty = {
let mut filter = |ty: MemoryType| {
if map == MappingRequirement::Map && !ty.is_host_visible() {
return AllocFromRequirementsFilter::Forbidden;
}
filter(ty)
};
let first_loop = device
.physical_device()
.memory_types()
.map(|t| (t, AllocFromRequirementsFilter::Preferred));
let second_loop = device
.physical_device()
.memory_types()
.map(|t| (t, AllocFromRequirementsFilter::Allowed));
first_loop
.chain(second_loop)
.filter(|&(t, _)| (requirements.memory_type_bits & (1 << t.id())) != 0)
.filter(|&(t, rq)| filter(t) == rq)
.next()
.expect("Couldn't find a memory type to allocate from")
.0
};
mem_ty
}
pub(crate) fn alloc_dedicated_with_exportable_fd<F>(
device: Arc<Device>,
requirements: &MemoryRequirements,
layout: AllocLayout,
map: MappingRequirement,
dedicated_allocation: DedicatedAllocation,
filter: F,
) -> Result<PotentialDedicatedAllocation<StdMemoryPoolAlloc>, DeviceMemoryAllocationError>
where
F: FnMut(MemoryType) -> AllocFromRequirementsFilter,
{
assert!(device.enabled_extensions().khr_external_memory_fd);
assert!(device.enabled_extensions().khr_external_memory);
let memory_type = choose_allocation_memory_type(&device, requirements, filter, map);
let memory = DeviceMemory::allocate(
device.clone(),
MemoryAllocateInfo {
allocation_size: requirements.size,
memory_type_index: memory_type.id(),
export_handle_types: ExternalMemoryHandleTypes {
opaque_fd: true,
..ExternalMemoryHandleTypes::none()
},
..MemoryAllocateInfo::dedicated_allocation(dedicated_allocation)
},
)?;
match map {
MappingRequirement::Map => {
let mapped_memory = MappedDeviceMemory::new(memory, 0..requirements.size)?;
Ok(PotentialDedicatedAllocation::DedicatedMapped(mapped_memory))
}
MappingRequirement::DoNotMap => Ok(PotentialDedicatedAllocation::Dedicated(memory)),
}
}
pub unsafe trait MemoryPool: DeviceOwned {
type Alloc: MemoryPoolAlloc;
fn alloc_generic(
&self,
ty: MemoryType,
size: DeviceSize,
alignment: DeviceSize,
layout: AllocLayout,
map: MappingRequirement,
) -> Result<Self::Alloc, DeviceMemoryAllocationError>;
fn alloc_from_requirements<F>(
&self,
requirements: &MemoryRequirements,
layout: AllocLayout,
map: MappingRequirement,
dedicated_allocation: Option<DedicatedAllocation>,
filter: F,
) -> Result<PotentialDedicatedAllocation<Self::Alloc>, DeviceMemoryAllocationError>
where
F: FnMut(MemoryType) -> AllocFromRequirementsFilter,
{
let memory_type = choose_allocation_memory_type(self.device(), requirements, filter, map);
if !requirements.prefer_dedicated && requirements.size <= MAX_POOL_ALLOC {
let alloc = self.alloc_generic(
memory_type,
requirements.size,
requirements.alignment,
layout,
map,
)?;
return Ok(alloc.into());
}
if dedicated_allocation.is_none() {
let alloc = self.alloc_generic(
memory_type,
requirements.size,
requirements.alignment,
layout,
map,
)?;
return Ok(alloc.into());
}
let memory = DeviceMemory::allocate(
self.device().clone(),
MemoryAllocateInfo {
allocation_size: requirements.size,
memory_type_index: memory_type.id(),
dedicated_allocation,
..Default::default()
},
)?;
match map {
MappingRequirement::Map => {
let mapped_memory = MappedDeviceMemory::new(memory, 0..requirements.size)?;
Ok(PotentialDedicatedAllocation::DedicatedMapped(mapped_memory))
}
MappingRequirement::DoNotMap => Ok(PotentialDedicatedAllocation::Dedicated(memory)),
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AllocFromRequirementsFilter {
Preferred,
Allowed,
Forbidden,
}
pub unsafe trait MemoryPoolAlloc: Send + Sync {
fn mapped_memory(&self) -> Option<&MappedDeviceMemory>;
fn memory(&self) -> &DeviceMemory;
fn offset(&self) -> DeviceSize;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MappingRequirement {
Map,
DoNotMap,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum AllocLayout {
Linear,
Optimal,
}
#[derive(Debug)]
pub enum PotentialDedicatedAllocation<A> {
Generic(A),
Dedicated(DeviceMemory),
DedicatedMapped(MappedDeviceMemory),
}
unsafe impl<A> MemoryPoolAlloc for PotentialDedicatedAllocation<A>
where
A: MemoryPoolAlloc,
{
#[inline]
fn mapped_memory(&self) -> Option<&MappedDeviceMemory> {
match *self {
PotentialDedicatedAllocation::Generic(ref alloc) => alloc.mapped_memory(),
PotentialDedicatedAllocation::Dedicated(_) => None,
PotentialDedicatedAllocation::DedicatedMapped(ref mem) => Some(mem),
}
}
#[inline]
fn memory(&self) -> &DeviceMemory {
match *self {
PotentialDedicatedAllocation::Generic(ref alloc) => alloc.memory(),
PotentialDedicatedAllocation::Dedicated(ref mem) => mem,
PotentialDedicatedAllocation::DedicatedMapped(ref mem) => mem.as_ref(),
}
}
#[inline]
fn offset(&self) -> DeviceSize {
match *self {
PotentialDedicatedAllocation::Generic(ref alloc) => alloc.offset(),
PotentialDedicatedAllocation::Dedicated(_) => 0,
PotentialDedicatedAllocation::DedicatedMapped(_) => 0,
}
}
}
impl<A> From<A> for PotentialDedicatedAllocation<A> {
#[inline]
fn from(alloc: A) -> PotentialDedicatedAllocation<A> {
PotentialDedicatedAllocation::Generic(alloc)
}
}