Skip to main content

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}