mod allocation;
mod allocator;
mod block;
mod chain;
mod granularity;
mod host;
mod linear;
mod metadata;
mod policy;
mod resource;
mod selector;
mod synchronized;
pub use synchronized::{SynchronizedAllocator, SynchronizedVirtualBlock};
mod tlsf;
pub mod virtual_block;
pub use allocation::Allocation;
#[cfg(unix)]
pub use allocator::get_memory_fd;
#[cfg(all(windows, feature = "platform-win32"))]
pub use allocator::get_memory_win32_handle;
pub use allocator::{
Allocator, TrimStats, allocate, allocate_dedicated, allocate_for_buffer, allocate_for_image,
allocate_with_options, allocation_info, bind_buffer_memory, bind_image_memory, budget_snapshot,
close, create_buffer, create_buffer_with_options, create_dedicated_buffer,
create_dedicated_image, create_image, create_image_with_options, destroy_buffer, destroy_image,
find_memory_type, find_memory_type_for_buffer_info, find_memory_type_for_image_info, flush, free,
invalidate, map, mapped_pointer, query_budget, set_heap_limit, statistics, trim,
trim_with_budget, unmap,
};
pub use allocator::{
CacheRange, DetailedStatistics, MemoryStatistics, allocate_many, allocation_name, allocator_info,
copy_from_allocation, copy_to_allocation, create_aliasing_buffer, create_aliasing_image,
detailed_pool_statistics, detailed_statistics, flush_many, free_many, invalidate_many,
memory_properties, memory_type_properties, physical_device_properties, pool_name,
set_allocation_name, set_allocation_user_data, set_pool_name, write_statistics_json,
};
pub use allocator::{
DefragmentationAlgorithm, DefragmentationContext, DefragmentationInfo, DefragmentationMove,
DefragmentationPass, DefragmentationResource, DefragmentationStats, begin_defragmentation,
begin_defragmentation_with_break, set_allocation_pinned,
};
pub use allocator::{
Pool, PoolCreateInfo, PoolStats, create_pool, create_pool_with_chain, destroy_pool,
pool_statistics, set_mapping_hysteresis, set_preferred_block_size,
};
pub use allocator::{bind_buffer_memory2, bind_image_memory2};
pub use allocator::{check_corruption, check_pool_corruption, set_debug_memory_settings};
pub use allocator::{external_memory_types, set_external_memory_types};
pub use allocator::{
heap_budgets, refresh_budget, refresh_budget_with_context, set_current_frame_index,
};
pub use chain::AllocationChain;
mod import;
pub use import::{ImportMemoryInfo, ImportResource};
pub use metadata::AllocationAlgorithm;
pub use policy::{HostAccess, MemoryUsage};
pub use selector::MemoryTypeSelector;
pub use virtual_block::{
PlacementStrategy, VirtualAllocation, VirtualAllocationInfo, VirtualBlock, VirtualBlockDetails,
VirtualBlockStats,
};
use crate::{self as vk, load::CallError};
#[derive(Debug, PartialEq)]
pub enum AllocError {
NoCompatibleMemoryType,
InvalidProperties(&'static str),
InvalidRequest(&'static str),
InvalidRange,
UnknownAllocation,
UnknownPool,
CorruptionDetected {
allocation: u64,
offset: u64,
},
WrongAllocator,
AlreadyMapped,
NotMapped,
NotHostVisible,
SerialExhausted,
SynchronizationPoisoned,
HostAllocationFailed,
AllocationLimit,
OutOfSpace,
AllocationTooLarge {
requested: u64,
limit: u64,
},
UnsupportedCapability(&'static str),
WrongResource,
LiveAllocations,
LivePools,
Closed,
Call(CallError),
Output {
kind: std::io::ErrorKind,
code: Option<i32>,
},
}
impl std::fmt::Display for AllocError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "allocation error: {self:?}")
}
}
impl std::error::Error for AllocError {}
impl From<crate::ConstructionError> for AllocError {
fn from(error: crate::ConstructionError) -> Self {
Self::from(CallError::from(error))
}
}
impl From<CallError> for AllocError {
fn from(error: CallError) -> Self {
Self::Call(error)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MemoryPriority(u32);
impl MemoryPriority {
pub fn new(value: f32) -> Result<Self, AllocError> {
if !value.is_finite() || !(0.0..=1.0).contains(&value) {
return Err(AllocError::InvalidRequest(
"memory priority must be finite and in 0..=1",
));
}
Ok(Self(if value == 0.0 {
0.0_f32.to_bits()
} else {
value.to_bits()
}))
}
pub fn get(self) -> f32 {
f32::from_bits(self.0)
}
}
impl Default for MemoryPriority {
fn default() -> Self {
Self(0.5_f32.to_bits())
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct DebugMemorySettings {
pub margin: u64,
pub initialize_allocations: bool,
pub poison_frees: bool,
}
impl DebugMemorySettings {
#[inline]
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[inline]
#[must_use]
pub fn set_margin(mut self, value: u64) -> Self {
self.margin = value;
self
}
#[inline]
#[must_use]
pub fn set_initialize_allocations(mut self, value: bool) -> Self {
self.initialize_allocations = value;
self
}
#[inline]
#[must_use]
pub fn set_poison_frees(mut self, value: bool) -> Self {
self.poison_frees = value;
self
}
}
#[derive(Clone, Copy, Default)]
pub struct DeviceMemoryCallbacks {
pub allocated: Option<
unsafe extern "system" fn(vk::DeviceHandle, vk::DeviceMemory, u64, u32, *mut std::ffi::c_void),
>,
pub freed: Option<
unsafe extern "system" fn(vk::DeviceHandle, vk::DeviceMemory, u64, u32, *mut std::ffi::c_void),
>,
pub p_user_data: *mut std::ffi::c_void,
}
impl DeviceMemoryCallbacks {
#[inline]
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[inline]
#[must_use]
pub fn set_allocated(
mut self,
value: Option<
unsafe extern "system" fn(
vk::DeviceHandle,
vk::DeviceMemory,
u64,
u32,
*mut std::ffi::c_void,
),
>,
) -> Self {
self.allocated = value;
self
}
#[inline]
#[must_use]
pub fn set_freed(
mut self,
value: Option<
unsafe extern "system" fn(
vk::DeviceHandle,
vk::DeviceMemory,
u64,
u32,
*mut std::ffi::c_void,
),
>,
) -> Self {
self.freed = value;
self
}
#[inline]
#[must_use]
pub fn set_p_user_data(mut self, value: *mut std::ffi::c_void) -> Self {
self.p_user_data = value;
self
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AllocatorInfo {
pub device: vk::DeviceHandle,
pub instance: Option<vk::InstanceHandle>,
pub physical_device: Option<vk::PhysicalDevice>,
pub api_version: Option<u32>,
}
impl AllocatorInfo {
#[inline]
#[must_use]
pub fn set_device(mut self, value: vk::DeviceHandle) -> Self {
self.device = value;
self
}
#[inline]
#[must_use]
pub fn set_instance(mut self, value: Option<vk::InstanceHandle>) -> Self {
self.instance = value;
self
}
#[inline]
#[must_use]
pub fn set_physical_device(mut self, value: Option<vk::PhysicalDevice>) -> Self {
self.physical_device = value;
self
}
#[inline]
#[must_use]
pub fn set_api_version(mut self, value: Option<u32>) -> Self {
self.api_version = value;
self
}
}
pub struct AllocRequest {
pub size: u64,
pub alignment: u64,
pub memory_type_bits: u32,
pub required_flags: vk::MemoryPropertyFlags,
pub preferred_flags: vk::MemoryPropertyFlags,
}
impl AllocRequest {
#[inline]
#[must_use]
pub fn new(size: u64, alignment: u64, memory_type_bits: u32) -> Self {
Self {
size,
alignment,
memory_type_bits,
required_flags: vk::MemoryPropertyFlags::empty(),
preferred_flags: vk::MemoryPropertyFlags::empty(),
}
}
#[inline]
#[must_use]
pub fn set_size(mut self, value: u64) -> Self {
self.size = value;
self
}
#[inline]
#[must_use]
pub fn set_alignment(mut self, value: u64) -> Self {
self.alignment = value;
self
}
#[inline]
#[must_use]
pub fn set_memory_type_bits(mut self, value: u32) -> Self {
self.memory_type_bits = value;
self
}
#[inline]
#[must_use]
pub fn set_required_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
self.required_flags = value;
self
}
#[inline]
#[must_use]
pub fn set_preferred_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
self.preferred_flags = value;
self
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum AllocationPolicy {
#[default]
Separate,
Automatic,
Pooled { block_size: u64 },
Adaptive {
block_size: u64,
min_block_size: u64,
},
}
#[derive(Clone, Copy, Debug)]
pub struct AllocationCreateInfo<'pool> {
pub within_budget: bool,
pub dedicated_memory: bool,
pub memory_allocate_next: Option<AllocationChain<'pool>>,
pub never_allocate: bool,
pub can_alias: bool,
pub priority: MemoryPriority,
pub min_allocation_alignment: u64,
pub pool: Option<&'pool Pool>,
pub usage: MemoryUsage,
pub host_access: HostAccess,
pub allow_transfer_instead: bool,
pub avoided_flags: vk::MemoryPropertyFlags,
pub required_flags: vk::MemoryPropertyFlags,
pub preferred_flags: vk::MemoryPropertyFlags,
pub memory_type_bits: u32,
pub strategy: PlacementStrategy,
pub upper_address: bool,
pub policy: AllocationPolicy,
pub persistent_map: bool,
}
impl Default for AllocationCreateInfo<'_> {
fn default() -> Self {
Self {
within_budget: false,
dedicated_memory: false,
memory_allocate_next: None,
never_allocate: false,
can_alias: false,
priority: MemoryPriority::default(),
min_allocation_alignment: 0,
pool: None,
usage: MemoryUsage::Explicit,
host_access: HostAccess::None,
allow_transfer_instead: false,
avoided_flags: vk::MemoryPropertyFlags::empty(),
required_flags: vk::MemoryPropertyFlags::empty(),
preferred_flags: vk::MemoryPropertyFlags::empty(),
memory_type_bits: u32::MAX,
strategy: PlacementStrategy::Default,
upper_address: false,
policy: AllocationPolicy::Separate,
persistent_map: false,
}
}
}
impl<'pool> AllocationCreateInfo<'pool> {
#[inline]
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[inline]
#[must_use]
pub fn set_within_budget(mut self, value: bool) -> Self {
self.within_budget = value;
self
}
#[inline]
#[must_use]
pub fn set_dedicated_memory(mut self, value: bool) -> Self {
self.dedicated_memory = value;
self
}
#[inline]
#[must_use]
pub fn set_memory_allocate_next(mut self, value: Option<AllocationChain<'pool>>) -> Self {
self.memory_allocate_next = value;
self
}
#[inline]
#[must_use]
pub fn set_never_allocate(mut self, value: bool) -> Self {
self.never_allocate = value;
self
}
#[inline]
#[must_use]
pub fn set_can_alias(mut self, value: bool) -> Self {
self.can_alias = value;
self
}
#[inline]
#[must_use]
pub fn set_priority(mut self, value: MemoryPriority) -> Self {
self.priority = value;
self
}
#[inline]
#[must_use]
pub fn set_min_allocation_alignment(mut self, value: u64) -> Self {
self.min_allocation_alignment = value;
self
}
#[inline]
#[must_use]
pub fn set_pool(mut self, value: Option<&'pool Pool>) -> Self {
self.pool = value;
self
}
#[inline]
#[must_use]
pub fn set_usage(mut self, value: MemoryUsage) -> Self {
self.usage = value;
self
}
#[inline]
#[must_use]
pub fn set_host_access(mut self, value: HostAccess) -> Self {
self.host_access = value;
self
}
#[inline]
#[must_use]
pub fn set_allow_transfer_instead(mut self, value: bool) -> Self {
self.allow_transfer_instead = value;
self
}
#[inline]
#[must_use]
pub fn set_avoided_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
self.avoided_flags = value;
self
}
#[inline]
#[must_use]
pub fn set_required_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
self.required_flags = value;
self
}
#[inline]
#[must_use]
pub fn set_preferred_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
self.preferred_flags = value;
self
}
#[inline]
#[must_use]
pub fn set_memory_type_bits(mut self, value: u32) -> Self {
self.memory_type_bits = value;
self
}
#[inline]
#[must_use]
pub fn set_strategy(mut self, value: PlacementStrategy) -> Self {
self.strategy = value;
self
}
#[inline]
#[must_use]
pub fn set_upper_address(mut self, value: bool) -> Self {
self.upper_address = value;
self
}
#[inline]
#[must_use]
pub fn set_policy(mut self, value: AllocationPolicy) -> Self {
self.policy = value;
self
}
#[inline]
#[must_use]
pub fn set_persistent_map(mut self, value: bool) -> Self {
self.persistent_map = value;
self
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct AllocationInfo {
pub device_memory: vk::DeviceMemory,
pub offset: u64,
pub size: u64,
pub reserved_size: u64,
pub memory_type_index: u32,
pub heap_index: u32,
pub memory_properties: vk::MemoryPropertyFlags,
pub mapped_pointer: Option<*mut std::ffi::c_void>,
pub map_count: u32,
pub native_size: u64,
pub is_separate: bool,
pub user_data: usize,
}
impl AllocationInfo {
#[inline]
#[must_use]
pub fn set_device_memory(mut self, value: vk::DeviceMemory) -> Self {
self.device_memory = value;
self
}
#[inline]
#[must_use]
pub fn set_offset(mut self, value: u64) -> Self {
self.offset = value;
self
}
#[inline]
#[must_use]
pub fn set_size(mut self, value: u64) -> Self {
self.size = value;
self
}
#[inline]
#[must_use]
pub fn set_reserved_size(mut self, value: u64) -> Self {
self.reserved_size = value;
self
}
#[inline]
#[must_use]
pub fn set_memory_type_index(mut self, value: u32) -> Self {
self.memory_type_index = value;
self
}
#[inline]
#[must_use]
pub fn set_heap_index(mut self, value: u32) -> Self {
self.heap_index = value;
self
}
#[inline]
#[must_use]
pub fn set_memory_properties(mut self, value: vk::MemoryPropertyFlags) -> Self {
self.memory_properties = value;
self
}
#[inline]
#[must_use]
pub fn set_mapped_pointer(mut self, value: Option<*mut std::ffi::c_void>) -> Self {
self.mapped_pointer = value;
self
}
#[inline]
#[must_use]
pub fn set_map_count(mut self, value: u32) -> Self {
self.map_count = value;
self
}
#[inline]
#[must_use]
pub fn set_native_size(mut self, value: u64) -> Self {
self.native_size = value;
self
}
#[inline]
#[must_use]
pub fn set_is_separate(mut self, value: bool) -> Self {
self.is_separate = value;
self
}
#[inline]
#[must_use]
pub fn set_user_data(mut self, value: usize) -> Self {
self.user_data = value;
self
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct AllocatorStats {
pub allocation_count: usize,
pub native_allocation_count: usize,
pub pooled_block_count: usize,
pub allocation_bytes: u64,
pub reserved_bytes: u64,
pub native_bytes: u64,
pub mapped_native_count: usize,
}
impl AllocatorStats {
#[inline]
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[inline]
#[must_use]
pub fn set_allocation_count(mut self, value: usize) -> Self {
self.allocation_count = value;
self
}
#[inline]
#[must_use]
pub fn set_native_allocation_count(mut self, value: usize) -> Self {
self.native_allocation_count = value;
self
}
#[inline]
#[must_use]
pub fn set_pooled_block_count(mut self, value: usize) -> Self {
self.pooled_block_count = value;
self
}
#[inline]
#[must_use]
pub fn set_allocation_bytes(mut self, value: u64) -> Self {
self.allocation_bytes = value;
self
}
#[inline]
#[must_use]
pub fn set_reserved_bytes(mut self, value: u64) -> Self {
self.reserved_bytes = value;
self
}
#[inline]
#[must_use]
pub fn set_native_bytes(mut self, value: u64) -> Self {
self.native_bytes = value;
self
}
#[inline]
#[must_use]
pub fn set_mapped_native_count(mut self, value: usize) -> Self {
self.mapped_native_count = value;
self
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum BudgetSource {
#[default]
Local,
Extension,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct HeapBudget {
pub size: u64,
pub limit: u64,
pub budget: u64,
pub usage: u64,
pub native_bytes: u64,
}
impl HeapBudget {
#[inline]
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[inline]
#[must_use]
pub fn set_size(mut self, value: u64) -> Self {
self.size = value;
self
}
#[inline]
#[must_use]
pub fn set_limit(mut self, value: u64) -> Self {
self.limit = value;
self
}
#[inline]
#[must_use]
pub fn set_budget(mut self, value: u64) -> Self {
self.budget = value;
self
}
#[inline]
#[must_use]
pub fn set_usage(mut self, value: u64) -> Self {
self.usage = value;
self
}
#[inline]
#[must_use]
pub fn set_native_bytes(mut self, value: u64) -> Self {
self.native_bytes = value;
self
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct BudgetSnapshot {
pub source: BudgetSource,
pub heap_count: u32,
pub heaps: [HeapBudget; 16],
}
impl BudgetSnapshot {
#[inline]
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[inline]
#[must_use]
pub fn set_source(mut self, value: BudgetSource) -> Self {
self.source = value;
self
}
#[inline]
#[must_use]
pub fn set_heap_count(mut self, value: u32) -> Self {
self.heap_count = value;
self
}
#[inline]
#[must_use]
pub fn set_heaps(mut self, value: [HeapBudget; 16]) -> Self {
self.heaps = value;
self
}
}
#[cfg(test)]
#[path = "../../test/rs/mem/test_host_allocator.rs"]
pub(crate) mod test_host_allocator;