Trait vulkano::memory::allocator::suballocator::Suballocator
source · pub unsafe trait Suballocator {
// Required methods
fn new(region: Region) -> Self
where Self: Sized;
fn allocate(
&self,
layout: DeviceLayout,
allocation_type: AllocationType,
buffer_image_granularity: DeviceAlignment
) -> Result<Suballocation, SuballocatorError>;
unsafe fn deallocate(&self, suballocation: Suballocation);
fn free_size(&self) -> DeviceSize;
fn cleanup(&mut self);
}
Expand description
Suballocators are used to divide a region into smaller suballocations.
Regions
As the name implies, a region is a contiguous portion of memory. It may be the whole dedicated
block of DeviceMemory
, or only a part of it. Or it may be a buffer, or only a part of a
buffer. Regions are just allocations like any other, but we use this term to refer specifically
to an allocation that is to be suballocated. Every suballocator is created with a region to
work with.
Free-lists
A free-list, also kind of predictably, refers to a list of (sub)allocations within a region that are currently free. Every (sub)allocator that can free allocations dynamically (in any order) needs to keep a free-list of some sort. This list is then consulted when new allocations are made, and can be used to coalesce neighboring allocations that are free into bigger ones.
Memory hierarchies
Different applications have wildly different allocation needs, and there’s no way to cover them
all with a single type of allocator. Furthermore, different allocators have different
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
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
suballocated into further regions and so on, creating hierarchies of arbitrary height.
Examples
TODO
Safety
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 withAllocationType::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 eitherdeallocate
is called on the memory block using any of the clones or all of the clones have been dropped.
Required Methods§
sourcefn new(region: Region) -> Selfwhere
Self: Sized,
fn new(region: Region) -> Selfwhere Self: Sized,
Creates a new suballocator for the given region.
sourcefn allocate(
&self,
layout: DeviceLayout,
allocation_type: AllocationType,
buffer_image_granularity: DeviceAlignment
) -> Result<Suballocation, SuballocatorError>
fn allocate( &self, layout: DeviceLayout, allocation_type: AllocationType, buffer_image_granularity: DeviceAlignment ) -> Result<Suballocation, SuballocatorError>
Creates a new suballocation within the region.
Arguments
-
layout
- The layout of the allocation. -
allocation_type
- The type of resources that can be bound to the allocation. -
buffer_image_granularity
- The buffer-image granularity device property.This is provided as an argument here rather than on construction of the allocator to allow for optimizations: if you are only ever going to be creating allocations with the same
allocation_type
using this allocator, then you may hard-code this toDeviceAlignment::MIN
, in which case, after inlining, the logic for aligning the allocation to the buffer-image-granularity based on the allocation type of surrounding allocations can be optimized out.You don’t need to consider the buffer-image granularity for instance when suballocating a buffer, or when suballocating a
DeviceMemory
block that’s only ever going to be used for optimal images. However, if you do allocate both linear and non-linear resources and don’t specify the buffer-image granularity device property here, you will get undefined behavior down the line. Note thatAllocationType::Unknown
counts as both linear and non-linear at the same time: if you always use this as theallocation_type
using this allocator, then it is valid to set this toDeviceAlignment::MIN
, but you must ensure all allocations are aligned to the buffer-image granularity at minimum.
sourceunsafe fn deallocate(&self, suballocation: Suballocation)
unsafe fn deallocate(&self, suballocation: Suballocation)
Deallocates the given suballocation
.
Safety
suballocation
must refer to a currently allocated suballocation ofself
.
sourcefn free_size(&self) -> DeviceSize
fn free_size(&self) -> DeviceSize
Returns the total amount of free space that is left in the region.