vpr::MemoryBlock class

A MemoryBlock is a large contiguous region of Vulkan memory of a uniform type (device local, host coherent, host visible, etc) that other objects bind to subregions of.

This should never be directly accessed by any client code: it is managed and interfaced to by other objects, and several of these of each type can exist (occurs when a memory block is fully used, until no more memory available).

Constructors, destructors, conversion operators

~MemoryBlock()
The object should be destroyed via the Destroy method before the destructor is called, but this will call the Destroy method if it hasn't been, and will log a warning that this was done.

Public functions

void Init(VkDeviceMemory& new_memory, const VkDeviceSize& new_size)
void Destroy()
Cleans up resources and prepares object to be safely destroyed.
auto Validate() const -> ValidationCode
Verifies integrity of memory by checking all contained suballocations for integrity and correctness.
auto RequestSuballocation(const VkDeviceSize& buffer_image_granularity, const VkDeviceSize& allocation_size, const VkDeviceSize& allocation_alignment, SuballocationType allocation_type, SuballocationRequest* dest_request) -> bool
Fills the given SuballocationRequest struct with information about where to place the suballocation, and returns whether or not it succeeded in finding a spot to put the requested suballocation.
auto VerifySuballocation(const VkDeviceSize& buffer_image_granularity, const VkDeviceSize& allocation_size, const VkDeviceSize& allocation_alignment, SuballocationType allocation_type, const suballocationList::const_iterator& dest_suballocation_location, VkDeviceSize* dest_offset) const -> bool
Verifies that requested suballocation can be added to this object, and sets dest_offset to reflect offset of this now-inserted suballocation.
void Allocate(const SuballocationRequest& request, const SuballocationType& allocation_type, const VkDeviceSize& allocation_size)
Performs the actual allocation, once "request" has been checked and made valid.
void Free(const Allocation* memory_to_free)
Frees memory in region specified (i.e frees/destroys a suballocation)
void Map(const Allocation* alloc_being_mapped, const VkDeviceSize& size_of_map, const VkDeviceSize& offset_to_map_at, void** destination_address)
When we map a suballocation, we are mapping a sub-region of the larger memory object it is bound to.
void Unmap()
As mentioned for the Map method, due to VkMapMemory functions we must make sure only one sub-region of an object is unmapped at a time, thus requiring the parent block to oversee the mapping/unmapping + using a mutex for thread safety.

Protected functions

void freeSuballocation(const suballocationList::iterator& item_to_free)
Changes the item pointed to by the iterator to be a free type, then adds the now-available size to availSize and increments freeCount.
void mergeFreeWithNext(const suballocationList::iterator& item_to_merge)
Effectively reduces fragmentation by merging two free allocations that are adjacent in memory into one larger allocation.
void insertFreeSuballocation(const suballocationList::iterator& item_to_insert)
Registers a free suballocation, inserting it into the proper location to keep the sorting intact (via std::lower_bound)
void removeFreeSuballocation(const suballocationList::iterator& item_to_remove)
Removes a free suballocation, usually indicating that it is about to be made active and used by an object (or that it has been merged with another free suballocation)

Protected variables

std::vector<suballocationList::iterator> availSuballocations
This vector stores iterators that can be used to locate suballocations in this object's suballocationList.

Function documentation

void vpr::MemoryBlock::Init(VkDeviceMemory& new_memory, const VkDeviceSize& new_size)

Parameters
new_memory This is the handle that this block will take ownership of.
new_size total size of this memory block.

void vpr::MemoryBlock::Destroy()

Cleans up resources and prepares object to be safely destroyed.

Should be called before the destructor is called, but for safety's sake the destructor will also call this.

bool vpr::MemoryBlock::RequestSuballocation(const VkDeviceSize& buffer_image_granularity, const VkDeviceSize& allocation_size, const VkDeviceSize& allocation_alignment, SuballocationType allocation_type, SuballocationRequest* dest_request)

Fills the given SuballocationRequest struct with information about where to place the suballocation, and returns whether or not it succeeded in finding a spot to put the requested suballocation.

Usually, a failure means we'll just try another memory block (and ultimately, consider creating a new one)

void vpr::MemoryBlock::Map(const Allocation* alloc_being_mapped, const VkDeviceSize& size_of_map, const VkDeviceSize& offset_to_map_at, void** destination_address)

When we map a suballocation, we are mapping a sub-region of the larger memory object it is bound to.

We cannot perform another map until this sub-region is unmapped. Thus, suballocations actually call their parent's mapping method. This lets us use a mutex to lock off access to this block's VkDeviceMemory object until the memory is unmapped.

void vpr::MemoryBlock::freeSuballocation(const suballocationList::iterator& item_to_free) protected

Changes the item pointed to by the iterator to be a free type, then adds the now-available size to availSize and increments freeCount.

This method may also call mergeFreeWithNext, insertFreeSuballocation, and removeFreeSuballocation if adjacent suballocations are free or can be merged with the now-free allocation passed in.

Variable documentation

std::vector<suballocationList::iterator> vpr::MemoryBlock::availSuballocations protected

This vector stores iterators that can be used to locate suballocations in this object's suballocationList.

Using iterators avoids accidental duplication of objects, (akin to a pointer), but with more safety and extra convienience when it comes to retrieving, modifying, or even removing the object "pointed" to by the iterator.