Document the safety invariants of the (sub)allocator traits (#2321)

* Document the safety invariants of the (sub)allocator traits

* Oopsie

* Remove alignment from the safety requirements

Reason being that this requirement is already explained in the docs of
`Suballocation`, along with the requirements of the other fields.
This commit is contained in:
marc0246 2023-09-12 17:25:46 +02:00 committed by GitHub
parent 081d9c2d4e
commit c43a9c9d50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 5 deletions

View File

@ -257,7 +257,31 @@ const G: DeviceSize = 1024 * M;
///
/// # Safety
///
/// TODO
/// - `allocate`, `allocate_from_type` and `allocate_dedicated` must return a memory block that is
/// in bounds of its device memory.
/// - `allocate` and `allocate_from_type` must return a memory block that doesn't alias any other
/// currently allocated memory blocks:
/// - Two currently allocated memory blocks must not share any memory locations, meaning that the
/// intersection of the byte ranges of the two memory blocks must be empty.
/// - Two neighboring currently allocated memory blocks must not share any [page] whose size is
/// given by the [buffer-image granularity], unless either both were allocated with
/// [`AllocationType::Linear`] or both were allocated with [`AllocationType::NonLinear`].
/// - For all [host-visible] memory types that are not [host-coherent], all memory blocks must be
/// aligned to the [non-coherent atom size].
/// - The size does **not** have to be padded to the alignment. That is, as long the offset is
/// aligned and the memory blocks don't share any memory locations, a memory block is not
/// considered to alias another even if the padded size shares memory locations with another
/// memory block.
/// - A memory block must stay allocated until either `deallocate` is called on it or the allocator
/// is dropped. If the allocator is cloned, it must produce the same allocator, and memory blocks
/// must stay allocated until either `deallocate` is called on the memory block using any of the
/// clones or all of the clones have been dropped.
///
/// [page]: self#pages
/// [buffer-image granularity]: self#buffer-image-granularity
/// [host-visible]: MemoryPropertyFlags::HOST_VISIBLE
/// [host-coherent]: MemoryPropertyFlags::HOST_COHERENT
/// [non-coherent atom size]: crate::device::Properties::non_coherent_atom_size
pub unsafe trait MemoryAllocator: DeviceOwned + Send + Sync + 'static {
/// Finds the most suitable memory type index in `memory_type_bits` using the given `filter`.
/// Returns [`None`] if the requirements are too strict and no memory type is able to satisfy

View File

@ -50,7 +50,7 @@ use std::{
/// trade-offs and are best suited to specific tasks. To account for all possible use-cases,
/// Vulkano offers the ability to create *memory hierarchies*. We refer to the `DeviceMemory` as
/// the root of any such hierarchy, even though technically the driver has levels that are further
/// up, because those `DeviceMemory` blocks need to be allocated from physical memory [pages]
/// up, because those `DeviceMemory` blocks need to be allocated from physical memory pages
/// themselves, but since those levels are not accessible to us we don't need to consider them. You
/// can create any number of levels/branches from there, bounded only by the amount of available
/// memory within a `DeviceMemory` block. You can suballocate the root into regions, which are then
@ -60,12 +60,31 @@ use std::{
///
/// TODO
///
/// # Implementing the trait
/// # Safety
///
/// TODO
/// First consider using the provided implementations as there should be no reason to implement
/// this trait, but if you **must**:
///
/// - `allocate` must return a memory block that is in bounds of the region.
/// - `allocate` must return a memory block that doesn't alias any other currently allocated
/// memory blocks:
/// - Two currently allocated memory blocks must not share any memory locations, meaning that the
/// intersection of the byte ranges of the two memory blocks must be empty.
/// - Two neighboring currently allocated memory blocks must not share any [page] whose size is
/// given by the [buffer-image granularity], unless either both were allocated with
/// [`AllocationType::Linear`] or both were allocated with [`AllocationType::NonLinear`].
/// - The size does **not** have to be padded to the alignment. That is, as long the offset is
/// aligned and the memory blocks don't share any memory locations, a memory block is not
/// considered to alias another even if the padded size shares memory locations with another
/// memory block.
/// - A memory block must stay allocated until either `deallocate` is called on it or the allocator
/// is dropped. If the allocator is cloned, it must produce the same allocator, and memory blocks
/// must stay allocated until either `deallocate` is called on the memory block using any of the
/// clones or all of the clones have been dropped.
///
/// [`DeviceMemory`]: crate::memory::DeviceMemory
/// [pages]: super#pages
/// [page]: super#pages
/// [buffer-image granularity]: super#buffer-image-granularity
pub unsafe trait Suballocator {
/// Whether the allocator needs [`cleanup`] to be called before memory can be released.
///