From 012a4ac69767cd9692323aac1e92624915c055b6 Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Tue, 9 Oct 2018 13:25:01 +0200 Subject: [PATCH] Designed and documented new interface for defragmentation. Added: VmaDefragmentationContext, VmaDefragmentationFlagBits, VmaDefragmentationFlags, VmaDefragmentationInfo2, vmaDefragmentationBegin(), vmaDefragmentationEnd(). Extended VmaDefragmentationStats by allocationsLost. Deprecated VmaDefragmentationInfo2, vmaDefragment(). --- docs/html/annotated.html | 22 +- docs/html/classes.html | 8 +- docs/html/defragmentation.html | 4 +- docs/html/deprecated.html | 82 ++++++ docs/html/functions.html | 25 +- docs/html/functions_vars.html | 25 +- docs/html/globals.html | 32 ++- docs/html/globals_enum.html | 3 + docs/html/globals_eval.html | 15 + docs/html/globals_func.html | 6 + docs/html/globals_type.html | 9 + docs/html/pages.html | 1 + docs/html/record_and_replay.html | 2 +- docs/html/search/all_0.js | 3 +- docs/html/search/all_10.js | 11 + docs/html/search/all_3.js | 1 + docs/html/search/all_4.js | 2 +- docs/html/search/all_7.js | 4 + docs/html/search/all_a.js | 2 + docs/html/search/classes_0.js | 2 + docs/html/search/enums_0.js | 1 + docs/html/search/enumvalues_0.js | 5 + docs/html/search/functions_0.js | 2 + docs/html/search/pages_2.js | 3 +- docs/html/search/typedefs_1.js | 3 + docs/html/search/variables_0.js | 3 +- docs/html/search/variables_3.js | 2 +- docs/html/search/variables_4.js | 4 + docs/html/search/variables_6.js | 2 + docs/html/struct_vma_allocation_info.html | 6 +- .../struct_vma_defragmentation_context.html | 87 ++++++ .../html/struct_vma_defragmentation_info.html | 5 +- ...uct_vma_defragmentation_info2-members.html | 87 ++++++ .../struct_vma_defragmentation_info2.html | 253 ++++++++++++++++ ...uct_vma_defragmentation_stats-members.html | 9 +- .../struct_vma_defragmentation_stats.html | 23 +- docs/html/vk__mem__alloc_8h.html | 211 +++++++++++++- docs/html/vk__mem__alloc_8h_source.html | 43 ++- src/vk_mem_alloc.h | 271 +++++++++++++++--- 39 files changed, 1189 insertions(+), 90 deletions(-) create mode 100644 docs/html/deprecated.html create mode 100644 docs/html/struct_vma_defragmentation_context.html create mode 100644 docs/html/struct_vma_defragmentation_info2-members.html create mode 100644 docs/html/struct_vma_defragmentation_info2.html diff --git a/docs/html/annotated.html b/docs/html/annotated.html index 5cca84d..3e67fd5 100644 --- a/docs/html/annotated.html +++ b/docs/html/annotated.html @@ -72,16 +72,18 @@ $(function() {  CVmaAllocationInfoParameters of VmaAllocation objects, that can be retrieved using function vmaGetAllocationInfo()  CVmaAllocatorRepresents main object of this library initialized  CVmaAllocatorCreateInfoDescription of a Allocator to be created - CVmaDefragmentationInfoOptional configuration parameters to be passed to function vmaDefragment() - CVmaDefragmentationStatsStatistics returned by function vmaDefragment() - CVmaDeviceMemoryCallbacksSet of callbacks that the library will call for vkAllocateMemory and vkFreeMemory - CVmaPoolRepresents custom memory pool - CVmaPoolCreateInfoDescribes parameter of created VmaPool - CVmaPoolStatsDescribes parameter of existing VmaPool - CVmaRecordSettingsParameters for recording calls to VMA functions. To be used in VmaAllocatorCreateInfo::pRecordSettings - CVmaStatInfoCalculated statistics of memory usage in entire allocator - CVmaStatsGeneral statistics from current state of Allocator - CVmaVulkanFunctionsPointers to some Vulkan functions - a subset used by the library + CVmaDefragmentationContextRepresents Opaque object that represents started defragmentation process + CVmaDefragmentationInfoDeprecated. Optional configuration parameters to be passed to function vmaDefragment() + CVmaDefragmentationInfo2Parameters for defragmentation + CVmaDefragmentationStatsStatistics returned by function vmaDefragment() + CVmaDeviceMemoryCallbacksSet of callbacks that the library will call for vkAllocateMemory and vkFreeMemory + CVmaPoolRepresents custom memory pool + CVmaPoolCreateInfoDescribes parameter of created VmaPool + CVmaPoolStatsDescribes parameter of existing VmaPool + CVmaRecordSettingsParameters for recording calls to VMA functions. To be used in VmaAllocatorCreateInfo::pRecordSettings + CVmaStatInfoCalculated statistics of memory usage in entire allocator + CVmaStatsGeneral statistics from current state of Allocator + CVmaVulkanFunctionsPointers to some Vulkan functions - a subset used by the library diff --git a/docs/html/classes.html b/docs/html/classes.html index d922236..1b93e8a 100644 --- a/docs/html/classes.html +++ b/docs/html/classes.html @@ -68,10 +68,10 @@ $(function() {
v
- - - + + + +
  v  
-
VmaAllocationInfo   VmaDefragmentationStats   VmaPoolStats   VmaVulkanFunctions   
VmaAllocator   VmaDeviceMemoryCallbacks   VmaRecordSettings   
VmaAllocation   VmaAllocatorCreateInfo   VmaPool   VmaStatInfo   
VmaAllocationCreateInfo   VmaDefragmentationInfo   VmaPoolCreateInfo   VmaStats   
VmaAllocationInfo   VmaDefragmentationInfo   VmaPool   VmaStatInfo   
VmaAllocator   VmaDefragmentationInfo2   VmaPoolCreateInfo   VmaStats   
VmaAllocation   VmaAllocatorCreateInfo   VmaDefragmentationStats   VmaPoolStats   VmaVulkanFunctions   
VmaAllocationCreateInfo   VmaDefragmentationContext   VmaDeviceMemoryCallbacks   VmaRecordSettings   
v
diff --git a/docs/html/defragmentation.html b/docs/html/defragmentation.html index 72fa300..4f232ec 100644 --- a/docs/html/defragmentation.html +++ b/docs/html/defragmentation.html @@ -70,13 +70,13 @@ $(function() {

Interleaved allocations and deallocations of many objects of varying size can cause fragmentation, which can lead to a situation where the library is unable to find a continuous range of free memory for a new allocation despite there is enough free space, just scattered across many small free ranges between existing allocations.

-

To mitigate this problem, you can use vmaDefragment(). Given set of allocations, this function can move them to compact used memory, ensure more continuous free space and possibly also free some VkDeviceMemory. Currently it can work only on allocations made from memory type that is HOST_VISIBLE and HOST_COHERENT. Allocations are modified to point to the new VkDeviceMemory and offset. Data in this memory is also memmove-ed to the new place. However, if you have images or buffers bound to these allocations (and you certainly do), you need to destroy, recreate, and bind them to the new place in memory.

+

To mitigate this problem, you can use vmaDefragment(). Given set of allocations, this function can move them to compact used memory, ensure more continuous free space and possibly also free some VkDeviceMemory. Currently it can work only on allocations made from memory type that is HOST_VISIBLE and HOST_COHERENT. Allocations are modified to point to the new VkDeviceMemory and offset. Data in this memory is also memmove-ed to the new place. However, if you have images or buffers bound to these allocations (and you certainly do), you need to destroy, recreate, and bind them to the new place in memory.

After allocation has been moved, its VmaAllocationInfo::deviceMemory and/or VmaAllocationInfo::offset changes. You must query them again using vmaGetAllocationInfo() if you need them.

If an allocation has been moved, data in memory is copied to new place automatically, but if it was bound to a buffer or an image, you must destroy that object yourself, create new one and bind it to the new memory pointed by the allocation. You must use vkDestroyBuffer(), vkDestroyImage(), vkCreateBuffer(), vkCreateImage() for that purpose and NOT vmaDestroyBuffer(), vmaDestroyImage(), vmaCreateBuffer(), vmaCreateImage()! Example:

VkDevice device = ...;
VmaAllocator allocator = ...;
std::vector<VkBuffer> buffers = ...;
std::vector<VmaAllocation> allocations = ...;
const size_t allocCount = allocations.size();
std::vector<VkBool32> allocationsChanged(allocCount);
vmaDefragment(allocator, allocations.data(), allocCount, allocationsChanged.data(), nullptr, nullptr);
for(size_t i = 0; i < allocCount; ++i)
{
if(allocationsChanged[i])
{
// Destroy buffers that is immutably bound to memory region which is no longer valid.
vkDestroyBuffer(device, buffers[i], nullptr);
// Create new buffer with same parameters.
VkBufferCreateInfo bufferInfo = ...;
vkCreateBuffer(device, &bufferInfo, nullptr, &buffers[i]);
// You can make dummy call to vkGetBufferMemoryRequirements here to silence validation layer warning.
// Bind new buffer with new memory region. Data contained in it is already there.
VmaAllocationInfo allocInfo;
vmaGetAllocationInfo(allocator, allocations[i], &allocInfo);
vkBindBufferMemory(device, buffers[i], allocInfo.deviceMemory, allocInfo.offset);
}
}

Please don't expect memory to be fully compacted after defragmentation. Algorithms inside are based on some heuristics that try to maximize number of Vulkan memory blocks to make totally empty to release them, as well as to maximimze continuous empty space inside remaining blocks, while minimizing the number and size of allocations that needs to be moved. Some fragmentation still remains after this call. This is normal.

If you defragment allocations bound to images, these images should be created with VK_IMAGE_CREATE_ALIAS_BIT flag, to make sure that new image created with same parameters and pointing to data copied to another memory region will interpret its contents consistently. Otherwise you may experience corrupted data on some implementations, e.g. due to different pixel swizzling used internally by the graphics driver.

If you defragment allocations bound to images, new images to be bound to new memory region after defragmentation should be created with VK_IMAGE_LAYOUT_PREINITIALIZED and then transitioned to their original layout from before defragmentation using an image memory barrier.

-

For further details, see documentation of function vmaDefragment().

+

For further details, see documentation of function vmaDefragment().