pub mod suballocator;
use self::array_vec::ArrayVec;
pub use self::suballocator::{
AllocationType, BuddyAllocator, BumpAllocator, FreeListAllocator, MemoryAlloc, PoolAllocator,
SuballocationCreateInfo, SuballocationCreationError, Suballocator,
};
use super::{
DedicatedAllocation, DeviceMemory, ExternalMemoryHandleTypes, MemoryAllocateFlags,
MemoryAllocateInfo, MemoryProperties, MemoryPropertyFlags, MemoryRequirements, MemoryType,
};
use crate::{
device::{Device, DeviceOwned},
DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanError,
};
use ash::vk::{MAX_MEMORY_HEAPS, MAX_MEMORY_TYPES};
use parking_lot::RwLock;
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
sync::Arc,
};
const B: DeviceSize = 1;
const K: DeviceSize = 1024 * B;
const M: DeviceSize = 1024 * K;
const G: DeviceSize = 1024 * M;
pub unsafe trait MemoryAllocator: DeviceOwned {
fn find_memory_type_index(
&self,
memory_type_bits: u32,
filter: MemoryTypeFilter,
) -> Option<u32>;
fn allocate_from_type(
&self,
memory_type_index: u32,
create_info: SuballocationCreateInfo,
) -> Result<MemoryAlloc, AllocationCreationError>;
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
unsafe fn allocate_from_type_unchecked(
&self,
memory_type_index: u32,
create_info: SuballocationCreateInfo,
never_allocate: bool,
) -> Result<MemoryAlloc, AllocationCreationError>;
fn allocate(
&self,
create_info: AllocationCreateInfo<'_>,
) -> Result<MemoryAlloc, AllocationCreationError>;
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
unsafe fn allocate_unchecked(
&self,
create_info: AllocationCreateInfo<'_>,
) -> Result<MemoryAlloc, AllocationCreationError>;
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
unsafe fn allocate_dedicated_unchecked(
&self,
memory_type_index: u32,
allocation_size: DeviceSize,
dedicated_allocation: Option<DedicatedAllocation<'_>>,
export_handle_types: ExternalMemoryHandleTypes,
) -> Result<MemoryAlloc, AllocationCreationError>;
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct MemoryTypeFilter {
pub required_flags: MemoryPropertyFlags,
pub preferred_flags: MemoryPropertyFlags,
pub not_preferred_flags: MemoryPropertyFlags,
}
impl From<MemoryUsage> for MemoryTypeFilter {
#[inline]
fn from(usage: MemoryUsage) -> Self {
let mut filter = Self::default();
match usage {
MemoryUsage::GpuOnly => {
filter.preferred_flags.device_local = true;
filter.not_preferred_flags.host_visible = true;
}
MemoryUsage::Upload => {
filter.required_flags.host_visible = true;
filter.preferred_flags.device_local = true;
filter.not_preferred_flags.host_cached = true;
}
MemoryUsage::Download => {
filter.required_flags.host_visible = true;
filter.preferred_flags.host_cached = true;
}
}
filter
}
}
#[derive(Clone, Debug)]
pub struct AllocationCreateInfo<'d> {
pub requirements: MemoryRequirements,
pub allocation_type: AllocationType,
pub usage: MemoryUsage,
pub allocate_preference: MemoryAllocatePreference,
pub dedicated_allocation: Option<DedicatedAllocation<'d>>,
pub _ne: crate::NonExhaustive,
}
impl Default for AllocationCreateInfo<'_> {
#[inline]
fn default() -> Self {
AllocationCreateInfo {
requirements: MemoryRequirements {
size: 0,
alignment: 0,
memory_type_bits: 0,
prefers_dedicated_allocation: false,
requires_dedicated_allocation: false,
},
allocation_type: AllocationType::Unknown,
usage: MemoryUsage::GpuOnly,
allocate_preference: MemoryAllocatePreference::Unknown,
dedicated_allocation: None,
_ne: crate::NonExhaustive(()),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum MemoryUsage {
GpuOnly,
Upload,
Download,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum MemoryAllocatePreference {
Unknown,
NeverAllocate,
AlwaysAllocate,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum AllocationCreationError {
VulkanError(VulkanError),
OutOfPoolMemory,
DedicatedAllocationRequired,
BlockSizeExceeded,
SuballocatorBlockSizeExceeded,
}
impl Error for AllocationCreationError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::VulkanError(err) => Some(err),
_ => None,
}
}
}
impl Display for AllocationCreationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::VulkanError(_) => write!(f, "a runtime error occurred"),
Self::OutOfPoolMemory => write!(f, "the pool doesn't have enough free space"),
Self::DedicatedAllocationRequired => write!(
f,
"a dedicated allocation is required but was explicitly forbidden",
),
Self::BlockSizeExceeded => write!(
f,
"the allocation size was greater than the block size for all heaps of suitable \
memory types and dedicated allocations were explicitly forbidden",
),
Self::SuballocatorBlockSizeExceeded => write!(
f,
"the allocation size was greater than the suballocator's block size",
),
}
}
}
impl From<VulkanError> for AllocationCreationError {
fn from(err: VulkanError) -> Self {
AllocationCreationError::VulkanError(err)
}
}
pub type StandardMemoryAllocator = GenericMemoryAllocator<Arc<FreeListAllocator>>;
impl StandardMemoryAllocator {
pub fn new_default(device: Arc<Device>) -> Self {
#[allow(clippy::erasing_op, clippy::identity_op)]
let create_info = GenericMemoryAllocatorCreateInfo {
#[rustfmt::skip]
block_sizes: &[
(0 * B, 64 * M),
(1 * G, 256 * M),
],
..Default::default()
};
unsafe { Self::new_unchecked(device, create_info) }
}
}
pub type FastMemoryAllocator = GenericMemoryAllocator<Arc<BumpAllocator>>;
impl FastMemoryAllocator {
pub fn new_default(device: Arc<Device>) -> Self {
#[allow(clippy::erasing_op, clippy::identity_op)]
let create_info = GenericMemoryAllocatorCreateInfo {
#[rustfmt::skip]
block_sizes: &[
( 0 * B, 16 * M),
(512 * M, 32 * M),
( 1 * G, 64 * M),
],
..Default::default()
};
unsafe { Self::new_unchecked(device, create_info) }
}
}
#[derive(Debug)]
pub struct GenericMemoryAllocator<S: Suballocator> {
device: Arc<Device>,
pools: ArrayVec<Pool<S>, MAX_MEMORY_TYPES>,
block_sizes: ArrayVec<DeviceSize, MAX_MEMORY_HEAPS>,
allocation_type: AllocationType,
dedicated_allocation: bool,
export_handle_types: ArrayVec<ExternalMemoryHandleTypes, MAX_MEMORY_TYPES>,
flags: MemoryAllocateFlags,
memory_type_bits: u32,
max_allocations: u32,
}
#[derive(Debug)]
struct Pool<S> {
blocks: RwLock<Vec<S>>,
memory_type: ash::vk::MemoryType,
}
impl<S: Suballocator> GenericMemoryAllocator<S> {
#[allow(clippy::declare_interior_mutable_const)]
const EMPTY_POOL: Pool<S> = Pool {
blocks: RwLock::new(Vec::new()),
memory_type: ash::vk::MemoryType {
property_flags: ash::vk::MemoryPropertyFlags::empty(),
heap_index: 0,
},
};
pub fn new(
device: Arc<Device>,
create_info: GenericMemoryAllocatorCreateInfo<'_, '_>,
) -> Result<Self, GenericMemoryAllocatorCreationError> {
Self::validate_new(&device, &create_info)?;
Ok(unsafe { Self::new_unchecked(device, create_info) })
}
fn validate_new(
device: &Device,
create_info: &GenericMemoryAllocatorCreateInfo<'_, '_>,
) -> Result<(), GenericMemoryAllocatorCreationError> {
let &GenericMemoryAllocatorCreateInfo {
block_sizes,
allocation_type: _,
dedicated_allocation: _,
export_handle_types,
device_address: _,
_ne: _,
} = create_info;
assert!(
block_sizes.windows(2).all(|win| win[0].0 < win[1].0),
"`create_info.block_sizes` must be sorted by threshold without duplicates",
);
assert!(
matches!(block_sizes.first(), Some((0, _))),
"`create_info.block_sizes` must contain a baseline threshold `0`",
);
if !export_handle_types.is_empty() {
if !(device.api_version() >= Version::V1_1
&& device.enabled_extensions().khr_external_memory)
{
return Err(GenericMemoryAllocatorCreationError::RequirementNotMet {
required_for: "`create_info.export_handle_types` was not empty",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
device_extensions: &["khr_external_memory"],
..Default::default()
},
});
}
assert!(
export_handle_types.len()
== device
.physical_device()
.memory_properties()
.memory_types
.len(),
"`create_info.export_handle_types` must contain as many elements as the number of \
memory types if not empty",
);
for export_handle_types in export_handle_types {
export_handle_types.validate_device(device)?;
}
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn new_unchecked(
device: Arc<Device>,
create_info: GenericMemoryAllocatorCreateInfo<'_, '_>,
) -> Self {
let GenericMemoryAllocatorCreateInfo {
block_sizes,
allocation_type,
dedicated_allocation,
export_handle_types,
mut device_address,
_ne: _,
} = create_info;
let MemoryProperties {
memory_types,
memory_heaps,
} = device.physical_device().memory_properties();
let mut pools = ArrayVec::new(memory_types.len(), [Self::EMPTY_POOL; MAX_MEMORY_TYPES]);
for (i, memory_type) in memory_types.iter().enumerate() {
pools[i].memory_type = ash::vk::MemoryType {
property_flags: memory_type.property_flags.into(),
heap_index: memory_type.heap_index,
};
}
let block_sizes = {
let mut sizes = ArrayVec::new(memory_heaps.len(), [0; MAX_MEMORY_HEAPS]);
for (i, memory_heap) in memory_heaps.iter().enumerate() {
let idx = match block_sizes.binary_search_by_key(&memory_heap.size, |&(t, _)| t) {
Ok(idx) => idx,
Err(idx) => idx.saturating_sub(1),
};
sizes[i] = block_sizes[idx].1;
assert!(sizes[i] <= memory_heap.size);
}
sizes
};
let export_handle_types = {
let mut types = ArrayVec::new(
export_handle_types.len(),
[ExternalMemoryHandleTypes::empty(); MAX_MEMORY_TYPES],
);
types.copy_from_slice(export_handle_types);
types
};
device_address &= device.enabled_features().buffer_device_address
&& !device.enabled_extensions().ext_buffer_device_address;
device_address &=
device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_device_group;
let mut memory_type_bits = u32::MAX;
for (index, MemoryType { property_flags, .. }) in memory_types.iter().enumerate() {
if property_flags.lazily_allocated
|| property_flags.protected
|| property_flags.device_coherent
|| property_flags.device_uncached
|| property_flags.rdma_capable
{
memory_type_bits &= !(1 << index);
}
}
let max_memory_allocation_count = device
.physical_device()
.properties()
.max_memory_allocation_count;
let max_allocations = max_memory_allocation_count / 4 * 3;
GenericMemoryAllocator {
device,
pools,
block_sizes,
allocation_type,
dedicated_allocation,
export_handle_types,
flags: MemoryAllocateFlags {
device_address,
..Default::default()
},
memory_type_bits,
max_allocations,
}
}
fn validate_allocate_from_type(
&self,
memory_type_index: u32,
create_info: &SuballocationCreateInfo,
) {
let memory_type = &self.pools[memory_type_index as usize].memory_type;
assert!(
memory_type
.property_flags
.contains(ash::vk::MemoryPropertyFlags::PROTECTED)
&& !self.device.enabled_features().protected_memory,
"attempted to allocate from a protected memory type without the `protected_memory` \
feature being enabled on the device",
);
assert!(
memory_type
.property_flags
.contains(ash::vk::MemoryPropertyFlags::DEVICE_COHERENT_AMD)
&& !self.device.enabled_features().device_coherent_memory,
"attempted to allocate memory from a device-coherent memory type without the \
`device_coherent_memory` feature being enabled on the device",
);
create_info.validate();
}
fn validate_allocate(&self, create_info: &AllocationCreateInfo<'_>) {
let &AllocationCreateInfo {
requirements,
allocation_type: _,
usage: _,
allocate_preference: _,
dedicated_allocation,
_ne: _,
} = create_info;
SuballocationCreateInfo::from(create_info.clone()).validate();
assert!(requirements.memory_type_bits != 0);
assert!(requirements.memory_type_bits < 1 << self.pools.len());
if let Some(dedicated_allocation) = dedicated_allocation {
match dedicated_allocation {
DedicatedAllocation::Buffer(buffer) => {
assert_eq!(&self.device, buffer.device());
let required_size = buffer.memory_requirements().size;
assert!(requirements.size != required_size);
}
DedicatedAllocation::Image(image) => {
assert_eq!(&self.device, image.device());
let required_size = image.memory_requirements()[0].size;
assert!(requirements.size != required_size);
}
}
}
}
}
unsafe impl<S: Suballocator> MemoryAllocator for GenericMemoryAllocator<S> {
fn find_memory_type_index(
&self,
memory_type_bits: u32,
filter: MemoryTypeFilter,
) -> Option<u32> {
let required_flags = filter.required_flags.into();
let preferred_flags = filter.preferred_flags.into();
let not_preferred_flags = filter.not_preferred_flags.into();
self.pools
.iter()
.map(|pool| pool.memory_type.property_flags)
.enumerate()
.filter(|&(index, flags)| {
memory_type_bits & (1 << index) != 0 && flags & required_flags == required_flags
})
.min_by_key(|&(_, flags)| {
(!flags & preferred_flags).as_raw().count_ones()
+ (flags & not_preferred_flags).as_raw().count_ones()
})
.map(|(index, _)| index as u32)
}
fn allocate_from_type(
&self,
memory_type_index: u32,
create_info: SuballocationCreateInfo,
) -> Result<MemoryAlloc, AllocationCreationError> {
self.validate_allocate_from_type(memory_type_index, &create_info);
if self.pools[memory_type_index as usize]
.memory_type
.property_flags
.contains(ash::vk::MemoryPropertyFlags::LAZILY_ALLOCATED)
{
return unsafe {
self.allocate_dedicated_unchecked(
memory_type_index,
create_info.size,
None,
if !self.export_handle_types.is_empty() {
self.export_handle_types[memory_type_index as usize]
} else {
ExternalMemoryHandleTypes::empty()
},
)
};
}
unsafe { self.allocate_from_type_unchecked(memory_type_index, create_info, false) }
}
unsafe fn allocate_from_type_unchecked(
&self,
memory_type_index: u32,
create_info: SuballocationCreateInfo,
never_allocate: bool,
) -> Result<MemoryAlloc, AllocationCreationError> {
let SuballocationCreateInfo {
size,
alignment: _,
allocation_type: _,
_ne: _,
} = create_info;
let pool = &self.pools[memory_type_index as usize];
let block_size = self.block_sizes[pool.memory_type.heap_index as usize];
if size > block_size {
return Err(AllocationCreationError::BlockSizeExceeded);
}
let mut blocks = if S::IS_BLOCKING {
let mut blocks = pool.blocks.write();
blocks.sort_by_key(Suballocator::free_size);
let (Ok(idx) | Err(idx)) = blocks.binary_search_by_key(&size, Suballocator::free_size);
for block in &blocks[idx..] {
match block.allocate_unchecked(create_info.clone()) {
Ok(alloc) => return Ok(alloc),
Err(SuballocationCreationError::BlockSizeExceeded) => {
return Err(AllocationCreationError::SuballocatorBlockSizeExceeded);
}
Err(_) => {}
}
}
blocks
} else {
let blocks = pool.blocks.read();
for block in blocks.iter().rev() {
match block.allocate_unchecked(create_info.clone()) {
Ok(alloc) => return Ok(alloc),
Err(SuballocationCreationError::BlockSizeExceeded) => {
return Err(AllocationCreationError::SuballocatorBlockSizeExceeded);
}
Err(_) => {}
}
}
let len = blocks.len();
drop(blocks);
let blocks = pool.blocks.write();
if blocks.len() > len {
match blocks[len].allocate_unchecked(create_info.clone()) {
Ok(alloc) => return Ok(alloc),
Err(SuballocationCreationError::BlockSizeExceeded) => {
return Err(AllocationCreationError::SuballocatorBlockSizeExceeded);
}
Err(_) => {}
}
}
blocks
};
if S::NEEDS_CLEANUP {
blocks.iter_mut().for_each(Suballocator::cleanup);
blocks.sort_unstable_by_key(Suballocator::free_size);
if let Some(block) = blocks.last() {
if let Ok(alloc) = block.allocate_unchecked(create_info.clone()) {
return Ok(alloc);
}
}
}
if never_allocate {
return Err(AllocationCreationError::OutOfPoolMemory);
}
let block = {
let export_handle_types = if !self.export_handle_types.is_empty() {
self.export_handle_types[memory_type_index as usize]
} else {
ExternalMemoryHandleTypes::empty()
};
let mut i = 0;
loop {
let allocate_info = MemoryAllocateInfo {
allocation_size: block_size >> i,
memory_type_index,
export_handle_types,
dedicated_allocation: None,
flags: self.flags,
..Default::default()
};
match DeviceMemory::allocate_unchecked(self.device.clone(), allocate_info, None) {
Ok(device_memory) => {
break S::new(MemoryAlloc::new(device_memory)?);
}
Err(VulkanError::OutOfHostMemory | VulkanError::OutOfDeviceMemory) if i < 3 => {
i += 1;
}
Err(err) => return Err(err.into()),
}
}
};
blocks.push(block);
let block = blocks.last().unwrap();
match block.allocate_unchecked(create_info) {
Ok(alloc) => Ok(alloc),
Err(SuballocationCreationError::OutOfRegionMemory) => Err(
AllocationCreationError::VulkanError(VulkanError::OutOfDeviceMemory),
),
Err(SuballocationCreationError::FragmentedRegion) => unreachable!(),
Err(SuballocationCreationError::BlockSizeExceeded) => {
Err(AllocationCreationError::SuballocatorBlockSizeExceeded)
}
}
}
fn allocate(
&self,
create_info: AllocationCreateInfo<'_>,
) -> Result<MemoryAlloc, AllocationCreationError> {
self.validate_allocate(&create_info);
unsafe { self.allocate_unchecked(create_info) }
}
unsafe fn allocate_unchecked(
&self,
create_info: AllocationCreateInfo<'_>,
) -> Result<MemoryAlloc, AllocationCreationError> {
let AllocationCreateInfo {
requirements:
MemoryRequirements {
size,
alignment: _,
mut memory_type_bits,
mut prefers_dedicated_allocation,
requires_dedicated_allocation,
},
allocation_type: _,
usage,
allocate_preference,
mut dedicated_allocation,
_ne: _,
} = create_info;
let create_info = SuballocationCreateInfo::from(create_info);
memory_type_bits &= self.memory_type_bits;
let filter = usage.into();
let mut memory_type_index = self
.find_memory_type_index(memory_type_bits, filter)
.expect("couldn't find a suitable memory type");
if !self.dedicated_allocation {
dedicated_allocation = None;
}
let export_handle_types = if self.export_handle_types.is_empty() {
ExternalMemoryHandleTypes::empty()
} else {
self.export_handle_types[memory_type_index as usize]
};
loop {
let memory_type = self.pools[memory_type_index as usize].memory_type;
let block_size = self.block_sizes[memory_type.heap_index as usize];
let res = match allocate_preference {
MemoryAllocatePreference::Unknown => {
if requires_dedicated_allocation {
self.allocate_dedicated_unchecked(
memory_type_index,
size,
dedicated_allocation,
export_handle_types,
)
} else {
if size > block_size / 2 {
prefers_dedicated_allocation = true;
}
if self.device.allocation_count() > self.max_allocations
&& size <= block_size
{
prefers_dedicated_allocation = false;
}
if prefers_dedicated_allocation {
self.allocate_dedicated_unchecked(
memory_type_index,
size,
dedicated_allocation,
export_handle_types,
)
.or_else(|err| {
if size <= block_size {
self.allocate_from_type_unchecked(
memory_type_index,
create_info.clone(),
true, )
.map_err(|_| err)
} else {
Err(err)
}
})
} else {
self.allocate_from_type_unchecked(
memory_type_index,
create_info.clone(),
false,
)
.or_else(|_| {
self.allocate_dedicated_unchecked(
memory_type_index,
size,
dedicated_allocation,
export_handle_types,
)
})
}
}
}
MemoryAllocatePreference::NeverAllocate => {
if requires_dedicated_allocation {
return Err(AllocationCreationError::DedicatedAllocationRequired);
}
self.allocate_from_type_unchecked(memory_type_index, create_info.clone(), true)
}
MemoryAllocatePreference::AlwaysAllocate => self.allocate_dedicated_unchecked(
memory_type_index,
size,
dedicated_allocation,
export_handle_types,
),
};
match res {
Ok(alloc) => return Ok(alloc),
Err(AllocationCreationError::SuballocatorBlockSizeExceeded) => {
return Err(AllocationCreationError::SuballocatorBlockSizeExceeded);
}
Err(err) => {
memory_type_bits &= !(1 << memory_type_index);
memory_type_index = self
.find_memory_type_index(memory_type_bits, filter)
.ok_or(err)?;
}
}
}
}
unsafe fn allocate_dedicated_unchecked(
&self,
memory_type_index: u32,
allocation_size: DeviceSize,
mut dedicated_allocation: Option<DedicatedAllocation<'_>>,
export_handle_types: ExternalMemoryHandleTypes,
) -> Result<MemoryAlloc, AllocationCreationError> {
if !(self.device.api_version() >= Version::V1_1
|| self.device.enabled_extensions().khr_dedicated_allocation)
{
dedicated_allocation = None;
}
let allocate_info = MemoryAllocateInfo {
allocation_size,
memory_type_index,
dedicated_allocation,
export_handle_types,
flags: self.flags,
..Default::default()
};
let mut alloc = MemoryAlloc::new(
DeviceMemory::allocate_unchecked(self.device.clone(), allocate_info, None)
.map_err(AllocationCreationError::from)?,
)?;
alloc.set_allocation_type(self.allocation_type);
Ok(alloc)
}
}
unsafe impl<S: Suballocator> MemoryAllocator for Arc<GenericMemoryAllocator<S>> {
fn find_memory_type_index(
&self,
memory_type_bits: u32,
filter: MemoryTypeFilter,
) -> Option<u32> {
(**self).find_memory_type_index(memory_type_bits, filter)
}
fn allocate_from_type(
&self,
memory_type_index: u32,
create_info: SuballocationCreateInfo,
) -> Result<MemoryAlloc, AllocationCreationError> {
(**self).allocate_from_type(memory_type_index, create_info)
}
unsafe fn allocate_from_type_unchecked(
&self,
memory_type_index: u32,
create_info: SuballocationCreateInfo,
never_allocate: bool,
) -> Result<MemoryAlloc, AllocationCreationError> {
(**self).allocate_from_type_unchecked(memory_type_index, create_info, never_allocate)
}
fn allocate(
&self,
create_info: AllocationCreateInfo<'_>,
) -> Result<MemoryAlloc, AllocationCreationError> {
(**self).allocate(create_info)
}
unsafe fn allocate_unchecked(
&self,
create_info: AllocationCreateInfo<'_>,
) -> Result<MemoryAlloc, AllocationCreationError> {
(**self).allocate_unchecked(create_info)
}
unsafe fn allocate_dedicated_unchecked(
&self,
memory_type_index: u32,
allocation_size: DeviceSize,
dedicated_allocation: Option<DedicatedAllocation<'_>>,
export_handle_types: ExternalMemoryHandleTypes,
) -> Result<MemoryAlloc, AllocationCreationError> {
(**self).allocate_dedicated_unchecked(
memory_type_index,
allocation_size,
dedicated_allocation,
export_handle_types,
)
}
}
unsafe impl<S: Suballocator> DeviceOwned for GenericMemoryAllocator<S> {
fn device(&self) -> &Arc<Device> {
&self.device
}
}
#[derive(Clone, Debug)]
pub struct GenericMemoryAllocatorCreateInfo<'b, 'e> {
pub block_sizes: &'b [(Threshold, BlockSize)],
pub allocation_type: AllocationType,
pub dedicated_allocation: bool,
pub export_handle_types: &'e [ExternalMemoryHandleTypes],
pub device_address: bool,
pub _ne: crate::NonExhaustive,
}
pub type Threshold = DeviceSize;
pub type BlockSize = DeviceSize;
impl Default for GenericMemoryAllocatorCreateInfo<'_, '_> {
#[inline]
fn default() -> Self {
GenericMemoryAllocatorCreateInfo {
block_sizes: &[],
allocation_type: AllocationType::Unknown,
dedicated_allocation: true,
export_handle_types: &[],
device_address: true,
_ne: crate::NonExhaustive(()),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum GenericMemoryAllocatorCreationError {
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for GenericMemoryAllocatorCreationError {}
impl Display for GenericMemoryAllocatorCreationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
}
impl From<RequirementNotMet> for GenericMemoryAllocatorCreationError {
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
mod array_vec {
use std::ops::{Deref, DerefMut};
#[derive(Clone, Copy, Debug)]
pub(super) struct ArrayVec<T, const N: usize> {
len: usize,
data: [T; N],
}
impl<T, const N: usize> ArrayVec<T, N> {
pub fn new(len: usize, data: [T; N]) -> Self {
assert!(len <= N);
ArrayVec { len, data }
}
}
impl<T, const N: usize> Deref for ArrayVec<T, N> {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { self.data.get_unchecked(0..self.len) }
}
}
impl<T, const N: usize> DerefMut for ArrayVec<T, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { self.data.get_unchecked_mut(0..self.len) }
}
}
}