Skip to main content

vk/memory/
allocation.rs

1//! Checked separate or pooled allocation identity and bounded cache ranges.
2
3use super::AllocError;
4use crate::core as vk;
5use std::sync::Arc;
6
7/// One live native region. No implicit free, unmap, submission or wait in Drop.
8pub struct Allocation {
9	pub(crate) handle: vk::DeviceMemory,
10	pub(crate) size: u64,
11	pub(crate) offset: u64,
12	pub(crate) block_size: u64,
13	pub(crate) reserved_size: u64,
14	pub(crate) memory_type_index: u32,
15	pub(crate) heap_index: u32,
16	pub(crate) flags: vk::MemoryPropertyFlags,
17	pub(crate) atom: u64,
18	pub(crate) owner: Arc<()>,
19	pub(crate) serial: u64,
20}
21
22impl Allocation {
23	pub fn handle(&self) -> vk::DeviceMemory {
24		self.handle
25	}
26
27	pub fn offset(&self) -> u64 {
28		self.offset
29	}
30
31	pub fn size(&self) -> u64 {
32		self.size
33	}
34
35	/// Native extent reserved to this region, including non-coherent atom padding.
36	pub fn reserved_size(&self) -> u64 {
37		self.reserved_size
38	}
39
40	pub fn memory_type_index(&self) -> u32 {
41		self.memory_type_index
42	}
43
44	pub fn heap_index(&self) -> u32 {
45		self.heap_index
46	}
47
48	pub fn is_host_coherent(&self) -> bool {
49		self.flags.as_raw() & vk::MemoryPropertyFlagBits::HOST_COHERENT_BIT.as_raw() != 0
50	}
51
52	pub fn is_host_visible(&self) -> bool {
53		self.flags.as_raw() & vk::MemoryPropertyFlagBits::HOST_VISIBLE_BIT.as_raw() != 0
54	}
55
56	pub fn is_freed(&self) -> bool {
57		self.handle.is_null()
58	}
59
60	/// Translate an allocation-relative range to a native block range.
61	/// This does not validate allocator liveness or establish a mapping.
62	///
63	/// Donor: VMA `VmaAllocator_T::GetFlushOrInvalidateRange`.
64	/// Adaptation: checked arithmetic, no-op ranges, allocation-end exception.
65	pub fn mapped_range(
66		&self,
67		offset: u64,
68		size: u64,
69	) -> Result<Option<vk::MappedMemoryRange>, AllocError> {
70		if self.is_freed() {
71			return Err(AllocError::UnknownAllocation);
72		}
73		if !self.is_host_visible() {
74			return Err(AllocError::NotHostVisible);
75		}
76		let end = if size == vk::WHOLE_SIZE {
77			self.size
78		} else {
79			offset.checked_add(size).ok_or(AllocError::InvalidRange)?
80		};
81		if offset > self.size || end > self.size || end < offset {
82			return Err(AllocError::InvalidRange);
83		}
84		if offset == end || self.is_host_coherent() {
85			return Ok(None);
86		}
87		let absolute_end = self
88			.offset
89			.checked_add(end)
90			.ok_or(AllocError::InvalidRange)?;
91		let start = self
92			.offset
93			.checked_add(offset)
94			.ok_or(AllocError::InvalidRange)?
95			& !(self.atom - 1);
96		let rounded = absolute_end
97			.checked_add(self.atom - 1)
98			.map(|v| v & !(self.atom - 1))
99			.unwrap_or(self.block_size)
100			.min(self.block_size);
101		Ok(Some(vk::MappedMemoryRange {
102			memory: self.handle,
103			offset: start,
104			size: rounded - start,
105			..Default::default()
106		}))
107	}
108}
109
110#[cfg(test)]
111#[path = "../../../test/rs/memory/test_allocation.rs"]
112mod tests;