Skip to main content

vk/
mem.rs

1//! Rust-native, VMA-derived allocation, managed buffers/images and virtual placement.
2//!
3//! Free functions and [`Allocator`] methods share one implementation. For example,
4//! [`create_buffer_with_options`] and [`Allocator::create_buffer_with_options`]
5//! create, allocate and bind a managed buffer. The root [`crate::create_buffer`]
6//! is the raw Vulkan operation and creates an unbound buffer.
7//!
8//! Use `use vk::mem as vma;` for a caller-local alias. This adds no wrapper,
9//! runtime cost or second allocator type; [`crate::Allocator`] is [`Allocator`].
10//! Full VMA equivalence, broad concurrent stress, multi-driver execution and
11//! additional platforms remain
12//! unqualified. See the [qualification report](https://github.com/realminc/vk/blob/main/docs/external/qualification.md).
13//!
14//! Every public field on a plain record has a consuming `set_*()` method alongside
15//! direct field access. Default-backed records support `new().set_*()`;
16//! [`AllocRequest`], [`ImportMemoryInfo`] and [`CacheRange`] take required inputs
17//! in `new`. Setters retain borrows and leave validation to the using operation.
18//! Editing a diagnostic snapshot changes only that record, never live allocator
19//! state. Resource identities and owners retain their checked operation APIs.
20//!
21//! Allocator operations do not submit or wait. GPU completion, resource
22//! destruction and host/GPU access ordering remain caller responsibilities.
23
24mod allocation;
25mod allocator;
26mod block;
27mod chain;
28mod granularity;
29mod host;
30mod linear;
31mod metadata;
32mod policy;
33mod resource;
34mod selector;
35mod synchronized;
36pub use synchronized::{SynchronizedAllocator, SynchronizedVirtualBlock};
37mod tlsf;
38pub mod virtual_block;
39
40pub use allocation::Allocation;
41#[cfg(unix)]
42pub use allocator::get_memory_fd;
43#[cfg(all(windows, feature = "platform-win32"))]
44pub use allocator::get_memory_win32_handle;
45pub use allocator::{
46	Allocator, TrimStats, allocate, allocate_dedicated, allocate_for_buffer, allocate_for_image,
47	allocate_with_options, allocation_info, bind_buffer_memory, bind_image_memory, budget_snapshot,
48	close, create_buffer, create_buffer_with_options, create_dedicated_buffer,
49	create_dedicated_image, create_image, create_image_with_options, destroy_buffer, destroy_image,
50	find_memory_type, find_memory_type_for_buffer_info, find_memory_type_for_image_info, flush, free,
51	invalidate, map, mapped_pointer, query_budget, set_heap_limit, statistics, trim,
52	trim_with_budget, unmap,
53};
54pub use allocator::{
55	CacheRange, DetailedStatistics, MemoryStatistics, allocate_many, allocation_name, allocator_info,
56	copy_from_allocation, copy_to_allocation, create_aliasing_buffer, create_aliasing_image,
57	detailed_pool_statistics, detailed_statistics, flush_many, free_many, invalidate_many,
58	memory_properties, memory_type_properties, physical_device_properties, pool_name,
59	set_allocation_name, set_allocation_user_data, set_pool_name, write_statistics_json,
60};
61pub use allocator::{
62	DefragmentationAlgorithm, DefragmentationContext, DefragmentationInfo, DefragmentationMove,
63	DefragmentationPass, DefragmentationResource, DefragmentationStats, begin_defragmentation,
64	begin_defragmentation_with_break, set_allocation_pinned,
65};
66pub use allocator::{
67	Pool, PoolCreateInfo, PoolStats, create_pool, create_pool_with_chain, destroy_pool,
68	pool_statistics, set_mapping_hysteresis, set_preferred_block_size,
69};
70pub use allocator::{bind_buffer_memory2, bind_image_memory2};
71pub use allocator::{check_corruption, check_pool_corruption, set_debug_memory_settings};
72pub use allocator::{external_memory_types, set_external_memory_types};
73pub use allocator::{
74	heap_budgets, refresh_budget, refresh_budget_with_context, set_current_frame_index,
75};
76pub use chain::AllocationChain;
77mod import;
78pub use import::{ImportMemoryInfo, ImportResource};
79pub use metadata::AllocationAlgorithm;
80pub use policy::{HostAccess, MemoryUsage};
81pub use selector::MemoryTypeSelector;
82pub use virtual_block::{
83	PlacementStrategy, VirtualAllocation, VirtualAllocationInfo, VirtualBlock, VirtualBlockDetails,
84	VirtualBlockStats,
85};
86
87use crate::{self as vk, load::CallError};
88
89#[derive(Debug, PartialEq)]
90pub enum AllocError {
91	NoCompatibleMemoryType,
92	InvalidProperties(&'static str),
93	InvalidRequest(&'static str),
94	InvalidRange,
95	UnknownAllocation,
96	UnknownPool,
97	CorruptionDetected {
98		allocation: u64,
99		offset: u64,
100	},
101	WrongAllocator,
102	AlreadyMapped,
103	NotMapped,
104	NotHostVisible,
105	SerialExhausted,
106	SynchronizationPoisoned,
107	HostAllocationFailed,
108	AllocationLimit,
109	OutOfSpace,
110	AllocationTooLarge {
111		requested: u64,
112		limit: u64,
113	},
114	UnsupportedCapability(&'static str),
115	WrongResource,
116	LiveAllocations,
117	LivePools,
118	Closed,
119	Call(CallError),
120	Output {
121		kind: std::io::ErrorKind,
122		code: Option<i32>,
123	},
124}
125
126impl std::fmt::Display for AllocError {
127	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128		write!(f, "allocation error: {self:?}")
129	}
130}
131
132impl std::error::Error for AllocError {}
133
134impl From<crate::ConstructionError> for AllocError {
135	fn from(error: crate::ConstructionError) -> Self {
136		Self::from(CallError::from(error))
137	}
138}
139
140impl From<CallError> for AllocError {
141	fn from(error: CallError) -> Self {
142		Self::Call(error)
143	}
144}
145
146/// Finite native memory priority in the inclusive range 0..=1.
147#[derive(Clone, Copy, Debug, PartialEq, Eq)]
148pub struct MemoryPriority(u32);
149
150impl MemoryPriority {
151	/// Validate a native allocation priority.
152	/// # Errors
153	/// Returns InvalidRequest for NaN, infinities or values outside 0..=1.
154	pub fn new(value: f32) -> Result<Self, AllocError> {
155		if !value.is_finite() || !(0.0..=1.0).contains(&value) {
156			return Err(AllocError::InvalidRequest(
157				"memory priority must be finite and in 0..=1",
158			));
159		}
160		Ok(Self(if value == 0.0 {
161			0.0_f32.to_bits()
162		} else {
163			value.to_bits()
164		}))
165	}
166
167	pub fn get(self) -> f32 {
168		f32::from_bits(self.0)
169	}
170}
171
172impl Default for MemoryPriority {
173	fn default() -> Self {
174		Self(0.5_f32.to_bits())
175	}
176}
177
178/// Opt-in host-visible debug instrumentation, configured before native acquisition.
179/// Guard margins follow VMA's coherent pooled-memory policy. Zero disables guards.
180#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
181pub struct DebugMemorySettings {
182	/// Trailing guard bytes, a multiple of four. Separate native allocations have no guard tail.
183	pub margin: u64,
184	/// Initialize admitted host-visible allocation bytes with VMA's created pattern (0xDC).
185	pub initialize_allocations: bool,
186	/// Overwrite admitted host-visible bytes with VMA's destroyed pattern (0xEF) on release.
187	pub poison_frees: bool,
188}
189
190impl DebugMemorySettings {
191	/// Construct the record with its default state.
192	#[inline]
193	#[must_use]
194	pub fn new() -> Self {
195		Self::default()
196	}
197
198	/// Set [`margin`](Self::margin) and return the updated record.
199	#[inline]
200	#[must_use]
201	pub fn set_margin(mut self, value: u64) -> Self {
202		self.margin = value;
203		self
204	}
205
206	/// Set [`initialize_allocations`](Self::initialize_allocations) and return the updated record.
207	#[inline]
208	#[must_use]
209	pub fn set_initialize_allocations(mut self, value: bool) -> Self {
210		self.initialize_allocations = value;
211		self
212	}
213
214	/// Set [`poison_frees`](Self::poison_frees) and return the updated record.
215	#[inline]
216	#[must_use]
217	pub fn set_poison_frees(mut self, value: bool) -> Self {
218		self.poison_frees = value;
219		self
220	}
221}
222
223/// Informative notifications for actual native memory allocation/free effects.
224/// Callbacks do not allocate Rust metadata and do not own the native memory.
225#[derive(Clone, Copy, Default)]
226pub struct DeviceMemoryCallbacks {
227	pub allocated: Option<
228		unsafe extern "system" fn(vk::DeviceHandle, vk::DeviceMemory, u64, u32, *mut std::ffi::c_void),
229	>,
230	pub freed: Option<
231		unsafe extern "system" fn(vk::DeviceHandle, vk::DeviceMemory, u64, u32, *mut std::ffi::c_void),
232	>,
233	pub p_user_data: *mut std::ffi::c_void,
234}
235
236impl DeviceMemoryCallbacks {
237	/// Construct the record with its default state.
238	#[inline]
239	#[must_use]
240	pub fn new() -> Self {
241		Self::default()
242	}
243
244	/// Set [`allocated`](Self::allocated) and return the updated record.
245	#[inline]
246	#[must_use]
247	pub fn set_allocated(
248		mut self,
249		value: Option<
250			unsafe extern "system" fn(
251				vk::DeviceHandle,
252				vk::DeviceMemory,
253				u64,
254				u32,
255				*mut std::ffi::c_void,
256			),
257		>,
258	) -> Self {
259		self.allocated = value;
260		self
261	}
262
263	/// Set [`freed`](Self::freed) and return the updated record.
264	#[inline]
265	#[must_use]
266	pub fn set_freed(
267		mut self,
268		value: Option<
269			unsafe extern "system" fn(
270				vk::DeviceHandle,
271				vk::DeviceMemory,
272				u64,
273				u32,
274				*mut std::ffi::c_void,
275			),
276		>,
277	) -> Self {
278		self.freed = value;
279		self
280	}
281
282	/// Set [`p_user_data`](Self::p_user_data) and return the updated record.
283	#[inline]
284	#[must_use]
285	pub fn set_p_user_data(mut self, value: *mut std::ffi::c_void) -> Self {
286		self.p_user_data = value;
287		self
288	}
289}
290
291/// Captured native identities. Manual metadata constructors do not invent parent identities.
292#[derive(Clone, Copy, Debug, PartialEq, Eq)]
293pub struct AllocatorInfo {
294	pub device: vk::DeviceHandle,
295	pub instance: Option<vk::InstanceHandle>,
296	pub physical_device: Option<vk::PhysicalDevice>,
297	pub api_version: Option<u32>,
298}
299
300impl AllocatorInfo {
301	/// Set [`device`](Self::device) and return the updated record.
302	#[inline]
303	#[must_use]
304	pub fn set_device(mut self, value: vk::DeviceHandle) -> Self {
305		self.device = value;
306		self
307	}
308
309	/// Set [`instance`](Self::instance) and return the updated record.
310	#[inline]
311	#[must_use]
312	pub fn set_instance(mut self, value: Option<vk::InstanceHandle>) -> Self {
313		self.instance = value;
314		self
315	}
316
317	/// Set [`physical_device`](Self::physical_device) and return the updated record.
318	#[inline]
319	#[must_use]
320	pub fn set_physical_device(mut self, value: Option<vk::PhysicalDevice>) -> Self {
321		self.physical_device = value;
322		self
323	}
324
325	/// Set [`api_version`](Self::api_version) and return the updated record.
326	#[inline]
327	#[must_use]
328	pub fn set_api_version(mut self, value: Option<u32>) -> Self {
329		self.api_version = value;
330		self
331	}
332}
333
334pub struct AllocRequest {
335	pub size: u64,
336	pub alignment: u64,
337	pub memory_type_bits: u32,
338	pub required_flags: vk::MemoryPropertyFlags,
339	pub preferred_flags: vk::MemoryPropertyFlags,
340}
341
342impl AllocRequest {
343	/// Construct explicit requirements with no required or preferred properties.
344	/// The selector/allocation operation validates size, alignment and type compatibility.
345	#[inline]
346	#[must_use]
347	pub fn new(size: u64, alignment: u64, memory_type_bits: u32) -> Self {
348		Self {
349			size,
350			alignment,
351			memory_type_bits,
352			required_flags: vk::MemoryPropertyFlags::empty(),
353			preferred_flags: vk::MemoryPropertyFlags::empty(),
354		}
355	}
356
357	/// Set [`size`](Self::size) and return the updated record.
358	#[inline]
359	#[must_use]
360	pub fn set_size(mut self, value: u64) -> Self {
361		self.size = value;
362		self
363	}
364
365	/// Set [`alignment`](Self::alignment) and return the updated record.
366	#[inline]
367	#[must_use]
368	pub fn set_alignment(mut self, value: u64) -> Self {
369		self.alignment = value;
370		self
371	}
372
373	/// Set [`memory_type_bits`](Self::memory_type_bits) and return the updated record.
374	#[inline]
375	#[must_use]
376	pub fn set_memory_type_bits(mut self, value: u32) -> Self {
377		self.memory_type_bits = value;
378		self
379	}
380
381	/// Set [`required_flags`](Self::required_flags) and return the updated record.
382	#[inline]
383	#[must_use]
384	pub fn set_required_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
385		self.required_flags = value;
386		self
387	}
388
389	/// Set [`preferred_flags`](Self::preferred_flags) and return the updated record.
390	#[inline]
391	#[must_use]
392	pub fn set_preferred_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
393		self.preferred_flags = value;
394		self
395	}
396}
397
398/// Managed resource storage policy. Required or preferred native dedication takes precedence.
399#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
400pub enum AllocationPolicy {
401	#[default]
402	Separate,
403	/// Heap-sized default pools with pinned VMA growth, reuse and separate fallback.
404	Automatic,
405	/// Reuse ordinary buffer blocks with this exact native size. No block shrinking.
406	/// Requests larger than the block use separate storage.
407	Pooled { block_size: u64 },
408	/// Try bounded power-of-two block sizes, shrinking only on recoverable storage failure.
409	/// Large regions and exhausted block attempts fall back to separate storage.
410	Adaptive {
411		block_size: u64,
412		min_block_size: u64,
413	},
414}
415
416/// Managed-resource policy, including optional borrowed native allocation storage;
417/// this Rust record is not part of the Vulkan ABI.
418#[derive(Clone, Copy, Debug)]
419pub struct AllocationCreateInfo<'pool> {
420	/// Gate new native memory against owned cached/refreshed budgets; reuse needs no new budget.
421	pub within_budget: bool,
422	/// Force separate native storage, including in automatic custom pools.
423	pub dedicated_memory: bool,
424	/// Borrowed native allocation chain. Implies separate storage; never combined
425	/// with a pool chain. Imports are attempted once and never initialized/poisoned.
426	pub memory_allocate_next: Option<AllocationChain<'pool>>,
427	/// Reuse existing pool storage only; never grow or fall back to separate native storage.
428	pub never_allocate: bool,
429	/// Reserve conservatively for alias resources and omit resource-specific dedication.
430	pub can_alias: bool,
431	/// Non-default priority requires captured enabled EXT_memory_priority.
432	pub priority: MemoryPriority,
433	/// Additional offset alignment; zero means only native/pool/atom constraints.
434	/// Otherwise a power of two, combined with every mandatory alignment.
435	pub min_allocation_alignment: u64,
436	/// Fixed-type custom pool. Overrides `policy`; native type compatibility and
437	/// required properties remain mandatory. No fallback outside this pool.
438	///
439	/// Pool policy storage cannot outlive or be used after destroying its pool:
440	/// ```compile_fail,E0502
441	/// # fn example(allocator: &mut vk::Allocator<'_>, pool: &mut vk::Pool) {
442	/// let options = vk::mem::AllocationCreateInfo::new().set_pool(Some(pool));
443	/// allocator.destroy_pool(pool).unwrap();
444	/// assert!(!options.pool.unwrap().is_destroyed());
445	/// # }
446	/// ```
447	pub pool: Option<&'pool Pool>,
448	pub usage: MemoryUsage,
449	/// Automatic host intent also prefers already mapped compatible blocks.
450	/// Explicit usage retains mapping intent; absence of automatic intent prefers unmapped blocks.
451	pub host_access: HostAccess,
452	/// Permit automatic selection of non-host-visible memory; caller supplies staging.
453	pub allow_transfer_instead: bool,
454	/// Properties penalized during memory-type selection; never a hard exclusion.
455	pub avoided_flags: vk::MemoryPropertyFlags,
456	pub required_flags: vk::MemoryPropertyFlags,
457	pub preferred_flags: vk::MemoryPropertyFlags,
458	/// Intersected with queried native requirements; zero admits no memory types.
459	pub memory_type_bits: u32,
460	/// TLSF block search is forward except MinTime, which searches in reverse.
461	/// Other strategies group host-visible blocks by mapping preference first.
462	pub strategy: PlacementStrategy,
463	/// Allocate downward in a single-block linear custom pool. Other routes reject it.
464	pub upper_address: bool,
465	pub policy: AllocationPolicy,
466	/// Retain a mapping until explicit allocation release. Requires host-visible storage.
467	pub persistent_map: bool,
468}
469
470impl Default for AllocationCreateInfo<'_> {
471	fn default() -> Self {
472		Self {
473			within_budget: false,
474			dedicated_memory: false,
475			memory_allocate_next: None,
476			never_allocate: false,
477			can_alias: false,
478			priority: MemoryPriority::default(),
479			min_allocation_alignment: 0,
480			pool: None,
481			usage: MemoryUsage::Explicit,
482			host_access: HostAccess::None,
483			allow_transfer_instead: false,
484			avoided_flags: vk::MemoryPropertyFlags::empty(),
485			required_flags: vk::MemoryPropertyFlags::empty(),
486			preferred_flags: vk::MemoryPropertyFlags::empty(),
487			memory_type_bits: u32::MAX,
488			strategy: PlacementStrategy::Default,
489			upper_address: false,
490			policy: AllocationPolicy::Separate,
491			persistent_map: false,
492		}
493	}
494}
495
496impl<'pool> AllocationCreateInfo<'pool> {
497	/// Construct the record with its default state.
498	#[inline]
499	#[must_use]
500	pub fn new() -> Self {
501		Self::default()
502	}
503
504	/// Set [`within_budget`](Self::within_budget) and return the updated record.
505	#[inline]
506	#[must_use]
507	pub fn set_within_budget(mut self, value: bool) -> Self {
508		self.within_budget = value;
509		self
510	}
511
512	/// Set [`dedicated_memory`](Self::dedicated_memory) and return the updated record.
513	#[inline]
514	#[must_use]
515	pub fn set_dedicated_memory(mut self, value: bool) -> Self {
516		self.dedicated_memory = value;
517		self
518	}
519
520	/// Set [`memory_allocate_next`](Self::memory_allocate_next) and return the updated record.
521	///
522	/// The descriptor retains its chain storage borrow:
523	/// ```compile_fail,E0597
524	/// # fn example() {
525	/// let options;
526	/// {
527	///     let record = vk::ExportMemoryAllocateInfo::new();
528	///     // SAFETY: this correctly tagged record has no linked or nested storage.
529	///     let chain = unsafe { vk::mem::AllocationChain::new_from_record(&record) }.unwrap();
530	///     options = vk::mem::AllocationCreateInfo::new()
531	///         .set_memory_allocate_next(Some(chain))
532	///         .set_dedicated_memory(true);
533	/// }
534	/// assert!(options.memory_allocate_next.is_some());
535	/// # }
536	/// ```
537	#[inline]
538	#[must_use]
539	pub fn set_memory_allocate_next(mut self, value: Option<AllocationChain<'pool>>) -> Self {
540		self.memory_allocate_next = value;
541		self
542	}
543
544	/// Set [`never_allocate`](Self::never_allocate) and return the updated record.
545	#[inline]
546	#[must_use]
547	pub fn set_never_allocate(mut self, value: bool) -> Self {
548		self.never_allocate = value;
549		self
550	}
551
552	/// Set [`can_alias`](Self::can_alias) and return the updated record.
553	#[inline]
554	#[must_use]
555	pub fn set_can_alias(mut self, value: bool) -> Self {
556		self.can_alias = value;
557		self
558	}
559
560	/// Set [`priority`](Self::priority) and return the updated record.
561	#[inline]
562	#[must_use]
563	pub fn set_priority(mut self, value: MemoryPriority) -> Self {
564		self.priority = value;
565		self
566	}
567
568	/// Set [`min_allocation_alignment`](Self::min_allocation_alignment) and return the updated record.
569	#[inline]
570	#[must_use]
571	pub fn set_min_allocation_alignment(mut self, value: u64) -> Self {
572		self.min_allocation_alignment = value;
573		self
574	}
575
576	/// Set [`pool`](Self::pool) and return the updated record.
577	#[inline]
578	#[must_use]
579	pub fn set_pool(mut self, value: Option<&'pool Pool>) -> Self {
580		self.pool = value;
581		self
582	}
583
584	/// Set [`usage`](Self::usage) and return the updated record.
585	#[inline]
586	#[must_use]
587	pub fn set_usage(mut self, value: MemoryUsage) -> Self {
588		self.usage = value;
589		self
590	}
591
592	/// Set [`host_access`](Self::host_access) and return the updated record.
593	#[inline]
594	#[must_use]
595	pub fn set_host_access(mut self, value: HostAccess) -> Self {
596		self.host_access = value;
597		self
598	}
599
600	/// Set [`allow_transfer_instead`](Self::allow_transfer_instead) and return the updated record.
601	#[inline]
602	#[must_use]
603	pub fn set_allow_transfer_instead(mut self, value: bool) -> Self {
604		self.allow_transfer_instead = value;
605		self
606	}
607
608	/// Set [`avoided_flags`](Self::avoided_flags) and return the updated record.
609	#[inline]
610	#[must_use]
611	pub fn set_avoided_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
612		self.avoided_flags = value;
613		self
614	}
615
616	/// Set [`required_flags`](Self::required_flags) and return the updated record.
617	#[inline]
618	#[must_use]
619	pub fn set_required_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
620		self.required_flags = value;
621		self
622	}
623
624	/// Set [`preferred_flags`](Self::preferred_flags) and return the updated record.
625	#[inline]
626	#[must_use]
627	pub fn set_preferred_flags(mut self, value: vk::MemoryPropertyFlags) -> Self {
628		self.preferred_flags = value;
629		self
630	}
631
632	/// Set [`memory_type_bits`](Self::memory_type_bits) and return the updated record.
633	#[inline]
634	#[must_use]
635	pub fn set_memory_type_bits(mut self, value: u32) -> Self {
636		self.memory_type_bits = value;
637		self
638	}
639
640	/// Set [`strategy`](Self::strategy) and return the updated record.
641	#[inline]
642	#[must_use]
643	pub fn set_strategy(mut self, value: PlacementStrategy) -> Self {
644		self.strategy = value;
645		self
646	}
647
648	/// Set [`upper_address`](Self::upper_address) and return the updated record.
649	#[inline]
650	#[must_use]
651	pub fn set_upper_address(mut self, value: bool) -> Self {
652		self.upper_address = value;
653		self
654	}
655
656	/// Set [`policy`](Self::policy) and return the updated record.
657	#[inline]
658	#[must_use]
659	pub fn set_policy(mut self, value: AllocationPolicy) -> Self {
660		self.policy = value;
661		self
662	}
663
664	/// Set [`persistent_map`](Self::persistent_map) and return the updated record.
665	#[inline]
666	#[must_use]
667	pub fn set_persistent_map(mut self, value: bool) -> Self {
668		self.persistent_map = value;
669		self
670	}
671}
672
673/// Checked binding and mapping snapshot of one live allocation.
674///
675/// Offsets and sizes are native bytes. `size` is the queried memory requirement,
676/// not necessarily the logical buffer size or a linear image's pixel extent.
677/// Copying a snapshot does not retain its allocation, mapping or native objects.
678/// Query again after mapping changes; never use a saved pointer after unmap/free.
679#[derive(Clone, Copy, Debug, PartialEq, Eq)]
680pub struct AllocationInfo {
681	pub device_memory: vk::DeviceMemory,
682	pub offset: u64,
683	pub size: u64,
684	/// Includes non-coherent atom padding reserved to a pooled region.
685	pub reserved_size: u64,
686	pub memory_type_index: u32,
687	pub heap_index: u32,
688	/// Actual selected memory properties, rather than requested preferences.
689	pub memory_properties: vk::MemoryPropertyFlags,
690	/// Allocation-relative pointer, present only for this region's mapping hold.
691	/// Observing this pointer does not acquire a hold or authorize dereferencing it.
692	pub mapped_pointer: Option<*mut std::ffi::c_void>,
693	/// Explicit mapping holds; persistent mapping is independent.
694	pub map_count: u32,
695	/// Size of the backing native memory object, including other pooled regions.
696	pub native_size: u64,
697	/// Separate native storage rather than a pooled placement (not proof of native dedication).
698	pub is_separate: bool,
699	/// Opaque consumer metadata. No dereference or ownership is inferred.
700	pub user_data: usize,
701}
702
703impl AllocationInfo {
704	/// Set [`device_memory`](Self::device_memory) and return the updated record.
705	#[inline]
706	#[must_use]
707	pub fn set_device_memory(mut self, value: vk::DeviceMemory) -> Self {
708		self.device_memory = value;
709		self
710	}
711
712	/// Set [`offset`](Self::offset) and return the updated record.
713	#[inline]
714	#[must_use]
715	pub fn set_offset(mut self, value: u64) -> Self {
716		self.offset = value;
717		self
718	}
719
720	/// Set [`size`](Self::size) and return the updated record.
721	#[inline]
722	#[must_use]
723	pub fn set_size(mut self, value: u64) -> Self {
724		self.size = value;
725		self
726	}
727
728	/// Set [`reserved_size`](Self::reserved_size) and return the updated record.
729	#[inline]
730	#[must_use]
731	pub fn set_reserved_size(mut self, value: u64) -> Self {
732		self.reserved_size = value;
733		self
734	}
735
736	/// Set [`memory_type_index`](Self::memory_type_index) and return the updated record.
737	#[inline]
738	#[must_use]
739	pub fn set_memory_type_index(mut self, value: u32) -> Self {
740		self.memory_type_index = value;
741		self
742	}
743
744	/// Set [`heap_index`](Self::heap_index) and return the updated record.
745	#[inline]
746	#[must_use]
747	pub fn set_heap_index(mut self, value: u32) -> Self {
748		self.heap_index = value;
749		self
750	}
751
752	/// Set [`memory_properties`](Self::memory_properties) and return the updated record.
753	#[inline]
754	#[must_use]
755	pub fn set_memory_properties(mut self, value: vk::MemoryPropertyFlags) -> Self {
756		self.memory_properties = value;
757		self
758	}
759
760	/// Set [`mapped_pointer`](Self::mapped_pointer) and return the updated record.
761	#[inline]
762	#[must_use]
763	pub fn set_mapped_pointer(mut self, value: Option<*mut std::ffi::c_void>) -> Self {
764		self.mapped_pointer = value;
765		self
766	}
767
768	/// Set [`map_count`](Self::map_count) and return the updated record.
769	#[inline]
770	#[must_use]
771	pub fn set_map_count(mut self, value: u32) -> Self {
772		self.map_count = value;
773		self
774	}
775
776	/// Set [`native_size`](Self::native_size) and return the updated record.
777	#[inline]
778	#[must_use]
779	pub fn set_native_size(mut self, value: u64) -> Self {
780		self.native_size = value;
781		self
782	}
783
784	/// Set [`is_separate`](Self::is_separate) and return the updated record.
785	#[inline]
786	#[must_use]
787	pub fn set_is_separate(mut self, value: bool) -> Self {
788		self.is_separate = value;
789		self
790	}
791
792	/// Set [`user_data`](Self::user_data) and return the updated record.
793	#[inline]
794	#[must_use]
795	pub fn set_user_data(mut self, value: usize) -> Self {
796		self.user_data = value;
797		self
798	}
799}
800
801/// Local accounting snapshot; excludes allocations made by other allocators/raw calls.
802#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
803pub struct AllocatorStats {
804	pub allocation_count: usize,
805	pub native_allocation_count: usize,
806	pub pooled_block_count: usize,
807	/// Sum of native requirements sizes, or full accounted external import extents.
808	pub allocation_bytes: u64,
809	/// Includes cache-atom padding reserved to live pooled regions.
810	pub reserved_bytes: u64,
811	pub native_bytes: u64,
812	pub mapped_native_count: usize,
813}
814
815impl AllocatorStats {
816	/// Construct the record with its default state.
817	#[inline]
818	#[must_use]
819	pub fn new() -> Self {
820		Self::default()
821	}
822
823	/// Set [`allocation_count`](Self::allocation_count) and return the updated record.
824	#[inline]
825	#[must_use]
826	pub fn set_allocation_count(mut self, value: usize) -> Self {
827		self.allocation_count = value;
828		self
829	}
830
831	/// Set [`native_allocation_count`](Self::native_allocation_count) and return the updated record.
832	#[inline]
833	#[must_use]
834	pub fn set_native_allocation_count(mut self, value: usize) -> Self {
835		self.native_allocation_count = value;
836		self
837	}
838
839	/// Set [`pooled_block_count`](Self::pooled_block_count) and return the updated record.
840	#[inline]
841	#[must_use]
842	pub fn set_pooled_block_count(mut self, value: usize) -> Self {
843		self.pooled_block_count = value;
844		self
845	}
846
847	/// Set [`allocation_bytes`](Self::allocation_bytes) and return the updated record.
848	#[inline]
849	#[must_use]
850	pub fn set_allocation_bytes(mut self, value: u64) -> Self {
851		self.allocation_bytes = value;
852		self
853	}
854
855	/// Set [`reserved_bytes`](Self::reserved_bytes) and return the updated record.
856	#[inline]
857	#[must_use]
858	pub fn set_reserved_bytes(mut self, value: u64) -> Self {
859		self.reserved_bytes = value;
860		self
861	}
862
863	/// Set [`native_bytes`](Self::native_bytes) and return the updated record.
864	#[inline]
865	#[must_use]
866	pub fn set_native_bytes(mut self, value: u64) -> Self {
867		self.native_bytes = value;
868		self
869	}
870
871	/// Set [`mapped_native_count`](Self::mapped_native_count) and return the updated record.
872	#[inline]
873	#[must_use]
874	pub fn set_mapped_native_count(mut self, value: usize) -> Self {
875		self.mapped_native_count = value;
876		self
877	}
878}
879
880/// Budget provenance. Heap-size/local accounting does not measure external pressure.
881#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
882pub enum BudgetSource {
883	#[default]
884	Local,
885	Extension,
886}
887
888/// One heap at the explicit snapshot boundary. Budget/usage can change immediately.
889#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
890pub struct HeapBudget {
891	pub size: u64,
892	pub limit: u64,
893	pub budget: u64,
894	pub usage: u64,
895	pub native_bytes: u64,
896}
897
898impl HeapBudget {
899	/// Construct the record with its default state.
900	#[inline]
901	#[must_use]
902	pub fn new() -> Self {
903		Self::default()
904	}
905
906	/// Set [`size`](Self::size) and return the updated record.
907	#[inline]
908	#[must_use]
909	pub fn set_size(mut self, value: u64) -> Self {
910		self.size = value;
911		self
912	}
913
914	/// Set [`limit`](Self::limit) and return the updated record.
915	#[inline]
916	#[must_use]
917	pub fn set_limit(mut self, value: u64) -> Self {
918		self.limit = value;
919		self
920	}
921
922	/// Set [`budget`](Self::budget) and return the updated record.
923	#[inline]
924	#[must_use]
925	pub fn set_budget(mut self, value: u64) -> Self {
926		self.budget = value;
927		self
928	}
929
930	/// Set [`usage`](Self::usage) and return the updated record.
931	#[inline]
932	#[must_use]
933	pub fn set_usage(mut self, value: u64) -> Self {
934		self.usage = value;
935		self
936	}
937
938	/// Set [`native_bytes`](Self::native_bytes) and return the updated record.
939	#[inline]
940	#[must_use]
941	pub fn set_native_bytes(mut self, value: u64) -> Self {
942		self.native_bytes = value;
943		self
944	}
945}
946
947#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
948pub struct BudgetSnapshot {
949	pub source: BudgetSource,
950	pub heap_count: u32,
951	pub heaps: [HeapBudget; 16],
952}
953
954impl BudgetSnapshot {
955	/// Construct the record with its default state.
956	#[inline]
957	#[must_use]
958	pub fn new() -> Self {
959		Self::default()
960	}
961
962	/// Set [`source`](Self::source) and return the updated record.
963	#[inline]
964	#[must_use]
965	pub fn set_source(mut self, value: BudgetSource) -> Self {
966		self.source = value;
967		self
968	}
969
970	/// Set [`heap_count`](Self::heap_count) and return the updated record.
971	#[inline]
972	#[must_use]
973	pub fn set_heap_count(mut self, value: u32) -> Self {
974		self.heap_count = value;
975		self
976	}
977
978	/// Set [`heaps`](Self::heaps) and return the updated record.
979	#[inline]
980	#[must_use]
981	pub fn set_heaps(mut self, value: [HeapBudget; 16]) -> Self {
982		self.heaps = value;
983		self
984	}
985}
986
987#[cfg(test)]
988#[path = "../../test/rs/mem/test_host_allocator.rs"]
989pub(crate) mod test_host_allocator;