vulkano/memory/allocator/mod.rs
1//! In Vulkan, suballocation of [`DeviceMemory`] is left to the application, because every
2//! application has slightly different needs and one can not incorporate an allocator into the
3//! driver that would perform well in all cases. Vulkano stays true to this sentiment, but aims to
4//! reduce the burden on the user as much as possible. You have a toolbox of [suballocators] to
5//! choose from that cover all allocation algorithms, which you can compose into any kind of
6//! [hierarchy] you wish. This way you have maximum flexibility while still only using a few
7//! `DeviceMemory` blocks and not writing any of the very error-prone code.
8//!
9//! If you just want to allocate memory and don't have any special needs, look no further than the
10//! [`StandardMemoryAllocator`].
11//!
12//! # Why not just allocate `DeviceMemory`?
13//!
14//! But the driver has an allocator! Otherwise you wouldn't be able to allocate `DeviceMemory`,
15//! right? Indeed, but that allocation is very expensive. Not only that, there is also a pretty low
16//! limit on the number of allocations by the drivers. See, everything in Vulkan tries to keep you
17//! away from allocating `DeviceMemory` too much. These limits are used by the implementation to
18//! optimize on its end, while the application optimizes on the other end.
19//!
20//! # Alignment
21//!
22//! At the end of the day, memory needs to be backed by hardware somehow. A *memory cell* stores a
23//! single *bit*, bits are grouped into *bytes* and bytes are grouped into *words*. Intuitively, it
24//! should make sense that accessing single bits at a time would be very inefficient. That is why
25//! computers always access a whole word of memory at once, at least. That means that if you tried
26//! to do an unaligned access, you would need to access twice the number of memory locations.
27//!
28//! Example aligned access, performing bitwise NOT on the (64-bit) word at offset 0x08:
29//!
30//! ```plain
31//! | 08 | 10 | 18
32//! ----+-------------------------+-------------------------+----
33//! ••• | 35 35 35 35 35 35 35 35 | 01 23 45 67 89 ab cd ef | •••
34//! ----+-------------------------+-------------------------+----
35//! , | ,
36//! +------------|------------+
37//! ' v '
38//! ----+-------------------------+-------------------------+----
39//! ••• | ca ca ca ca ca ca ca ca | 01 23 45 67 89 ab cd ef | •••
40//! ----+-------------------------+-------------------------+----
41//! ```
42//!
43//! Same example as above, but this time unaligned with a word at offset 0x0a:
44//!
45//! ```plain
46//! | 08 0a | 10 | 18
47//! ----+-------------------------+-------------------------+----
48//! ••• | cd ef 35 35 35 35 35 35 | 35 35 01 23 45 67 89 ab | •••
49//! ----+-------------------------+-------------------------+----
50//! , | ,
51//! +------------|------------+
52//! ' v '
53//! ----+-------------------------+-------------------------+----
54//! ••• | cd ef ca ca ca ca ca ca | ca ca 01 23 45 67 89 ab | •••
55//! ----+-------------------------+-------------------------+----
56//! ```
57//!
58//! As you can see, in the unaligned case the hardware would need to read both the word at offset
59//! 0x08 and the word at the offset 0x10 and then shift the bits from one register into the other.
60//! Safe to say it should to be avoided, and this is why we need alignment. This example also goes
61//! to show how inefficient unaligned writes are. Say you pieced together your word as described,
62//! and now you want to perform the bitwise NOT and write the result back. Difficult, isn't it?
63//! That's due to the fact that even though the chunks occupy different ranges in memory, they are
64//! still said to *alias* each other, because if you try to write to one memory location, you would
65//! be overwriting 2 or more different chunks of data.
66//!
67//! ## Pages
68//!
69//! It doesn't stop at the word, though. Words are further grouped into *pages*. These are
70//! typically power-of-two multiples of the word size, much like words are typically powers of two
71//! themselves. You can easily extend the concepts from the previous examples to pages if you think
72//! of the examples as having a page size of 1 word. Two resources are said to alias if they share
73//! a page, and therefore should be aligned to the page size. What the page size is depends on the
74//! context, and a computer might have multiple different ones for different parts of hardware.
75//!
76//! ## Memory requirements
77//!
78//! A Vulkan device might have any number of reasons it would want certain alignments for certain
79//! resources. For example, the device might have different caches for different types of
80//! resources, which have different page sizes. Maybe the device wants to store images in some
81//! other cache compared to buffers which needs different alignment. Or maybe images of different
82//! layouts require different alignment, or buffers with different usage/mapping do. The specifics
83//! don't matter in the end, this just goes to illustrate the point. This is why memory
84//! requirements in Vulkan vary not only with the Vulkan implementation, but also with the type of
85//! resource.
86//!
87//! ## Buffer-image granularity
88//!
89//! This unfortunately named granularity is the page size which a linear resource neighboring a
90//! non-linear resource must be aligned to in order for them not to alias. The difference between
91//! the memory requirements of the individual resources and the [buffer-image granularity] is that
92//! the memory requirements only apply to the resource they are for, while the buffer-image
93//! granularity applies to two neighboring resources. For example, you might create two buffers,
94//! which might have two different memory requirements, but as long as those are satisfied, you can
95//! put these buffers cheek to cheek. On the other hand, if one of them is an (optimal layout)
96//! image, then they must not share any page, whose size is given by this granularity. The Vulkan
97//! implementation can use this for additional optimizations if it needs to, or report a
98//! granularity of 1.
99//!
100//! # Fragmentation
101//!
102//! Memory fragmentation refers to the wastage of memory that results from alignment requirements
103//! and/or dynamic memory allocation. As such, some level of fragmentation is always going to be
104//! inevitable. Different allocation algorithms each have their own characteristics and trade-offs
105//! in relation to fragmentation.
106//!
107//! ## Internal Fragmentation
108//!
109//! This type of fragmentation arises from alignment requirements. These might be imposed by the
110//! Vulkan implementation or the application itself.
111//!
112//! Say for example your allocations need to be aligned to 64B, then any allocation whose size is
113//! not a multiple of the alignment will need padding at the end:
114//!
115//! ```plain
116//! | 0x040 | 0x080 | 0x0c0 | 0x100
117//! ----+------------------+------------------+------------------+--------
118//! | ############ | ################ | ######## | #######
119//! ••• | ### 48 B ### | ##### 64 B ##### | # 32 B # | ### •••
120//! | ############ | ################ | ######## | #######
121//! ----+------------------+------------------+------------------+--------
122//! ```
123//!
124//! If this alignment is imposed by the Vulkan implementation, then there's nothing one can do
125//! about this. Simply put, that space is unusable. One also shouldn't want to do anything about
126//! it, since these requirements have very good reasons, as described in further detail in previous
127//! sections. They prevent resources from aliasing so that performance is optimal.
128//!
129//! It might seem strange that the application would want to cause internal fragmentation itself,
130//! but this is often a good trade-off to reduce or even completely eliminate external
131//! fragmentation. Internal fragmentation is very predictable, which makes it easier to deal with.
132//!
133//! ## External fragmentation
134//!
135//! With external fragmentation, what happens is that while the allocations might be using their
136//! own memory totally efficiently, the way they are arranged in relation to each other would
137//! prevent a new contiguous chunk of memory to be allocated even though there is enough free space
138//! left. That is why this fragmentation is said to be external to the allocations. Also, the
139//! allocations together with the fragments in-between add overhead both in terms of space and time
140//! to the allocator, because it needs to keep track of more things overall.
141//!
142//! As an example, take these 4 allocations within some block, with the rest of the block assumed
143//! to be full:
144//!
145//! ```plain
146//! +-----+-------------------+-------+-----------+-- - - --+
147//! | | | | | |
148//! | A | B | C | D | ••• |
149//! | | | | | |
150//! +-----+-------------------+-------+-----------+-- - - --+
151//! ```
152//!
153//! The allocations were all done in order, and naturally there is no fragmentation at this point.
154//! Now if we free B and D, since these are done out of order, we will be left with holes between
155//! the other allocations, and we won't be able to fit allocation E anywhere:
156//!
157//! ```plain
158//! +-----+-------------------+-------+-----------+-- - - --+ +-------------------------+
159//! | | | | | | ? | |
160//! | A | | C | | ••• | <== | E |
161//! | | | | | | | |
162//! +-----+-------------------+-------+-----------+-- - - --+ +-------------------------+
163//! ```
164//!
165//! So fine, we use a different block for E, and just use this block for allocations that fit:
166//!
167//! ```plain
168//! +-----+---+-----+---------+-------+-----+-----+-- - - --+
169//! | | | | | | | | |
170//! | A | H | I | J | C | F | G | ••• |
171//! | | | | | | | | |
172//! +-----+---+-----+---------+-------+-----+-----+-- - - --+
173//! ```
174//!
175//! Sure, now let's free some shall we? And voilà, the problem just became much worse:
176//!
177//! ```plain
178//! +-----+---+-----+---------+-------+-----+-----+-- - - --+
179//! | | | | | | | | |
180//! | A | | I | J | | F | | ••• |
181//! | | | | | | | | |
182//! +-----+---+-----+---------+-------+-----+-----+-- - - --+
183//! ```
184//!
185//! # Leakage
186//!
187//! Memory leaks happen when allocations are kept alive past their shelf life. This most often
188//! occurs because of [cyclic references]. If you have structures that have cycles, then make sure
189//! you read the documentation for [`Arc`]/[`Rc`] carefully to avoid memory leaks. You can also
190//! introduce memory leaks willingly by using [`mem::forget`] or [`Box::leak`] to name a few. In
191//! all of these examples the memory can never be reclaimed, but that doesn't have to be the case
192//! for something to be considered a leak. Say for example you have a [region] which you
193//! suballocate, and at some point you drop all the suballocations. When that happens, the region
194//! can be returned (freed) to the next level up the hierarchy, or it can be reused by another
195//! suballocator. But if you happen to keep alive just one suballocation for the duration of the
196//! program for instance, then the whole region is also kept as it is for that time (and keep in
197//! mind this bubbles up the hierarchy). Therefore, for the program, that memory might be a leak
198//! depending on the allocator, because some allocators wouldn't be able to reuse the entire rest
199//! of the region. You must always consider the lifetime of your resources when choosing the
200//! appropriate allocator.
201//!
202//! [suballocators]: Suballocator
203//! [hierarchy]: Suballocator#memory-hierarchies
204//! [buffer-image granularity]: crate::device::DeviceProperties::buffer_image_granularity
205//! [cyclic references]: Arc#breaking-cycles-with-weak
206//! [`Rc`]: std::rc::Rc
207//! [region]: Suballocator#regions
208
209use self::{aliasable_box::AliasableBox, array_vec::ArrayVec, suballocator::Region};
210pub use self::{
211 layout::DeviceLayout,
212 suballocator::{
213 AllocationType, BuddyAllocator, BumpAllocator, FreeListAllocator, Suballocation,
214 Suballocator, SuballocatorError,
215 },
216};
217use super::{
218 DedicatedAllocation, DeviceAlignment, DeviceMemory, ExternalMemoryHandleTypes,
219 MemoryAllocateFlags, MemoryAllocateInfo, MemoryMapFlags, MemoryMapInfo, MemoryProperties,
220 MemoryPropertyFlags, MemoryRequirements, MemoryType,
221};
222use crate::{
223 device::{Device, DeviceOwned},
224 instance::InstanceOwnedDebugWrapper,
225 DeviceSize, Validated, Version, VulkanError,
226};
227use ash::vk::MAX_MEMORY_TYPES;
228use parking_lot::{Mutex, MutexGuard};
229use slabbin::SlabAllocator;
230use std::{
231 error::Error,
232 fmt::{Debug, Display, Error as FmtError, Formatter},
233 iter::FusedIterator,
234 mem,
235 ops::BitOr,
236 ptr, slice,
237 sync::Arc,
238};
239
240mod layout;
241pub mod suballocator;
242
243/// General-purpose memory allocators which allocate from any memory type dynamically as needed.
244///
245/// # Safety
246///
247/// - `allocate`, `allocate_from_type` and `allocate_dedicated` must return a memory block that is
248/// in bounds of its device memory.
249/// - `allocate` and `allocate_from_type` must return a memory block that doesn't alias any other
250/// currently allocated memory blocks:
251/// - Two currently allocated memory blocks must not share any memory locations, meaning that the
252/// intersection of the byte ranges of the two memory blocks must be empty.
253/// - Two neighboring currently allocated memory blocks must not share any [page] whose size is
254/// given by the [buffer-image granularity], unless either both were allocated with
255/// [`AllocationType::Linear`] or both were allocated with [`AllocationType::NonLinear`].
256/// - For all [host-visible] memory types that are not [host-coherent], all memory blocks must be
257/// aligned to the [non-coherent atom size].
258/// - The size does **not** have to be padded to the alignment. That is, as long the offset is
259/// aligned and the memory blocks don't share any memory locations, a memory block is not
260/// considered to alias another even if the padded size shares memory locations with another
261/// memory block.
262/// - A memory block must stay allocated until either `deallocate` is called on it or the allocator
263/// is dropped. If the allocator is cloned, it must produce the same allocator, and memory blocks
264/// must stay allocated until either `deallocate` is called on the memory block using any of the
265/// clones or all of the clones have been dropped.
266///
267/// [page]: self#pages
268/// [buffer-image granularity]: self#buffer-image-granularity
269/// [host-visible]: MemoryPropertyFlags::HOST_VISIBLE
270/// [host-coherent]: MemoryPropertyFlags::HOST_COHERENT
271/// [non-coherent atom size]: crate::device::DeviceProperties::non_coherent_atom_size
272pub unsafe trait MemoryAllocator: DeviceOwned + Send + Sync + 'static {
273 /// Finds the most suitable memory type index in `memory_type_bits` using the given `filter`.
274 /// Returns [`None`] if the requirements are too strict and no memory type is able to satisfy
275 /// them.
276 fn find_memory_type_index(
277 &self,
278 memory_type_bits: u32,
279 filter: MemoryTypeFilter,
280 ) -> Option<u32>;
281
282 /// Allocates memory from a specific memory type.
283 ///
284 /// # Arguments
285 ///
286 /// - `memory_type_index` - The index of the memory type to allocate from.
287 ///
288 /// - `layout` - The layout of the allocation.
289 ///
290 /// - `allocation_type` - The type of resources that can be bound to the allocation.
291 ///
292 /// - `never_allocate` - If `true` then the allocator should never allocate `DeviceMemory`,
293 /// instead only suballocate from existing blocks.
294 fn allocate_from_type(
295 &self,
296 memory_type_index: u32,
297 layout: DeviceLayout,
298 allocation_type: AllocationType,
299 never_allocate: bool,
300 ) -> Result<MemoryAlloc, MemoryAllocatorError>;
301
302 /// Allocates memory according to requirements.
303 ///
304 /// # Arguments
305 ///
306 /// - `requirements` - Requirements of the resource you want to allocate memory for.
307 ///
308 /// If you plan to bind this memory directly to a non-sparse resource, then this must
309 /// correspond to the value returned by either [`RawBuffer::memory_requirements`] or
310 /// [`RawImage::memory_requirements`] for the respective buffer or image.
311 ///
312 /// - `allocation_type` - What type of resource this allocation will be used for.
313 ///
314 /// This should be [`Linear`] for buffers and linear images, and [`NonLinear`] for optimal
315 /// images. You can not bind memory allocated with the [`Linear`] type to optimal images or
316 /// bind memory allocated with the [`NonLinear`] type to buffers and linear images. You
317 /// should never use the [`Unknown`] type unless you have to, as that can be less memory
318 /// efficient.
319 ///
320 /// - `dedicated_allocation` - Allows a dedicated allocation to be created.
321 ///
322 /// You should always fill this field in if you are allocating memory for a non-sparse
323 /// resource, otherwise the allocator won't be able to create a dedicated allocation if one
324 /// is required or recommended.
325 ///
326 /// This argument is silently ignored (treated as `None`) if the device API version is below
327 /// 1.1 and the [`khr_dedicated_allocation`] extension is not enabled on the device.
328 ///
329 /// [`RawBuffer::memory_requirements`]: crate::buffer::sys::RawBuffer::memory_requirements
330 /// [`RawImage::memory_requirements`]: crate::image::sys::RawImage::memory_requirements
331 /// [`Linear`]: AllocationType::Linear
332 /// [`NonLinear`]: AllocationType::NonLinear
333 /// [`Unknown`]: AllocationType::Unknown
334 /// [`khr_dedicated_allocation`]: crate::device::DeviceExtensions::khr_dedicated_allocation
335 fn allocate(
336 &self,
337 requirements: MemoryRequirements,
338 allocation_type: AllocationType,
339 create_info: AllocationCreateInfo,
340 dedicated_allocation: Option<DedicatedAllocation<'_>>,
341 ) -> Result<MemoryAlloc, MemoryAllocatorError>;
342
343 /// Creates an allocation with a whole device memory block dedicated to it.
344 fn allocate_dedicated(
345 &self,
346 memory_type_index: u32,
347 allocation_size: DeviceSize,
348 dedicated_allocation: Option<DedicatedAllocation<'_>>,
349 export_handle_types: ExternalMemoryHandleTypes,
350 ) -> Result<MemoryAlloc, MemoryAllocatorError>;
351
352 /// Deallocates the given `allocation`.
353 ///
354 /// # Safety
355 ///
356 /// - `allocation` must refer to a **currently allocated** allocation of `self`.
357 unsafe fn deallocate(&self, allocation: MemoryAlloc);
358}
359
360impl Debug for dyn MemoryAllocator {
361 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
362 f.debug_struct("MemoryAllocator").finish_non_exhaustive()
363 }
364}
365
366/// Describes what memory property flags are required, preferred and not preferred when picking a
367/// memory type index.
368///
369/// # Examples
370///
371/// #### Direct device access only
372///
373/// For resources that the device frequently accesses, e.g. textures, render targets, or
374/// intermediary buffers, you want device-local memory without any host access:
375///
376/// ```
377/// # use vulkano::{
378/// # image::{Image, ImageCreateInfo, ImageUsage},
379/// # memory::allocator::{AllocationCreateInfo, MemoryTypeFilter},
380/// # };
381/// #
382/// # let memory_allocator: std::sync::Arc<vulkano::memory::allocator::StandardMemoryAllocator> = return;
383/// # let format = return;
384/// # let extent = return;
385/// #
386/// let texture = Image::new(
387/// memory_allocator.clone(),
388/// ImageCreateInfo {
389/// format,
390/// extent,
391/// usage: ImageUsage::TRANSFER_DST | ImageUsage::SAMPLED,
392/// ..Default::default()
393/// },
394/// AllocationCreateInfo {
395/// memory_type_filter: MemoryTypeFilter::PREFER_DEVICE,
396/// ..Default::default()
397/// },
398/// )
399/// .unwrap();
400/// ```
401///
402/// #### Sequential writes from host, indirect device access
403///
404/// For staging, the resource is only ever written to sequentially. Also, since the device will
405/// only read the staging resource once, it would yield no benefit to place it in device-local
406/// memory, in fact it would be wasteful. Therefore, it's best to put it in host-local memory:
407///
408/// ```
409/// # use vulkano::{
410/// # buffer::{Buffer, BufferCreateInfo, BufferUsage},
411/// # memory::allocator::{AllocationCreateInfo, MemoryTypeFilter},
412/// # };
413/// #
414/// # let memory_allocator: std::sync::Arc<vulkano::memory::allocator::StandardMemoryAllocator> = return;
415/// #
416/// let staging_buffer = Buffer::new_sized(
417/// memory_allocator.clone(),
418/// BufferCreateInfo {
419/// usage: BufferUsage::TRANSFER_SRC,
420/// ..Default::default()
421/// },
422/// AllocationCreateInfo {
423/// memory_type_filter: MemoryTypeFilter::PREFER_HOST |
424/// MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
425/// ..Default::default()
426/// },
427/// )
428/// .unwrap();
429/// #
430/// # let staging_buffer: vulkano::buffer::Subbuffer<u32> = staging_buffer;
431/// ```
432///
433/// #### Sequential writes from host, direct device access
434///
435/// For resources that the device accesses directly, aka a buffer/image used for anything other
436/// than transfers, it's probably best to put it in device-local memory:
437///
438/// ```
439/// # use vulkano::{
440/// # buffer::{Buffer, BufferCreateInfo, BufferUsage},
441/// # memory::allocator::{AllocationCreateInfo, MemoryTypeFilter},
442/// # };
443/// #
444/// # let memory_allocator: std::sync::Arc<vulkano::memory::allocator::StandardMemoryAllocator> = return;
445/// #
446/// let uniform_buffer = Buffer::new_sized(
447/// memory_allocator.clone(),
448/// BufferCreateInfo {
449/// usage: BufferUsage::UNIFORM_BUFFER,
450/// ..Default::default()
451/// },
452/// AllocationCreateInfo {
453/// memory_type_filter: MemoryTypeFilter::PREFER_DEVICE |
454/// MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
455/// ..Default::default()
456/// },
457/// )
458/// .unwrap();
459/// #
460/// # let uniform_buffer: vulkano::buffer::Subbuffer<u32> = uniform_buffer;
461/// ```
462///
463/// #### Readback to host
464///
465/// For readback, e.g. getting the results of a compute shader back to the host:
466///
467/// ```
468/// # use vulkano::{
469/// # buffer::{Buffer, BufferCreateInfo, BufferUsage},
470/// # memory::allocator::{AllocationCreateInfo, MemoryTypeFilter},
471/// # };
472/// #
473/// # let memory_allocator: std::sync::Arc<vulkano::memory::allocator::StandardMemoryAllocator> = return;
474/// #
475/// let readback_buffer = Buffer::new_sized(
476/// memory_allocator.clone(),
477/// BufferCreateInfo {
478/// usage: BufferUsage::TRANSFER_DST,
479/// ..Default::default()
480/// },
481/// AllocationCreateInfo {
482/// memory_type_filter: MemoryTypeFilter::PREFER_HOST |
483/// MemoryTypeFilter::HOST_RANDOM_ACCESS,
484/// ..Default::default()
485/// },
486/// )
487/// .unwrap();
488/// #
489/// # let readback_buffer: vulkano::buffer::Subbuffer<u32> = readback_buffer;
490/// ```
491#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
492pub struct MemoryTypeFilter {
493 pub required_flags: MemoryPropertyFlags,
494 pub preferred_flags: MemoryPropertyFlags,
495 pub not_preferred_flags: MemoryPropertyFlags,
496}
497
498impl MemoryTypeFilter {
499 /// Prefers picking a memory type with the [`DEVICE_LOCAL`] flag. **It does not affect whether
500 /// the memory is host-visible**. You need to combine this with either the
501 /// [`HOST_SEQUENTIAL_WRITE`] or [`HOST_RANDOM_ACCESS`] filter for that.
502 ///
503 /// Memory being device-local means that it is fastest to access for the device. However,
504 /// for dedicated GPUs, getting memory in and out of VRAM requires to go through the PCIe bus,
505 /// which is very slow and should therefore only be done when necessary.
506 ///
507 /// This filter is best suited for anything that the host doesn't access, but the device
508 /// accesses frequently. For example textures, render targets, and intermediary buffers.
509 ///
510 /// For memory that the host does access but less frequently than the device, such as updating
511 /// a uniform buffer each frame, device-local memory may also be preferred. In this case,
512 /// because the memory is only written once before being consumed by the device and becoming
513 /// outdated, it doesn't matter that the data is potentially transferred over the PCIe bus
514 /// since it only happens once. Since this is only a preference, if you have some requirements
515 /// such as the memory being [`HOST_VISIBLE`], those requirements will take precedence.
516 ///
517 /// For memory that the host doesn't access, and the device doesn't access directly, you may
518 /// still prefer device-local memory if the memory is used regularly. For instance, an image
519 /// that is swapped each frame.
520 ///
521 /// Keep in mind that for implementations with unified memory, there's only system RAM. That
522 /// means that even if the implementation reports a memory type that is not `HOST_VISIBLE` and
523 /// is `DEVICE_LOCAL`, its still the same unified memory as all other memory. However, it may
524 /// still be faster to access. On the other hand, some such implementations don't report any
525 /// memory types that are not `HOST_VISIBLE`, which makes sense since it's all system RAM. In
526 /// that case you wouldn't need to do staging.
527 ///
528 /// Don't use this together with [`PREFER_HOST`], that makes no sense.
529 ///
530 /// [`DEVICE_LOCAL`]: MemoryPropertyFlags::DEVICE_LOCAL
531 /// [`HOST_SEQUENTIAL_WRITE`]: Self::HOST_SEQUENTIAL_WRITE
532 /// [`HOST_RANDOM_ACCESS`]: Self::HOST_RANDOM_ACCESS
533 /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
534 /// [`PREFER_HOST`]: Self::PREFER_HOST
535 pub const PREFER_DEVICE: Self = Self {
536 required_flags: MemoryPropertyFlags::empty(),
537 preferred_flags: MemoryPropertyFlags::DEVICE_LOCAL,
538 not_preferred_flags: MemoryPropertyFlags::empty(),
539 };
540
541 /// Prefers picking a memory type without the [`DEVICE_LOCAL`] flag. **It does not affect
542 /// whether the memory is host-visible**. You need to combine this with either the
543 /// [`HOST_SEQUENTIAL_WRITE`] or [`HOST_RANDOM_ACCESS`] filter for that.
544 ///
545 /// This option is best suited for resources that the host does access, but device doesn't
546 /// access directly, such as staging buffers and readback buffers.
547 ///
548 /// For memory that the host does access but less frequently than the device, such as updating
549 /// a uniform buffer each frame, you may still get away with using host-local memory if the
550 /// updates are small and local enough. In such cases, the memory should be able to be quickly
551 /// cached by the device, such that the data potentially being transferred over the PCIe bus
552 /// wouldn't matter.
553 ///
554 /// For memory that the host doesn't access, and the device doesn't access directly, you may
555 /// still prefer host-local memory if the memory is rarely used, such as for manually paging
556 /// parts of device-local memory out in order to free up space on the device.
557 ///
558 /// Don't use this together with [`PREFER_DEVICE`], that makes no sense.
559 ///
560 /// [`DEVICE_LOCAL`]: MemoryPropertyFlags::DEVICE_LOCAL
561 /// [`HOST_SEQUENTIAL_WRITE`]: Self::HOST_SEQUENTIAL_WRITE
562 /// [`HOST_RANDOM_ACCESS`]: Self::HOST_RANDOM_ACCESS
563 /// [`PREFER_DEVICE`]: Self::PREFER_DEVICE
564 pub const PREFER_HOST: Self = Self {
565 required_flags: MemoryPropertyFlags::empty(),
566 preferred_flags: MemoryPropertyFlags::empty(),
567 not_preferred_flags: MemoryPropertyFlags::DEVICE_LOCAL,
568 };
569
570 /// This guarantees picking a memory type that has the [`HOST_VISIBLE`] flag. **It does not
571 /// affect whether the memory is device-local or host-local**. You need to combine this with
572 /// either the [`PREFER_DEVICE`] or [`PREFER_HOST`] filter for that.
573 ///
574 /// Using this filter allows the allocator to pick a memory type that is uncached and
575 /// write-combined, which is ideal for sequential writes. However, this optimization might lead
576 /// to poor performance for anything else. What counts as a sequential write is any kind of
577 /// loop that writes memory locations in order, such as iterating over a slice while writing
578 /// each element in order, or equivalently using [`slice::copy_from_slice`]. Copying sized data
579 /// also counts, as rustc should write the memory locations in order. If you have a struct,
580 /// make sure you write it member-by-member.
581 ///
582 /// Example use cases include staging buffers, as well as any other kind of buffer that you
583 /// only write to from the host, like a uniform or vertex buffer.
584 ///
585 /// Don't use this together with [`HOST_RANDOM_ACCESS`], that makes no sense. If you do both a
586 /// sequential write and read or random access, then you should use `HOST_RANDOM_ACCESS`
587 /// instead. However, you could also consider using different allocations for the two purposes
588 /// to get the most performance out, if that's possible.
589 ///
590 /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
591 /// [`PREFER_DEVICE`]: Self::PREFER_DEVICE
592 /// [`PREFER_HOST`]: Self::PREFER_HOST
593 /// [`HOST_RANDOM_ACCESS`]: Self::HOST_RANDOM_ACCESS
594 pub const HOST_SEQUENTIAL_WRITE: Self = Self {
595 required_flags: MemoryPropertyFlags::HOST_VISIBLE,
596 preferred_flags: MemoryPropertyFlags::empty(),
597 not_preferred_flags: MemoryPropertyFlags::HOST_CACHED,
598 };
599
600 /// This guarantees picking a memory type that has the [`HOST_VISIBLE`] and [`HOST_CACHED`]
601 /// flags, which is best suited for readback and/or random access. **It does not affect whether
602 /// the memory is device-local or host-local**. You need to combine this with either the
603 /// [`PREFER_DEVICE`] or [`PREFER_HOST`] filter for that.
604 ///
605 /// Example use cases include using the device for things other than rendering and getting the
606 /// results back to the host. That might be compute shading, or image or video manipulation, or
607 /// screenshotting.
608 ///
609 /// Don't use this together with [`HOST_SEQUENTIAL_WRITE`], that makes no sense. If you are
610 /// sure you only ever need to sequentially write to the allocation, then using
611 /// `HOST_SEQUENTIAL_WRITE` instead will yield better performance.
612 ///
613 /// [`HOST_VISIBLE`]: MemoryPropertyFlags::HOST_VISIBLE
614 /// [`HOST_CACHED`]: MemoryPropertyFlags::HOST_CACHED
615 /// [`PREFER_DEVICE`]: Self::PREFER_DEVICE
616 /// [`PREFER_HOST`]: Self::PREFER_HOST
617 /// [`HOST_SEQUENTIAL_WRITE`]: Self::HOST_SEQUENTIAL_WRITE
618 pub const HOST_RANDOM_ACCESS: Self = Self {
619 required_flags: MemoryPropertyFlags::HOST_VISIBLE.union(MemoryPropertyFlags::HOST_CACHED),
620 preferred_flags: MemoryPropertyFlags::empty(),
621 not_preferred_flags: MemoryPropertyFlags::empty(),
622 };
623
624 /// Returns a `MemoryTypeFilter` with none of the flags set.
625 #[inline]
626 pub const fn empty() -> Self {
627 Self {
628 required_flags: MemoryPropertyFlags::empty(),
629 preferred_flags: MemoryPropertyFlags::empty(),
630 not_preferred_flags: MemoryPropertyFlags::empty(),
631 }
632 }
633
634 /// Returns the union of `self` and `other`.
635 #[inline]
636 pub const fn union(self, other: Self) -> Self {
637 Self {
638 required_flags: self.required_flags.union(other.required_flags),
639 preferred_flags: self.preferred_flags.union(other.preferred_flags),
640 not_preferred_flags: self.not_preferred_flags.union(other.not_preferred_flags),
641 }
642 }
643}
644
645impl BitOr for MemoryTypeFilter {
646 type Output = Self;
647
648 #[inline]
649 fn bitor(self, rhs: Self) -> Self::Output {
650 self.union(rhs)
651 }
652}
653
654/// Parameters to create a new [allocation] using a [memory allocator].
655///
656/// [allocation]: MemoryAlloc
657/// [memory allocator]: MemoryAllocator
658#[derive(Clone, Debug)]
659pub struct AllocationCreateInfo {
660 /// Filter used to narrow down the memory type to be selected.
661 ///
662 /// The default value is [`MemoryTypeFilter::PREFER_DEVICE`].
663 pub memory_type_filter: MemoryTypeFilter,
664
665 /// Allows you to further constrain the possible choices of memory types, by only allowing the
666 /// memory type indices that have a corresponding bit at the same index set to 1.
667 ///
668 /// The default value is [`u32::MAX`].
669 pub memory_type_bits: u32,
670
671 /// How eager the allocator should be to allocate [`DeviceMemory`].
672 ///
673 /// The default value is [`MemoryAllocatePreference::Unknown`].
674 pub allocate_preference: MemoryAllocatePreference,
675
676 pub _ne: crate::NonExhaustive,
677}
678
679impl Default for AllocationCreateInfo {
680 #[inline]
681 fn default() -> Self {
682 AllocationCreateInfo {
683 memory_type_filter: MemoryTypeFilter::PREFER_DEVICE,
684 memory_type_bits: u32::MAX,
685 allocate_preference: MemoryAllocatePreference::Unknown,
686 _ne: crate::NonExhaustive(()),
687 }
688 }
689}
690
691/// Describes whether allocating [`DeviceMemory`] is desired.
692#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
693pub enum MemoryAllocatePreference {
694 /// There is no known preference, let the allocator decide.
695 Unknown,
696
697 /// The allocator should never allocate `DeviceMemory` and should instead only suballocate from
698 /// existing blocks.
699 ///
700 /// This option is best suited if you can not afford the overhead of allocating `DeviceMemory`.
701 NeverAllocate,
702
703 /// The allocator should always allocate `DeviceMemory`.
704 ///
705 /// This option is best suited if you are allocating a long-lived resource that you know could
706 /// benefit from having a dedicated allocation.
707 AlwaysAllocate,
708}
709
710/// An allocation made using a [memory allocator].
711///
712/// [memory allocator]: MemoryAllocator
713#[derive(Clone, Debug)]
714pub struct MemoryAlloc {
715 /// The underlying block of device memory.
716 pub device_memory: Arc<DeviceMemory>,
717
718 /// The suballocation within the device memory block, or [`None`] if this is a dedicated
719 /// allocation.
720 pub suballocation: Option<Suballocation>,
721
722 /// An opaque handle identifying the allocation inside the allocator.
723 pub allocation_handle: AllocationHandle,
724}
725
726/// An opaque handle identifying an allocation inside an allocator.
727#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
728#[cfg_attr(not(doc), repr(transparent))]
729pub struct AllocationHandle(*mut ());
730
731unsafe impl Send for AllocationHandle {}
732unsafe impl Sync for AllocationHandle {}
733
734impl AllocationHandle {
735 /// Creates a null `AllocationHandle`.
736 ///
737 /// Use this if you don't have anything that you need to associate with the allocation.
738 #[inline]
739 pub const fn null() -> Self {
740 AllocationHandle(ptr::null_mut())
741 }
742
743 /// Stores a pointer in an `AllocationHandle`.
744 ///
745 /// Use this if you want to associate an allocation with some (host) heap allocation.
746 #[inline]
747 pub const fn from_ptr(ptr: *mut ()) -> Self {
748 AllocationHandle(ptr)
749 }
750
751 /// Stores an index inside an `AllocationHandle`.
752 ///
753 /// Use this if you want to associate an allocation with some index.
754 #[allow(clippy::useless_transmute)]
755 #[inline]
756 pub const fn from_index(index: usize) -> Self {
757 // SAFETY: `usize` and `*mut ()` have the same layout.
758 AllocationHandle(unsafe { mem::transmute::<usize, *mut ()>(index) })
759 }
760
761 /// Retrieves a previously-stored pointer from the `AllocationHandle`.
762 ///
763 /// If this handle hasn't been created using [`from_ptr`] then this will return an invalid
764 /// pointer, dereferencing which is undefined behavior.
765 ///
766 /// [`from_ptr`]: Self::from_ptr
767 #[inline]
768 pub const fn as_ptr(self) -> *mut () {
769 self.0
770 }
771
772 /// Retrieves a previously-stored index from the `AllocationHandle`.
773 ///
774 /// If this handle hasn't been created using [`from_index`] then this will return a bogus
775 /// result.
776 ///
777 /// [`from_index`]: Self::from_index
778 #[allow(clippy::transmutes_expressible_as_ptr_casts)]
779 #[inline]
780 pub fn as_index(self) -> usize {
781 // SAFETY: `usize` and `*mut ()` have the same layout.
782 unsafe { mem::transmute::<*mut (), usize>(self.0) }
783 }
784}
785
786/// Error that can be returned when creating an [allocation] using a [memory allocator].
787///
788/// [allocation]: MemoryAlloc
789/// [memory allocator]: MemoryAllocator
790#[derive(Clone, Debug)]
791pub enum MemoryAllocatorError {
792 /// Allocating [`DeviceMemory`] failed.
793 AllocateDeviceMemory(Validated<VulkanError>),
794
795 /// Finding a suitable memory type failed.
796 ///
797 /// This is returned from [`MemoryAllocator::allocate`] when
798 /// [`MemoryAllocator::find_memory_type_index`] returns [`None`].
799 FindMemoryType,
800
801 /// There is not enough memory in the pool.
802 ///
803 /// This is returned when using [`MemoryAllocatePreference::NeverAllocate`] and there is not
804 /// enough memory in the pool.
805 OutOfPoolMemory,
806
807 /// A dedicated allocation is required but was explicitly forbidden.
808 ///
809 /// This is returned when using [`MemoryAllocatePreference::NeverAllocate`] and the
810 /// implementation requires a dedicated allocation.
811 DedicatedAllocationRequired,
812
813 /// The block size for the allocator was exceeded.
814 ///
815 /// This is returned when using [`MemoryAllocatePreference::NeverAllocate`] and the allocation
816 /// size exceeded the block size for all heaps of suitable memory types.
817 BlockSizeExceeded,
818}
819
820impl Error for MemoryAllocatorError {
821 fn source(&self) -> Option<&(dyn Error + 'static)> {
822 match self {
823 Self::AllocateDeviceMemory(err) => Some(err),
824 _ => None,
825 }
826 }
827}
828
829impl Display for MemoryAllocatorError {
830 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
831 let msg = match self {
832 Self::AllocateDeviceMemory(_) => "allocating device memory failed",
833 Self::FindMemoryType => "finding a suitable memory type failed",
834 Self::OutOfPoolMemory => "the pool doesn't have enough free space",
835 Self::DedicatedAllocationRequired => {
836 "a dedicated allocation is required but was explicitly forbidden"
837 }
838 Self::BlockSizeExceeded => {
839 "the allocation size was greater than the block size for all heaps of suitable \
840 memory types and dedicated allocations were explicitly forbidden"
841 }
842 };
843
844 f.write_str(msg)
845 }
846}
847
848/// Standard memory allocator intended as a global and general-purpose allocator.
849///
850/// This type of allocator is what you should always use, unless you know, for a fact, that it is
851/// not suited to the task.
852///
853/// See also [`GenericMemoryAllocator`] for details about the allocation algorithm, and
854/// [`FreeListAllocator`] for details about the suballocation algorithm.
855pub type StandardMemoryAllocator = GenericMemoryAllocator<FreeListAllocator>;
856
857impl StandardMemoryAllocator {
858 /// Creates a new `StandardMemoryAllocator` with default configuration.
859 pub fn new_default(device: Arc<Device>) -> Self {
860 let MemoryProperties {
861 memory_types,
862 memory_heaps,
863 } = device.physical_device().memory_properties();
864
865 let mut block_sizes = vec![0; memory_types.len()];
866 let mut memory_type_bits = u32::MAX;
867
868 for (index, memory_type) in memory_types.iter().enumerate() {
869 const LARGE_HEAP_THRESHOLD: DeviceSize = 1024 * 1024 * 1024;
870
871 let heap_size = memory_heaps[memory_type.heap_index as usize].size;
872
873 block_sizes[index] = if heap_size >= LARGE_HEAP_THRESHOLD {
874 256 * 1024 * 1024
875 } else {
876 64 * 1024 * 1024
877 };
878
879 if memory_type.property_flags.intersects(
880 MemoryPropertyFlags::LAZILY_ALLOCATED
881 | MemoryPropertyFlags::PROTECTED
882 | MemoryPropertyFlags::DEVICE_COHERENT
883 | MemoryPropertyFlags::RDMA_CAPABLE,
884 ) {
885 // VUID-VkMemoryAllocateInfo-memoryTypeIndex-01872
886 // VUID-vkAllocateMemory-deviceCoherentMemory-02790
887 // Lazily allocated memory would just cause problems for suballocation in general.
888 memory_type_bits &= !(1 << index);
889 }
890 }
891
892 let create_info = GenericMemoryAllocatorCreateInfo {
893 block_sizes: &block_sizes,
894 memory_type_bits,
895 ..Default::default()
896 };
897
898 Self::new(device, create_info)
899 }
900}
901
902/// A generic implementation of a [memory allocator].
903///
904/// The allocator keeps [a pool of `DeviceMemory` blocks] for each memory type and uses the type
905/// parameter `S` to [suballocate] these blocks. You can also configure the sizes of these blocks.
906/// This means that you can have as many `GenericMemoryAllocator`s as you you want for different
907/// needs, or for performance reasons, as long as the block sizes are configured properly so that
908/// too much memory isn't wasted.
909///
910/// See also [the `MemoryAllocator` implementation].
911///
912/// # Mapping behavior
913///
914/// Every time a new `DeviceMemory` block is allocated, it is mapped in full automatically as long
915/// as it resides in host-visible memory. It remains mapped until it is dropped, which only happens
916/// if the allocator is dropped. In other words, all eligible blocks are persistently mapped, so
917/// you don't need to worry about whether or not your host-visible allocations are host-accessible.
918///
919/// # `DeviceMemory` allocation
920///
921/// If an allocation is created with the [`MemoryAllocatePreference::Unknown`] option, and the
922/// allocator deems the allocation too big for suballocation (larger than half the block size), or
923/// the implementation prefers or requires a dedicated allocation, then that allocation is made a
924/// dedicated allocation. Using [`MemoryAllocatePreference::NeverAllocate`], a dedicated allocation
925/// is never created, even if the allocation is larger than the block size or a dedicated
926/// allocation is required. In such a case an error is returned instead. Using
927/// [`MemoryAllocatePreference::AlwaysAllocate`], a dedicated allocation is always created.
928///
929/// In all other cases, `DeviceMemory` is only allocated if a pool runs out of memory and needs
930/// another block. No `DeviceMemory` is allocated when the allocator is created, the blocks are
931/// only allocated once they are needed.
932///
933/// [memory allocator]: MemoryAllocator
934/// [a pool of `DeviceMemory` blocks]: DeviceMemoryPool
935/// [suballocate]: Suballocator
936/// [the `MemoryAllocator` implementation]: Self#impl-MemoryAllocator-for-GenericMemoryAllocator<S>
937#[derive(Debug)]
938pub struct GenericMemoryAllocator<S> {
939 device: InstanceOwnedDebugWrapper<Arc<Device>>,
940 buffer_image_granularity: DeviceAlignment,
941 // Each memory type has a pool of `DeviceMemory` blocks.
942 pools: ArrayVec<DeviceMemoryPool<S>, MAX_MEMORY_TYPES>,
943 // Global mask of memory types.
944 memory_type_bits: u32,
945 dedicated_allocation: bool,
946 export_handle_types: ArrayVec<ExternalMemoryHandleTypes, MAX_MEMORY_TYPES>,
947 flags: MemoryAllocateFlags,
948 // How many `DeviceMemory` allocations should be allowed before restricting them.
949 max_allocations: u32,
950}
951
952impl<S> GenericMemoryAllocator<S> {
953 // This is a false-positive, we only use this const for static initialization.
954 #[allow(clippy::declare_interior_mutable_const)]
955 const EMPTY_POOL: DeviceMemoryPool<S> = DeviceMemoryPool {
956 blocks: Mutex::new(DeviceMemoryBlockVec::new()),
957 property_flags: MemoryPropertyFlags::empty(),
958 atom_size: DeviceAlignment::MIN,
959 block_size: 0,
960 };
961
962 /// Creates a new `GenericMemoryAllocator<S>` using the provided suballocator `S` for
963 /// suballocation of [`DeviceMemory`] blocks.
964 ///
965 /// # Panics
966 ///
967 /// - Panics if `create_info.block_sizes` doesn't contain as many elements as the number of
968 /// memory types.
969 /// - Panics if `create_info.export_handle_types` is non-empty and doesn't contain as many
970 /// elements as the number of memory types.
971 pub fn new(device: Arc<Device>, create_info: GenericMemoryAllocatorCreateInfo<'_>) -> Self {
972 let GenericMemoryAllocatorCreateInfo {
973 block_sizes,
974 memory_type_bits,
975 dedicated_allocation,
976 export_handle_types,
977 mut device_address,
978 _ne: _,
979 } = create_info;
980
981 let memory_types = &device.physical_device().memory_properties().memory_types;
982
983 assert_eq!(
984 block_sizes.len(),
985 memory_types.len(),
986 "`create_info.block_sizes` must contain as many elements as the number of memory types",
987 );
988
989 if !export_handle_types.is_empty() {
990 assert_eq!(
991 export_handle_types.len(),
992 memory_types.len(),
993 "`create_info.export_handle_types` must contain as many elements as the number of \
994 memory types if not empty",
995 );
996 }
997
998 let buffer_image_granularity = device
999 .physical_device()
1000 .properties()
1001 .buffer_image_granularity;
1002
1003 let memory_types = &device.physical_device().memory_properties().memory_types;
1004
1005 let mut pools = ArrayVec::new(memory_types.len(), [Self::EMPTY_POOL; MAX_MEMORY_TYPES]);
1006
1007 for (index, &MemoryType { property_flags, .. }) in memory_types.iter().enumerate() {
1008 pools[index].property_flags = property_flags;
1009
1010 if property_flags.intersects(MemoryPropertyFlags::HOST_VISIBLE)
1011 && !property_flags.intersects(MemoryPropertyFlags::HOST_COHERENT)
1012 {
1013 pools[index].atom_size =
1014 device.physical_device().properties().non_coherent_atom_size;
1015 }
1016
1017 pools[index].block_size = block_sizes[index];
1018 }
1019
1020 let export_handle_types = {
1021 let mut types = ArrayVec::new(
1022 export_handle_types.len(),
1023 [ExternalMemoryHandleTypes::empty(); MAX_MEMORY_TYPES],
1024 );
1025 types.copy_from_slice(export_handle_types);
1026
1027 types
1028 };
1029
1030 // VUID-VkMemoryAllocateInfo-flags-03331
1031 device_address &= device.enabled_features().buffer_device_address
1032 && !device.enabled_extensions().ext_buffer_device_address;
1033 // Providers of `VkMemoryAllocateFlags`
1034 device_address &=
1035 device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_device_group;
1036
1037 let flags = if device_address {
1038 MemoryAllocateFlags::DEVICE_ADDRESS
1039 } else {
1040 MemoryAllocateFlags::empty()
1041 };
1042
1043 let max_memory_allocation_count = device
1044 .physical_device()
1045 .properties()
1046 .max_memory_allocation_count;
1047 let max_allocations = max_memory_allocation_count / 4 * 3;
1048
1049 GenericMemoryAllocator {
1050 device: InstanceOwnedDebugWrapper(device),
1051 buffer_image_granularity,
1052 pools,
1053 dedicated_allocation,
1054 export_handle_types,
1055 flags,
1056 memory_type_bits,
1057 max_allocations,
1058 }
1059 }
1060
1061 /// Returns the pools of [`DeviceMemory`] blocks that are currently allocated. Each memory type
1062 /// index has a corresponding element in the slice.
1063 #[inline]
1064 pub fn pools(&self) -> &[DeviceMemoryPool<S>] {
1065 &self.pools
1066 }
1067
1068 #[cold]
1069 fn allocate_device_memory(
1070 &self,
1071 memory_type_index: u32,
1072 allocation_size: DeviceSize,
1073 dedicated_allocation: Option<DedicatedAllocation<'_>>,
1074 export_handle_types: ExternalMemoryHandleTypes,
1075 ) -> Result<Arc<DeviceMemory>, Validated<VulkanError>> {
1076 let mut memory = DeviceMemory::allocate(
1077 self.device.clone(),
1078 MemoryAllocateInfo {
1079 allocation_size,
1080 memory_type_index,
1081 dedicated_allocation,
1082 export_handle_types,
1083 flags: self.flags,
1084 ..Default::default()
1085 },
1086 )?;
1087
1088 if self.pools[memory_type_index as usize]
1089 .property_flags
1090 .intersects(MemoryPropertyFlags::HOST_VISIBLE)
1091 {
1092 // SAFETY:
1093 // - We checked that the memory is host-visible.
1094 // - The memory can't be mapped already, because we just allocated it.
1095 // - Mapping the whole range is always valid.
1096 unsafe {
1097 memory.map_unchecked(MemoryMapInfo {
1098 flags: MemoryMapFlags::empty(),
1099 offset: 0,
1100 size: memory.allocation_size(),
1101 _ne: crate::NonExhaustive(()),
1102 })
1103 }?;
1104 }
1105
1106 Ok(Arc::new(memory))
1107 }
1108}
1109
1110unsafe impl<S: Suballocator + Send + 'static> MemoryAllocator for GenericMemoryAllocator<S> {
1111 fn find_memory_type_index(
1112 &self,
1113 memory_type_bits: u32,
1114 filter: MemoryTypeFilter,
1115 ) -> Option<u32> {
1116 let required_flags = filter.required_flags.into();
1117 let preferred_flags = filter.preferred_flags.into();
1118 let not_preferred_flags = filter.not_preferred_flags.into();
1119
1120 self.pools
1121 .iter()
1122 .map(|pool| ash::vk::MemoryPropertyFlags::from(pool.property_flags))
1123 .enumerate()
1124 // Filter out memory types which are supported by the memory type bits and have the
1125 // required flags set.
1126 .filter(|&(index, flags)| {
1127 memory_type_bits & (1 << index) != 0 && flags & required_flags == required_flags
1128 })
1129 // Rank memory types with more of the preferred flags higher, and ones with more of the
1130 // not preferred flags lower.
1131 .min_by_key(|&(_, flags)| {
1132 (!flags & preferred_flags).as_raw().count_ones()
1133 + (flags & not_preferred_flags).as_raw().count_ones()
1134 })
1135 .map(|(index, _)| index as u32)
1136 }
1137
1138 /// Allocates memory from a specific memory type.
1139 ///
1140 /// # Arguments
1141 ///
1142 /// - `memory_type_index` - The index of the memory type to allocate from.
1143 ///
1144 /// - `layout` - The layout of the allocation.
1145 ///
1146 /// - `allocation_type` - The type of resources that can be bound to the allocation.
1147 ///
1148 /// - `never_allocate` - If `true` then the allocator should never allocate `DeviceMemory`,
1149 /// instead only suballocate from existing blocks.
1150 ///
1151 /// # Panics
1152 ///
1153 /// - Panics if `memory_type_index` is not less than the number of available memory types.
1154 ///
1155 /// # Errors
1156 ///
1157 /// - Returns [`AllocateDeviceMemory`] if allocating a new block failed.
1158 /// - Returns [`OutOfPoolMemory`] if `never_allocate` is `true` and the pool doesn't have
1159 /// enough free space.
1160 /// - Returns [`BlockSizeExceeded`] if `create_info.layout.size()` is greater than the block
1161 /// size corresponding to the heap that the memory type corresponding to `memory_type_index`
1162 /// resides in.
1163 ///
1164 /// [`AllocateDeviceMemory`]: MemoryAllocatorError::AllocateDeviceMemory
1165 /// [`OutOfPoolMemory`]: MemoryAllocatorError::OutOfPoolMemory
1166 /// [`BlockSizeExceeded`]: MemoryAllocatorError::BlockSizeExceeded
1167 fn allocate_from_type(
1168 &self,
1169 memory_type_index: u32,
1170 mut layout: DeviceLayout,
1171 allocation_type: AllocationType,
1172 never_allocate: bool,
1173 ) -> Result<MemoryAlloc, MemoryAllocatorError> {
1174 let size = layout.size();
1175 let pool = &self.pools[memory_type_index as usize];
1176
1177 if size > pool.block_size {
1178 return Err(MemoryAllocatorError::BlockSizeExceeded);
1179 }
1180
1181 layout = layout.align_to(pool.atom_size).unwrap();
1182
1183 let blocks = &mut *pool.blocks.lock();
1184 let vec = &mut blocks.vec;
1185
1186 // TODO: Incremental sorting
1187 vec.sort_by_key(|block| block.free_size());
1188 let (Ok(idx) | Err(idx)) = vec.binary_search_by_key(&size, |block| block.free_size());
1189
1190 for block in &mut vec[idx..] {
1191 if let Ok(allocation) =
1192 block.allocate(layout, allocation_type, self.buffer_image_granularity)
1193 {
1194 return Ok(allocation);
1195 }
1196 }
1197
1198 if never_allocate {
1199 return Err(MemoryAllocatorError::OutOfPoolMemory);
1200 }
1201
1202 // The pool doesn't have enough real estate, so we need a new block.
1203 let block = {
1204 let export_handle_types = if !self.export_handle_types.is_empty() {
1205 self.export_handle_types[memory_type_index as usize]
1206 } else {
1207 ExternalMemoryHandleTypes::empty()
1208 };
1209 let mut i = 0;
1210
1211 loop {
1212 let allocation_size = pool.block_size >> i;
1213
1214 match self.allocate_device_memory(
1215 memory_type_index,
1216 allocation_size,
1217 None,
1218 export_handle_types,
1219 ) {
1220 Ok(device_memory) => {
1221 break DeviceMemoryBlock::new(device_memory, &blocks.block_allocator);
1222 }
1223 // Retry up to 3 times, halving the allocation size each time so long as the
1224 // resulting size is still large enough.
1225 Err(Validated::Error(
1226 VulkanError::OutOfHostMemory | VulkanError::OutOfDeviceMemory,
1227 )) if i < 3 && pool.block_size >> (i + 1) >= size => {
1228 i += 1;
1229 }
1230 Err(err) => return Err(MemoryAllocatorError::AllocateDeviceMemory(err)),
1231 }
1232 }
1233 };
1234
1235 vec.push(block);
1236 let block = vec.last_mut().unwrap();
1237
1238 match block.allocate(layout, allocation_type, self.buffer_image_granularity) {
1239 Ok(allocation) => Ok(allocation),
1240 // This can't happen as we always allocate a block of sufficient size.
1241 Err(SuballocatorError::OutOfRegionMemory) => unreachable!(),
1242 // This can't happen as the block is fresher than Febreze and we're still holding an
1243 // exclusive lock.
1244 Err(SuballocatorError::FragmentedRegion) => unreachable!(),
1245 }
1246 }
1247
1248 /// Allocates memory according to requirements.
1249 ///
1250 /// # Arguments
1251 ///
1252 /// - `requirements` - Requirements of the resource you want to allocate memory for.
1253 ///
1254 /// If you plan to bind this memory directly to a non-sparse resource, then this must
1255 /// correspond to the value returned by either [`RawBuffer::memory_requirements`] or
1256 /// [`RawImage::memory_requirements`] for the respective buffer or image.
1257 ///
1258 /// - `allocation_type` - What type of resource this allocation will be used for.
1259 ///
1260 /// This should be [`Linear`] for buffers and linear images, and [`NonLinear`] for optimal
1261 /// images. You can not bind memory allocated with the [`Linear`] type to optimal images or
1262 /// bind memory allocated with the [`NonLinear`] type to buffers and linear images. You
1263 /// should never use the [`Unknown`] type unless you have to, as that can be less memory
1264 /// efficient.
1265 ///
1266 /// - `dedicated_allocation` - Allows a dedicated allocation to be created.
1267 ///
1268 /// You should always fill this field in if you are allocating memory for a non-sparse
1269 /// resource, otherwise the allocator won't be able to create a dedicated allocation if one
1270 /// is required or recommended.
1271 ///
1272 /// This argument is silently ignored (treated as `None`) if the device API version is below
1273 /// 1.1 and the [`khr_dedicated_allocation`] extension is not enabled on the device.
1274 ///
1275 /// # Errors
1276 ///
1277 /// - Returns [`AllocateDeviceMemory`] if allocating a new block failed.
1278 /// - Returns [`FindMemoryType`] if finding a suitable memory type failed. This can happen if
1279 /// the `create_info.requirements` correspond to those of an optimal image but
1280 /// `create_info.memory_type_filter` requires host access.
1281 /// - Returns [`OutOfPoolMemory`] if `create_info.allocate_preference` is
1282 /// [`MemoryAllocatePreference::NeverAllocate`] and none of the pools of suitable memory
1283 /// types have enough free space.
1284 /// - Returns [`DedicatedAllocationRequired`] if `create_info.allocate_preference` is
1285 /// [`MemoryAllocatePreference::NeverAllocate`] and
1286 /// `create_info.requirements.requires_dedicated_allocation` is `true`.
1287 /// - Returns [`BlockSizeExceeded`] if `create_info.allocate_preference` is
1288 /// [`MemoryAllocatePreference::NeverAllocate`] and `create_info.requirements.size` is
1289 /// greater than the block size for all heaps of suitable memory types.
1290 ///
1291 /// [`RawBuffer::memory_requirements`]: crate::buffer::sys::RawBuffer::memory_requirements
1292 /// [`RawImage::memory_requirements`]: crate::image::sys::RawImage::memory_requirements
1293 /// [`Linear`]: AllocationType::Linear
1294 /// [`NonLinear`]: AllocationType::NonLinear
1295 /// [`Unknown`]: AllocationType::Unknown
1296 /// [`khr_dedicated_allocation`]: crate::device::DeviceExtensions::khr_dedicated_allocation
1297 /// [`AllocateDeviceMemory`]: MemoryAllocatorError::AllocateDeviceMemory
1298 /// [`FindMemoryType`]: MemoryAllocatorError::FindMemoryType
1299 /// [`OutOfPoolMemory`]: MemoryAllocatorError::OutOfPoolMemory
1300 /// [`DedicatedAllocationRequired`]: MemoryAllocatorError::DedicatedAllocationRequired
1301 /// [`BlockSizeExceeded`]: MemoryAllocatorError::BlockSizeExceeded
1302 fn allocate(
1303 &self,
1304 requirements: MemoryRequirements,
1305 allocation_type: AllocationType,
1306 create_info: AllocationCreateInfo,
1307 mut dedicated_allocation: Option<DedicatedAllocation<'_>>,
1308 ) -> Result<MemoryAlloc, MemoryAllocatorError> {
1309 let MemoryRequirements {
1310 layout,
1311 mut memory_type_bits,
1312 mut prefers_dedicated_allocation,
1313 requires_dedicated_allocation,
1314 } = requirements;
1315
1316 memory_type_bits &= self.memory_type_bits;
1317 memory_type_bits &= create_info.memory_type_bits;
1318
1319 let AllocationCreateInfo {
1320 memory_type_filter,
1321 memory_type_bits: _,
1322 allocate_preference,
1323 _ne: _,
1324 } = create_info;
1325
1326 let size = layout.size();
1327
1328 let mut memory_type_index = self
1329 .find_memory_type_index(memory_type_bits, memory_type_filter)
1330 .ok_or(MemoryAllocatorError::FindMemoryType)?;
1331
1332 if !self.dedicated_allocation && !requires_dedicated_allocation {
1333 dedicated_allocation = None;
1334 }
1335
1336 let export_handle_types = if self.export_handle_types.is_empty() {
1337 ExternalMemoryHandleTypes::empty()
1338 } else {
1339 self.export_handle_types[memory_type_index as usize]
1340 };
1341
1342 loop {
1343 let pool = &self.pools[memory_type_index as usize];
1344
1345 let res = match allocate_preference {
1346 MemoryAllocatePreference::Unknown => {
1347 // VUID-vkBindBufferMemory-buffer-01444
1348 // VUID-vkBindImageMemory-image-01445
1349 if requires_dedicated_allocation {
1350 self.allocate_dedicated(
1351 memory_type_index,
1352 size,
1353 dedicated_allocation,
1354 export_handle_types,
1355 )
1356 } else {
1357 if size > pool.block_size / 2 {
1358 prefers_dedicated_allocation = true;
1359 }
1360 if self.device.allocation_count() > self.max_allocations
1361 && size <= pool.block_size
1362 {
1363 prefers_dedicated_allocation = false;
1364 }
1365
1366 if prefers_dedicated_allocation {
1367 self.allocate_dedicated(
1368 memory_type_index,
1369 size,
1370 dedicated_allocation,
1371 export_handle_types,
1372 )
1373 // Fall back to suballocation.
1374 .or_else(|err| {
1375 self.allocate_from_type(
1376 memory_type_index,
1377 layout,
1378 allocation_type,
1379 true, // A dedicated allocation already failed.
1380 )
1381 .map_err(|_| err)
1382 })
1383 } else {
1384 self.allocate_from_type(
1385 memory_type_index,
1386 layout,
1387 allocation_type,
1388 false,
1389 )
1390 // Fall back to dedicated allocation. It is possible that the 1/8
1391 // block size tried was greater than the allocation size, so
1392 // there's hope.
1393 .or_else(|_| {
1394 self.allocate_dedicated(
1395 memory_type_index,
1396 size,
1397 dedicated_allocation,
1398 export_handle_types,
1399 )
1400 })
1401 }
1402 }
1403 }
1404 MemoryAllocatePreference::NeverAllocate => {
1405 if requires_dedicated_allocation {
1406 return Err(MemoryAllocatorError::DedicatedAllocationRequired);
1407 }
1408
1409 self.allocate_from_type(memory_type_index, layout, allocation_type, true)
1410 }
1411 MemoryAllocatePreference::AlwaysAllocate => self.allocate_dedicated(
1412 memory_type_index,
1413 size,
1414 dedicated_allocation,
1415 export_handle_types,
1416 ),
1417 };
1418
1419 match res {
1420 Ok(allocation) => return Ok(allocation),
1421 // Try a different memory type.
1422 Err(err) => {
1423 memory_type_bits &= !(1 << memory_type_index);
1424 memory_type_index = self
1425 .find_memory_type_index(memory_type_bits, memory_type_filter)
1426 .ok_or(err)?;
1427 }
1428 }
1429 }
1430 }
1431
1432 #[cold]
1433 fn allocate_dedicated(
1434 &self,
1435 memory_type_index: u32,
1436 allocation_size: DeviceSize,
1437 dedicated_allocation: Option<DedicatedAllocation<'_>>,
1438 export_handle_types: ExternalMemoryHandleTypes,
1439 ) -> Result<MemoryAlloc, MemoryAllocatorError> {
1440 let device_memory = self
1441 .allocate_device_memory(
1442 memory_type_index,
1443 allocation_size,
1444 dedicated_allocation,
1445 export_handle_types,
1446 )
1447 .map_err(MemoryAllocatorError::AllocateDeviceMemory)?;
1448
1449 Ok(MemoryAlloc {
1450 device_memory,
1451 suballocation: None,
1452 allocation_handle: AllocationHandle::null(),
1453 })
1454 }
1455
1456 unsafe fn deallocate(&self, allocation: MemoryAlloc) {
1457 if let Some(suballocation) = allocation.suballocation {
1458 let memory_type_index = allocation.device_memory.memory_type_index();
1459 let blocks = self.pools[memory_type_index as usize].blocks.lock();
1460 let vec = &blocks.vec;
1461 let block_ptr = allocation
1462 .allocation_handle
1463 .as_ptr()
1464 .cast::<DeviceMemoryBlock<S>>();
1465
1466 // TODO: Maybe do a similar check for dedicated blocks.
1467 debug_assert!(
1468 vec.iter().any(|block| ptr::addr_of!(**block) == block_ptr),
1469 "attempted to deallocate a memory block that does not belong to this allocator",
1470 );
1471
1472 // SAFETY: The caller must guarantee that `allocation` refers to one allocated by
1473 // `self`, therefore `block_ptr` must be the same one we gave out on allocation. We
1474 // know that this pointer must be valid, because all blocks are boxed and pinned in
1475 // memory and because a block isn't dropped until the allocator itself is dropped, at
1476 // which point it would be impossible to call this method. We also know that it must be
1477 // valid to create a reference to the block, because we locked the pool it belongs to.
1478 let block = unsafe { &mut *block_ptr };
1479
1480 // SAFETY: The caller must guarantee that `allocation` refers to a currently allocated
1481 // allocation of `self`.
1482 unsafe { block.deallocate(suballocation) };
1483 }
1484 }
1485}
1486
1487unsafe impl<T: MemoryAllocator> MemoryAllocator for Arc<T> {
1488 fn find_memory_type_index(
1489 &self,
1490 memory_type_bits: u32,
1491 filter: MemoryTypeFilter,
1492 ) -> Option<u32> {
1493 (**self).find_memory_type_index(memory_type_bits, filter)
1494 }
1495
1496 fn allocate_from_type(
1497 &self,
1498 memory_type_index: u32,
1499 layout: DeviceLayout,
1500 allocation_type: AllocationType,
1501 never_allocate: bool,
1502 ) -> Result<MemoryAlloc, MemoryAllocatorError> {
1503 (**self).allocate_from_type(memory_type_index, layout, allocation_type, never_allocate)
1504 }
1505
1506 fn allocate(
1507 &self,
1508 requirements: MemoryRequirements,
1509 allocation_type: AllocationType,
1510 create_info: AllocationCreateInfo,
1511 dedicated_allocation: Option<DedicatedAllocation<'_>>,
1512 ) -> Result<MemoryAlloc, MemoryAllocatorError> {
1513 (**self).allocate(
1514 requirements,
1515 allocation_type,
1516 create_info,
1517 dedicated_allocation,
1518 )
1519 }
1520
1521 fn allocate_dedicated(
1522 &self,
1523 memory_type_index: u32,
1524 allocation_size: DeviceSize,
1525 dedicated_allocation: Option<DedicatedAllocation<'_>>,
1526 export_handle_types: ExternalMemoryHandleTypes,
1527 ) -> Result<MemoryAlloc, MemoryAllocatorError> {
1528 (**self).allocate_dedicated(
1529 memory_type_index,
1530 allocation_size,
1531 dedicated_allocation,
1532 export_handle_types,
1533 )
1534 }
1535
1536 unsafe fn deallocate(&self, allocation: MemoryAlloc) {
1537 unsafe { (**self).deallocate(allocation) }
1538 }
1539}
1540
1541unsafe impl<S> DeviceOwned for GenericMemoryAllocator<S> {
1542 fn device(&self) -> &Arc<Device> {
1543 &self.device
1544 }
1545}
1546
1547/// A pool of [`DeviceMemory`] blocks within [`GenericMemoryAllocator`], specific to a memory type.
1548#[derive(Debug)]
1549pub struct DeviceMemoryPool<S> {
1550 blocks: Mutex<DeviceMemoryBlockVec<S>>,
1551 // This is cached here for faster access, so we don't need to hop through 3 pointers.
1552 property_flags: MemoryPropertyFlags,
1553 atom_size: DeviceAlignment,
1554 block_size: DeviceSize,
1555}
1556
1557impl<S> DeviceMemoryPool<S> {
1558 /// Returns an iterator over the [`DeviceMemory`] blocks in the pool.
1559 ///
1560 /// # Locking behavior
1561 ///
1562 /// This locks the pool for the lifetime of the returned iterator. Creating other iterators, or
1563 /// allocating/deallocating in the meantime, can therefore lead to a deadlock as long as this
1564 /// iterator isn't dropped.
1565 #[inline]
1566 pub fn blocks(&self) -> DeviceMemoryBlocks<'_, S> {
1567 DeviceMemoryBlocks {
1568 inner: MutexGuard::leak(self.blocks.lock()).vec.iter(),
1569 // SAFETY: We have just locked the pool above.
1570 _guard: unsafe { DeviceMemoryPoolGuard::new(self) },
1571 }
1572 }
1573}
1574
1575impl<S> Drop for DeviceMemoryPool<S> {
1576 fn drop(&mut self) {
1577 let blocks = self.blocks.get_mut();
1578
1579 for block in &mut blocks.vec {
1580 unsafe { AliasableBox::drop(block, &blocks.block_allocator) };
1581 }
1582 }
1583}
1584
1585#[derive(Debug)]
1586struct DeviceMemoryBlockVec<S> {
1587 vec: Vec<AliasableBox<DeviceMemoryBlock<S>>>,
1588 block_allocator: SlabAllocator<DeviceMemoryBlock<S>>,
1589}
1590
1591impl<S> DeviceMemoryBlockVec<S> {
1592 const fn new() -> Self {
1593 DeviceMemoryBlockVec {
1594 vec: Vec::new(),
1595 block_allocator: SlabAllocator::new(32),
1596 }
1597 }
1598}
1599
1600/// A [`DeviceMemory`] block within a [`DeviceMemoryPool`].
1601#[derive(Debug)]
1602pub struct DeviceMemoryBlock<S> {
1603 device_memory: Arc<DeviceMemory>,
1604 suballocator: S,
1605 allocation_count: usize,
1606}
1607
1608impl<S: Suballocator> DeviceMemoryBlock<S> {
1609 fn new(
1610 device_memory: Arc<DeviceMemory>,
1611 block_allocator: &SlabAllocator<Self>,
1612 ) -> AliasableBox<Self> {
1613 let suballocator = S::new(
1614 Region::new(0, device_memory.allocation_size())
1615 .expect("we somehow managed to allocate more than `DeviceLayout::MAX_SIZE` bytes"),
1616 );
1617
1618 AliasableBox::new(
1619 DeviceMemoryBlock {
1620 device_memory,
1621 suballocator,
1622 allocation_count: 0,
1623 },
1624 block_allocator,
1625 )
1626 }
1627
1628 unsafe fn deallocate(&mut self, suballocation: Suballocation) {
1629 unsafe { self.suballocator.deallocate(suballocation) };
1630
1631 self.allocation_count -= 1;
1632
1633 // For bump allocators, reset the free-start once there are no remaining allocations.
1634 if self.allocation_count == 0 {
1635 self.suballocator.reset();
1636 }
1637 }
1638
1639 /// Returns the [`DeviceMemory`] backing this block.
1640 #[inline]
1641 pub fn device_memory(&self) -> &Arc<DeviceMemory> {
1642 &self.device_memory
1643 }
1644
1645 /// Returns the suballocator used to suballocate this block.
1646 #[inline]
1647 pub fn suballocator(&self) -> &S {
1648 &self.suballocator
1649 }
1650
1651 /// Returns the number of suballocations currently allocated from the block.
1652 #[inline]
1653 pub fn allocation_count(&self) -> usize {
1654 self.allocation_count
1655 }
1656
1657 fn free_size(&self) -> DeviceSize {
1658 self.suballocator.free_size()
1659 }
1660}
1661
1662impl<S: Suballocator> AliasableBox<DeviceMemoryBlock<S>> {
1663 fn allocate(
1664 &mut self,
1665 layout: DeviceLayout,
1666 allocation_type: AllocationType,
1667 buffer_image_granularity: DeviceAlignment,
1668 ) -> Result<MemoryAlloc, SuballocatorError> {
1669 let suballocation =
1670 self.suballocator
1671 .allocate(layout, allocation_type, buffer_image_granularity)?;
1672
1673 self.allocation_count += 1;
1674
1675 // It is paramount to soundness that the pointer we give out doesn't go through `DerefMut`,
1676 // as such a pointer would become invalidated when another allocation is made.
1677 let ptr = AliasableBox::as_mut_ptr(self);
1678
1679 Ok(MemoryAlloc {
1680 device_memory: self.device_memory.clone(),
1681 suballocation: Some(suballocation),
1682 allocation_handle: AllocationHandle::from_ptr(<*mut _>::cast(ptr)),
1683 })
1684 }
1685}
1686
1687/// An iterator over the [`DeviceMemoryBlock`]s within a [`DeviceMemoryPool`].
1688pub struct DeviceMemoryBlocks<'a, S> {
1689 inner: slice::Iter<'a, AliasableBox<DeviceMemoryBlock<S>>>,
1690 _guard: DeviceMemoryPoolGuard<'a, S>,
1691}
1692
1693impl<'a, S> Iterator for DeviceMemoryBlocks<'a, S> {
1694 type Item = &'a DeviceMemoryBlock<S>;
1695
1696 #[inline]
1697 fn next(&mut self) -> Option<Self::Item> {
1698 self.inner.next().map(|block| &**block)
1699 }
1700
1701 #[inline]
1702 fn size_hint(&self) -> (usize, Option<usize>) {
1703 self.inner.size_hint()
1704 }
1705
1706 #[inline]
1707 fn count(self) -> usize
1708 where
1709 Self: Sized,
1710 {
1711 self.inner.count()
1712 }
1713
1714 #[inline]
1715 fn last(mut self) -> Option<Self::Item>
1716 where
1717 Self: Sized,
1718 {
1719 self.inner.next_back().map(|block| &**block)
1720 }
1721
1722 #[inline]
1723 fn nth(&mut self, n: usize) -> Option<Self::Item> {
1724 self.inner.nth(n).map(|block| &**block)
1725 }
1726
1727 #[inline]
1728 fn fold<B, F>(self, init: B, mut f: F) -> B
1729 where
1730 Self: Sized,
1731 F: FnMut(B, Self::Item) -> B,
1732 {
1733 self.inner.fold(init, |acc, block| f(acc, &**block))
1734 }
1735}
1736
1737impl<S> DoubleEndedIterator for DeviceMemoryBlocks<'_, S> {
1738 #[inline]
1739 fn next_back(&mut self) -> Option<Self::Item> {
1740 self.inner.next_back().map(|block| &**block)
1741 }
1742
1743 #[inline]
1744 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
1745 self.inner.nth_back(n).map(|block| &**block)
1746 }
1747}
1748
1749impl<S> ExactSizeIterator for DeviceMemoryBlocks<'_, S> {
1750 #[inline]
1751 fn len(&self) -> usize {
1752 self.inner.len()
1753 }
1754}
1755
1756impl<S> FusedIterator for DeviceMemoryBlocks<'_, S> {}
1757
1758struct DeviceMemoryPoolGuard<'a, S> {
1759 pool: &'a DeviceMemoryPool<S>,
1760}
1761
1762impl<'a, S> DeviceMemoryPoolGuard<'a, S> {
1763 /// # Safety
1764 ///
1765 /// - The `pool.blocks` mutex must be locked.
1766 unsafe fn new(pool: &'a DeviceMemoryPool<S>) -> Self {
1767 DeviceMemoryPoolGuard { pool }
1768 }
1769}
1770
1771impl<S> Drop for DeviceMemoryPoolGuard<'_, S> {
1772 fn drop(&mut self) {
1773 // SAFETY: Enforced by the caller of `DeviceMemoryPoolGuard::new`.
1774 unsafe { self.pool.blocks.force_unlock() };
1775 }
1776}
1777
1778/// Parameters to create a new [`GenericMemoryAllocator`].
1779#[derive(Clone, Debug)]
1780pub struct GenericMemoryAllocatorCreateInfo<'a> {
1781 /// Lets you configure the block sizes for each memory type.
1782 ///
1783 /// Must contain one entry for each memory type. The allocator keeps a pool of [`DeviceMemory`]
1784 /// blocks for each memory type, and every time a new block is allocated, the block size
1785 /// corresponding to the memory type index is looked up here and used for the allocation.
1786 ///
1787 /// The block size is going to be the maximum size of a `DeviceMemory` block that is tried. If
1788 /// allocating a block with the size fails, the allocator tries 1/2, 1/4 and 1/8 of the block
1789 /// size in that order until one succeeds, else a dedicated allocation is attempted for the
1790 /// allocation. If an allocation is created with a size greater than half the block size it is
1791 /// always made a dedicated allocation. All of this doesn't apply when using
1792 /// [`MemoryAllocatePreference::NeverAllocate`] however.
1793 ///
1794 /// The default value is `&[]`, which must be overridden.
1795 pub block_sizes: &'a [DeviceSize],
1796
1797 /// Lets you configure the allocator's global mask of memory type indices. Only the memory type
1798 /// indices that have a corresponding bit at the same index set will be allocated from when
1799 /// calling [`allocate`], otherwise [`MemoryAllocatorError::FindMemoryType`] is returned.
1800 ///
1801 /// You may use this to disallow problematic memory types, for instance ones with the
1802 /// [`PROTECTED`] flag, or any other flags you don't want.
1803 ///
1804 /// The default value is [`u32::MAX`].
1805 ///
1806 /// [`allocate`]: struct.GenericMemoryAllocator.html#method.allocate
1807 /// [`PROTECTED`]: MemoryPropertyFlags::DEVICE_COHERENT
1808 pub memory_type_bits: u32,
1809
1810 /// Whether the allocator should use the dedicated allocation APIs.
1811 ///
1812 /// This means that when the allocator decides that an allocation should not be suballocated,
1813 /// but rather have its own block of [`DeviceMemory`], that that allocation will be made a
1814 /// dedicated allocation. Otherwise they are still given their own block of device memory, just
1815 /// that that block won't be [dedicated] to a particular resource.
1816 ///
1817 /// Dedicated allocations are an optimization which may result in better performance, so there
1818 /// really is no reason to disable this option, unless the restrictions that they bring with
1819 /// them are a problem. Namely, a dedicated allocation must only be used for the resource it
1820 /// was created for. Meaning that reusing the memory for something else is not possible,
1821 /// suballocating it is not possible, and aliasing it is also not possible.
1822 ///
1823 /// This option is silently ignored (treated as `false`) if the device API version is below 1.1
1824 /// and the [`khr_dedicated_allocation`] extension is not enabled on the device.
1825 ///
1826 /// The default value is `true`.
1827 ///
1828 /// [dedicated]: DeviceMemory::is_dedicated
1829 /// [`khr_dedicated_allocation`]: crate::device::DeviceExtensions::khr_dedicated_allocation
1830 pub dedicated_allocation: bool,
1831
1832 /// Lets you configure the external memory handle types that the [`DeviceMemory`] blocks will
1833 /// be allocated with.
1834 ///
1835 /// Must be either empty or contain one element for each memory type. When `DeviceMemory` is
1836 /// allocated, the external handle types corresponding to the memory type index are looked up
1837 /// here and used for the allocation.
1838 ///
1839 /// The default value is `&[]`.
1840 pub export_handle_types: &'a [ExternalMemoryHandleTypes],
1841
1842 /// Whether the allocator should allocate the [`DeviceMemory`] blocks with the
1843 /// [`DEVICE_ADDRESS`] flag set.
1844 ///
1845 /// This is required if you want to allocate memory for buffers that have the
1846 /// [`SHADER_DEVICE_ADDRESS`] usage set. For this option too, there is no reason to disable it.
1847 ///
1848 /// This option is silently ignored (treated as `false`) if the [`buffer_device_address`]
1849 /// feature is not enabled on the device or if the [`ext_buffer_device_address`] extension is
1850 /// enabled on the device. It is also ignored if the device API version is below 1.1 and the
1851 /// [`khr_device_group`] extension is not enabled on the device.
1852 ///
1853 /// The default value is `true`.
1854 ///
1855 /// [`DEVICE_ADDRESS`]: MemoryAllocateFlags::DEVICE_ADDRESS
1856 /// [`SHADER_DEVICE_ADDRESS`]: crate::buffer::BufferUsage::SHADER_DEVICE_ADDRESS
1857 /// [`buffer_device_address`]: crate::device::DeviceFeatures::buffer_device_address
1858 /// [`ext_buffer_device_address`]: crate::device::DeviceExtensions::ext_buffer_device_address
1859 /// [`khr_device_group`]: crate::device::DeviceExtensions::khr_device_group
1860 pub device_address: bool,
1861
1862 pub _ne: crate::NonExhaustive,
1863}
1864
1865impl Default for GenericMemoryAllocatorCreateInfo<'_> {
1866 #[inline]
1867 fn default() -> Self {
1868 GenericMemoryAllocatorCreateInfo {
1869 block_sizes: &[],
1870 memory_type_bits: u32::MAX,
1871 dedicated_allocation: true,
1872 export_handle_types: &[],
1873 device_address: true,
1874 _ne: crate::NonExhaustive(()),
1875 }
1876 }
1877}
1878
1879/// Returns the smallest value greater or equal to `val` that is a multiple of `alignment`.
1880///
1881/// > **Note**: Returns zero on overflow.
1882#[inline(always)]
1883pub const fn align_up(val: DeviceSize, alignment: DeviceAlignment) -> DeviceSize {
1884 align_down(val.wrapping_add(alignment.as_devicesize() - 1), alignment)
1885}
1886
1887/// Returns the largest value smaller or equal to `val` that is a multiple of `alignment`.
1888#[inline(always)]
1889pub const fn align_down(val: DeviceSize, alignment: DeviceAlignment) -> DeviceSize {
1890 val & !(alignment.as_devicesize() - 1)
1891}
1892
1893mod array_vec {
1894 use std::ops::{Deref, DerefMut};
1895
1896 /// Minimal implementation of an `ArrayVec`. Useful when a `Vec` is needed but there is a known
1897 /// limit on the number of elements, so that it can occupy real estate on the stack.
1898 #[derive(Clone, Copy, Debug)]
1899 pub(super) struct ArrayVec<T, const N: usize> {
1900 len: usize,
1901 data: [T; N],
1902 }
1903
1904 impl<T, const N: usize> ArrayVec<T, N> {
1905 pub fn new(len: usize, data: [T; N]) -> Self {
1906 assert!(len <= N);
1907
1908 ArrayVec { len, data }
1909 }
1910 }
1911
1912 impl<T, const N: usize> Deref for ArrayVec<T, N> {
1913 type Target = [T];
1914
1915 fn deref(&self) -> &Self::Target {
1916 // SAFETY: `self.len <= N`.
1917 unsafe { self.data.get_unchecked(0..self.len) }
1918 }
1919 }
1920
1921 impl<T, const N: usize> DerefMut for ArrayVec<T, N> {
1922 fn deref_mut(&mut self) -> &mut Self::Target {
1923 // SAFETY: `self.len <= N`.
1924 unsafe { self.data.get_unchecked_mut(0..self.len) }
1925 }
1926 }
1927}
1928
1929mod aliasable_box {
1930 use slabbin::SlabAllocator;
1931 use std::{
1932 fmt,
1933 marker::PhantomData,
1934 ops::{Deref, DerefMut},
1935 panic::{RefUnwindSafe, UnwindSafe},
1936 ptr::NonNull,
1937 };
1938
1939 pub struct AliasableBox<T> {
1940 ptr: NonNull<T>,
1941 marker: PhantomData<T>,
1942 }
1943
1944 unsafe impl<T: Send> Send for AliasableBox<T> {}
1945 unsafe impl<T: Sync> Sync for AliasableBox<T> {}
1946
1947 impl<T: UnwindSafe> UnwindSafe for AliasableBox<T> {}
1948 impl<T: RefUnwindSafe> RefUnwindSafe for AliasableBox<T> {}
1949
1950 impl<T> Unpin for AliasableBox<T> {}
1951
1952 impl<T> AliasableBox<T> {
1953 pub fn new(value: T, allocator: &SlabAllocator<T>) -> Self {
1954 let ptr = allocator.allocate();
1955
1956 unsafe { ptr.as_ptr().write(value) };
1957
1958 AliasableBox {
1959 ptr,
1960 marker: PhantomData,
1961 }
1962 }
1963
1964 pub fn as_mut_ptr(this: &mut Self) -> *mut T {
1965 this.ptr.as_ptr()
1966 }
1967
1968 pub unsafe fn drop(this: &mut Self, allocator: &SlabAllocator<T>) {
1969 unsafe { this.ptr.as_ptr().drop_in_place() };
1970 unsafe { allocator.deallocate(this.ptr) };
1971 }
1972 }
1973
1974 impl<T: fmt::Debug> fmt::Debug for AliasableBox<T> {
1975 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1976 fmt::Debug::fmt(&**self, f)
1977 }
1978 }
1979
1980 impl<T> Deref for AliasableBox<T> {
1981 type Target = T;
1982
1983 #[inline]
1984 fn deref(&self) -> &Self::Target {
1985 unsafe { self.ptr.as_ref() }
1986 }
1987 }
1988
1989 impl<T> DerefMut for AliasableBox<T> {
1990 #[inline]
1991 fn deref_mut(&mut self) -> &mut Self::Target {
1992 unsafe { self.ptr.as_mut() }
1993 }
1994 }
1995}