From 7d182e2c5a5af5ad0c3d5c380a17166fde4c65ac Mon Sep 17 00:00:00 2001 From: Adam Sawicki Date: Mon, 7 Mar 2022 17:00:12 +0100 Subject: [PATCH] Change in the defragmentation API. Compatibility breaking! Removed VmaDefragmentationMove::dstMemory, dstOffset, internalData, added dstTmpAllocation. Code by @medranSolus --- docs/html/defragmentation.html | 22 +++--- docs/html/functions.html | 4 +- docs/html/functions_vars.html | 4 +- docs/html/group__group__alloc.html | 8 +- docs/html/search/all_3.js | 3 +- docs/html/search/all_7.js | 3 +- docs/html/search/variables_2.js | 3 +- docs/html/search/variables_4.js | 3 +- ...ruct_vma_defragmentation_move-members.html | 4 +- .../html/struct_vma_defragmentation_move.html | 57 +++------------ ...ct_vma_defragmentation_pass_move_info.html | 4 +- docs/html/virtual_allocator.html | 14 ++-- include/vk_mem_alloc.h | 73 +++++++------------ src/Tests.cpp | 4 +- 14 files changed, 70 insertions(+), 136 deletions(-) diff --git a/docs/html/defragmentation.html b/docs/html/defragmentation.html index 7fe71fc..ceb7eea 100644 --- a/docs/html/defragmentation.html +++ b/docs/html/defragmentation.html @@ -101,7 +101,7 @@ $(function() {
VkImage newImg;
res = vkCreateImage(device, &imgCreateInfo, nullptr, &newImg);
// Check res...
-
res = vKBindImageMemory(device, newImg, pass.pMoves[i].dstMemory, pass.pMoves[i].dstOffset);
+
res = vmaBindImageMemory(allocator, pMoves[i].dstTmpAllocation, newImg);
// Check res...
// Issue a vkCmdCopyBuffer/vkCmdCopyImage to copy its content to the new place.
@@ -128,6 +128,7 @@ $(function() {
}
vmaEndDefragmentation(allocator, defragCtx, nullptr);
+
VkResult vmaBindImageMemory(VmaAllocator allocator, VmaAllocation allocation, VkImage image)
Binds image to allocation.
void vmaEndDefragmentation(VmaAllocator allocator, VmaDefragmentationContext context, VmaDefragmentationStats *pStats)
Ends defragmentation process.
void vmaGetAllocationInfo(VmaAllocator allocator, VmaAllocation allocation, VmaAllocationInfo *pAllocationInfo)
Returns current information about specified allocation.
VkResult vmaBeginDefragmentationPass(VmaAllocator allocator, VmaDefragmentationContext context, VmaDefragmentationPassMoveInfo *pPassInfo)
Starts single defragmentation pass.
@@ -140,33 +141,30 @@ $(function() {
Parameters for defragmentation.
Definition: vk_mem_alloc.h:1401
VmaPool pool
Custom pool to be defragmented.
Definition: vk_mem_alloc.h:1408
VmaDefragmentationFlags flags
Use combination of VmaDefragmentationFlagBits.
Definition: vk_mem_alloc.h:1403
-
VkDeviceMemory dstMemory
Destination memory block where the allocation should be moved.
Definition: vk_mem_alloc.h:1429
-
VkDeviceSize dstOffset
Destination offset where the allocation should be moved.
Definition: vk_mem_alloc.h:1431
-
Parameters for incremental defragmentation steps.
Definition: vk_mem_alloc.h:1441
-
uint32_t moveCount
Number of elements in the pMoves array.
Definition: vk_mem_alloc.h:1443
-
VmaDefragmentationMove * pMoves
Array of moves to be performed by the user in the current defragmentation pass.
Definition: vk_mem_alloc.h:1467
+
Parameters for incremental defragmentation steps.
Definition: vk_mem_alloc.h:1442
+
uint32_t moveCount
Number of elements in the pMoves array.
Definition: vk_mem_alloc.h:1444

Although functions like vmaCreateBuffer(), vmaCreateImage(), vmaDestroyBuffer(), vmaDestroyImage() create/destroy an allocation and a buffer/image at once, these are just a shortcut for creating the resource, allocating memory, and binding them together. Defragmentation works on memory allocations only. You must handle the rest manually. Defragmentation is an iterative process that should repreat "passes" as long as related functions return VK_INCOMPLETE not VK_SUCCESS. In each pass:

  1. vmaBeginDefragmentationPass() function call:
    • Calculates and returns the list of allocations to be moved in this pass. Note this can be a time-consuming process.
    • -
    • Reserves destination memory for them by creating internal allocations. Returns their VkDeviceMemory + offset.
    • +
    • Reserves destination memory for them by creating temporary destination allocations that you can query for their VkDeviceMemory + offset using vmaGetAllocationInfo().
  2. Inside the pass, you should:
    • Inspect the returned list of allocations to be moved.
    • -
    • Create new buffers/images and bind them at the returned destination VkDeviceMemory + offset.
    • +
    • Create new buffers/images and bind them at the returned destination temporary allocations.
    • Copy data from source to destination resources if necessary.
    • Destroy the source buffers/images, but NOT their allocations.
  3. vmaEndDefragmentationPass() function call:
    • Frees the source memory reserved for the allocations that are moved.
    • -
    • Modifies VmaAllocation objects that are moved to point to the destination reserved memory.
    • +
    • Modifies source VmaAllocation objects that are moved to point to the destination reserved memory.
    • Frees VkDeviceMemory blocks that became empty.
-

Unlike in previous iterations of the defragmentation API, there is no list of "movable" allocations passed as a parameter. Defragmentation algorithm tries to move all suitable allocations. You can, however, refuse to move some of them inside a defragmentation pass, by setting pass.pMoves[i].operation to VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. This is not recommended and may result in suboptimal packing of the allocations after defragmentation. If you cannot ensure any allocation can be moved, it is better to keep movable allocations separate in a custom pool.

+

Unlike in previous iterations of the defragmentation API, there is no list of "movable" allocations passed as a parameter. Defragmentation algorithm tries to move all suitable allocations. You can, however, refuse to move some of them inside a defragmentation pass, by setting pass.pMoves[i].operation to VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE. This is not recommended and may result in suboptimal packing of the allocations after defragmentation. If you cannot ensure any allocation can be moved, it is better to keep movable allocations separate in a custom pool.

Inside a pass, for each allocation that should be moved:

@@ -100,7 +99,6 @@ $(function() {

- i -

diff --git a/docs/html/group__group__alloc.html b/docs/html/group__group__alloc.html index 719170e..331f431 100644 --- a/docs/html/group__group__alloc.html +++ b/docs/html/group__group__alloc.html @@ -712,11 +712,11 @@ Functions

Operation performed on single defragmentation move. See structure VmaDefragmentationMove.

- - -
Enumerator
VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY 

Buffer/image has been recreated at dstMemory + dstOffset, data has been copied, old buffer/image has been destroyed. srcAllocation should be changed to point to the new place. This is the default value set by vmaBeginDefragmentationPass().

+
Enumerator
VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY 

Buffer/image has been recreated at dstTmpAllocation, data has been copied, old buffer/image has been destroyed. srcAllocation should be changed to point to the new place. This is the default value set by vmaBeginDefragmentationPass().

VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE 

Set this value if you cannot move the allocation. New place reserved dstMemory + dstOffset will be freed. srcAllocation will remain unchanged.

+
VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE 

Set this value if you cannot move the allocation. New place reserved at dstTmpAllocation will be freed. srcAllocation will remain unchanged.

VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY 

Set this value if you decide to abandon the allocation and you destroyed the buffer/image. New place reserved dstMemory + dstOffset will be freed, along with srcAllocation.

+
VMA_DEFRAGMENTATION_MOVE_OPERATION_DESTROY 

Set this value if you decide to abandon the allocation and you destroyed the buffer/image. New place reserved at dstTmpAllocation will be freed, along with srcAllocation, which will be destroyed.

@@ -1862,7 +1862,7 @@ Functions

Returns VK_SUCCESS if no more moves are possible or VK_INCOMPLETE if more defragmentations are possible.

Ends incremental defragmentation pass and commits all defragmentation moves from pPassInfo. After this call:

If no more moves are possible you can end whole defragmentation.

diff --git a/docs/html/search/all_3.js b/docs/html/search/all_3.js index bc4a061..193d1da 100644 --- a/docs/html/search/all_3.js +++ b/docs/html/search/all_3.js @@ -6,6 +6,5 @@ var searchData= ['device_3',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo::device()'],['../struct_vma_allocator_info.html#a012b4c485bf3b0ea8921352c5ee0c357',1,'VmaAllocatorInfo::device()']]], ['devicememory_4',['deviceMemory',['../struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67',1,'VmaAllocationInfo']]], ['devicememoryblocksfreed_5',['deviceMemoryBlocksFreed',['../struct_vma_defragmentation_stats.html#a0113f1877904a5d1ee8f409216ff276b',1,'VmaDefragmentationStats']]], - ['dstmemory_6',['dstMemory',['../struct_vma_defragmentation_move.html#a382fbec8dac2747abdc1883b69ef9458',1,'VmaDefragmentationMove']]], - ['dstoffset_7',['dstOffset',['../struct_vma_defragmentation_move.html#a80c466b445bc272f82c7dbf1a971ba18',1,'VmaDefragmentationMove']]] + ['dsttmpallocation_6',['dstTmpAllocation',['../struct_vma_defragmentation_move.html#ab65b106adf209acd7313296d1075300e',1,'VmaDefragmentationMove']]] ]; diff --git a/docs/html/search/all_7.js b/docs/html/search/all_7.js index be9f324..de9b72c 100644 --- a/docs/html/search/all_7.js +++ b/docs/html/search/all_7.js @@ -1,5 +1,4 @@ var searchData= [ - ['instance_0',['instance',['../struct_vma_allocator_create_info.html#a70dd42e29b1df1d1b9b61532ae0b370b',1,'VmaAllocatorCreateInfo::instance()'],['../struct_vma_allocator_info.html#a2ed6a4d2d3fea039d66a13f15d0ce5fe',1,'VmaAllocatorInfo::instance()']]], - ['internaldata_1',['internalData',['../struct_vma_defragmentation_move.html#a4f3637400767f3e642b3936e18b00e0f',1,'VmaDefragmentationMove']]] + ['instance_0',['instance',['../struct_vma_allocator_create_info.html#a70dd42e29b1df1d1b9b61532ae0b370b',1,'VmaAllocatorCreateInfo::instance()'],['../struct_vma_allocator_info.html#a2ed6a4d2d3fea039d66a13f15d0ce5fe',1,'VmaAllocatorInfo::instance()']]] ]; diff --git a/docs/html/search/variables_2.js b/docs/html/search/variables_2.js index b763c1a..4739a71 100644 --- a/docs/html/search/variables_2.js +++ b/docs/html/search/variables_2.js @@ -3,6 +3,5 @@ var searchData= ['device_0',['device',['../struct_vma_allocator_create_info.html#ad924ddd77b04039c88d0c09b0ffcd500',1,'VmaAllocatorCreateInfo::device()'],['../struct_vma_allocator_info.html#a012b4c485bf3b0ea8921352c5ee0c357',1,'VmaAllocatorInfo::device()']]], ['devicememory_1',['deviceMemory',['../struct_vma_allocation_info.html#ae0bfb7dfdf79a76ffefc9a94677a2f67',1,'VmaAllocationInfo']]], ['devicememoryblocksfreed_2',['deviceMemoryBlocksFreed',['../struct_vma_defragmentation_stats.html#a0113f1877904a5d1ee8f409216ff276b',1,'VmaDefragmentationStats']]], - ['dstmemory_3',['dstMemory',['../struct_vma_defragmentation_move.html#a382fbec8dac2747abdc1883b69ef9458',1,'VmaDefragmentationMove']]], - ['dstoffset_4',['dstOffset',['../struct_vma_defragmentation_move.html#a80c466b445bc272f82c7dbf1a971ba18',1,'VmaDefragmentationMove']]] + ['dsttmpallocation_3',['dstTmpAllocation',['../struct_vma_defragmentation_move.html#ab65b106adf209acd7313296d1075300e',1,'VmaDefragmentationMove']]] ]; diff --git a/docs/html/search/variables_4.js b/docs/html/search/variables_4.js index be9f324..de9b72c 100644 --- a/docs/html/search/variables_4.js +++ b/docs/html/search/variables_4.js @@ -1,5 +1,4 @@ var searchData= [ - ['instance_0',['instance',['../struct_vma_allocator_create_info.html#a70dd42e29b1df1d1b9b61532ae0b370b',1,'VmaAllocatorCreateInfo::instance()'],['../struct_vma_allocator_info.html#a2ed6a4d2d3fea039d66a13f15d0ce5fe',1,'VmaAllocatorInfo::instance()']]], - ['internaldata_1',['internalData',['../struct_vma_defragmentation_move.html#a4f3637400767f3e642b3936e18b00e0f',1,'VmaDefragmentationMove']]] + ['instance_0',['instance',['../struct_vma_allocator_create_info.html#a70dd42e29b1df1d1b9b61532ae0b370b',1,'VmaAllocatorCreateInfo::instance()'],['../struct_vma_allocator_info.html#a2ed6a4d2d3fea039d66a13f15d0ce5fe',1,'VmaAllocatorInfo::instance()']]] ]; diff --git a/docs/html/struct_vma_defragmentation_move-members.html b/docs/html/struct_vma_defragmentation_move-members.html index 056f74d..7aac213 100644 --- a/docs/html/struct_vma_defragmentation_move-members.html +++ b/docs/html/struct_vma_defragmentation_move-members.html @@ -68,9 +68,7 @@ $(function() {

This is the complete list of members for VmaDefragmentationMove, including all inherited members.

- - - +
dstMemoryVmaDefragmentationMove
dstOffsetVmaDefragmentationMove
internalDataVmaDefragmentationMove
dstTmpAllocationVmaDefragmentationMove
operationVmaDefragmentationMove
srcAllocationVmaDefragmentationMove
diff --git a/docs/html/struct_vma_defragmentation_move.html b/docs/html/struct_vma_defragmentation_move.html index f9a3f4c..444d782 100644 --- a/docs/html/struct_vma_defragmentation_move.html +++ b/docs/html/struct_vma_defragmentation_move.html @@ -75,69 +75,32 @@ $(function() {

Public Attributes

VmaDefragmentationMoveOperation operation - Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it. More...
+ Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it. More...
  VmaAllocation srcAllocation  Allocation that should be moved. More...
  -VkDeviceMemory dstMemory - Destination memory block where the allocation should be moved. More...
-  -VkDeviceSize dstOffset - Destination offset where the allocation should be moved. More...
-  -void * internalData - Internal data used by VMA. Do not use or modify! More...
-  +VmaAllocation dstTmpAllocation + Temporary allocation pointing to destination memory that will replace srcAllocation. More...

Detailed Description

Single move of an allocation to be done for defragmentation.

Member Data Documentation

- -

◆ dstMemory

+ +

◆ dstTmpAllocation

- +
VkDeviceMemory VmaDefragmentationMove::dstMemoryVmaAllocation VmaDefragmentationMove::dstTmpAllocation
-

Destination memory block where the allocation should be moved.

- -
-
- -

◆ dstOffset

- -
-
- - - - -
VkDeviceSize VmaDefragmentationMove::dstOffset
-
- -

Destination offset where the allocation should be moved.

- -
-
- -

◆ internalData

- -
-
- - - - -
void* VmaDefragmentationMove::internalData
-
- -

Internal data used by VMA. Do not use or modify!

+

Temporary allocation pointing to destination memory that will replace srcAllocation.

+
Warning
Do not store this allocation in your data structures! It exists only temporarily, for the duration of the defragmentation pass, to be used for binding new buffer/image to the destination memory using e.g. vmaBindBufferMemory(). vmaEndDefragmentationPass() will destroy it and make srcAllocation point to this memory.
@@ -153,7 +116,7 @@ Public Attributes
-

Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it.

+

Operation to be performed on the allocation by vmaEndDefragmentationPass(). Default value is VMA_DEFRAGMENTATION_MOVE_OPERATION_COPY. You can modify it.

diff --git a/docs/html/struct_vma_defragmentation_pass_move_info.html b/docs/html/struct_vma_defragmentation_pass_move_info.html index ea8a5a6..91d3950 100644 --- a/docs/html/struct_vma_defragmentation_pass_move_info.html +++ b/docs/html/struct_vma_defragmentation_pass_move_info.html @@ -117,13 +117,13 @@ Public Attributes

Pointer to an array of moveCount elements, owned by VMA, created in vmaBeginDefragmentationPass(), destroyed in vmaEndDefragmentationPass().

For each element, you should:

    -
  1. Create a new buffer/image in the place pointed by VmaDefragmentationMove::dstMemory + VmaDefragmentationMove::dstOffset.
  2. +
  3. Create a new buffer/image in the place pointed by VmaDefragmentationMove::dstMemory + VmaDefragmentationMove::dstOffset.
  4. Copy data from the VmaDefragmentationMove::srcAllocation e.g. using vkCmdCopyBuffer, vkCmdCopyImage.
  5. Make sure these commands finished executing on the GPU.
  6. Destroy the old buffer/image.

Only then you can finish defragmentation pass by calling vmaEndDefragmentationPass(). After this call, the allocation will point to the new place in memory.

-

Alternatively, if you cannot move specific allocation, you can set VmaDefragmentationMove::operation to VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE.

+

Alternatively, if you cannot move specific allocation, you can set VmaDefragmentationMove::operation to VMA_DEFRAGMENTATION_MOVE_OPERATION_IGNORE.

Alternatively, if you decide you want to completely remove the allocation:

  1. Destroy its buffer/image.
  2. diff --git a/docs/html/virtual_allocator.html b/docs/html/virtual_allocator.html index 4df5f65..f233ca2 100644 --- a/docs/html/virtual_allocator.html +++ b/docs/html/virtual_allocator.html @@ -84,8 +84,8 @@ Creating virtual block
    VkResult res = vmaCreateVirtualBlock(&blockCreateInfo, &block);
    VkResult vmaCreateVirtualBlock(const VmaVirtualBlockCreateInfo *pCreateInfo, VmaVirtualBlock *pVirtualBlock)
    Creates new VmaVirtualBlock object.
    -
    Parameters of created VmaVirtualBlock object to be passed to vmaCreateVirtualBlock().
    Definition: vk_mem_alloc.h:1492
    -
    VkDeviceSize size
    Total size of the virtual block.
    Definition: vk_mem_alloc.h:1498
    +
    Parameters of created VmaVirtualBlock object to be passed to vmaCreateVirtualBlock().
    Definition: vk_mem_alloc.h:1493
    +
    VkDeviceSize size
    Total size of the virtual block.
    Definition: vk_mem_alloc.h:1499
    Handle to a virtual block object that allows to use core allocation algorithm without allocating any ...

    Making virtual allocations

    @@ -111,8 +111,8 @@ Making virtual allocations
    // Allocation failed - no space for it could be found. Handle this error!
    }
    VkResult vmaVirtualAllocate(VmaVirtualBlock virtualBlock, const VmaVirtualAllocationCreateInfo *pCreateInfo, VmaVirtualAllocation *pAllocation, VkDeviceSize *pOffset)
    Allocates new virtual allocation inside given VmaVirtualBlock.
    -
    Parameters of created virtual allocation to be passed to vmaVirtualAllocate().
    Definition: vk_mem_alloc.h:1513
    -
    VkDeviceSize size
    Size of the allocation.
    Definition: vk_mem_alloc.h:1518
    +
    Parameters of created virtual allocation to be passed to vmaVirtualAllocate().
    Definition: vk_mem_alloc.h:1514
    +
    VkDeviceSize size
    Size of the allocation.
    Definition: vk_mem_alloc.h:1519
    Represents single memory allocation done inside VmaVirtualBlock.

    Deallocation

    @@ -140,8 +140,8 @@ Allocation parameters
    vmaVirtualFree(block, alloc);
    void vmaGetVirtualAllocationInfo(VmaVirtualBlock virtualBlock, VmaVirtualAllocation allocation, VmaVirtualAllocationInfo *pVirtualAllocInfo)
    Returns information about a specific virtual allocation within a virtual block, like its size and pUs...
    -
    Parameters of an existing virtual allocation, returned by vmaGetVirtualAllocationInfo().
    Definition: vk_mem_alloc.h:1536
    -
    void * pUserData
    Custom pointer associated with the allocation.
    Definition: vk_mem_alloc.h:1551
    +
    Parameters of an existing virtual allocation, returned by vmaGetVirtualAllocationInfo().
    Definition: vk_mem_alloc.h:1537
    +
    void * pUserData
    Custom pointer associated with the allocation.
    Definition: vk_mem_alloc.h:1552

    Alignment and units

    It feels natural to express sizes and offsets in bytes. If an offset of an allocation needs to be aligned to a multiply of some number (e.g. 4 bytes), you can fill optional member VmaVirtualAllocationCreateInfo::alignment to request it. Example:

    @@ -151,7 +151,7 @@ Alignment and units
    res = vmaVirtualAllocate(block, &allocCreateInfo, &alloc, nullptr);
    -
    VkDeviceSize alignment
    Required alignment of the allocation. Optional.
    Definition: vk_mem_alloc.h:1523
    +
    VkDeviceSize alignment
    Required alignment of the allocation. Optional.
    Definition: vk_mem_alloc.h:1524

    Alignments of different allocations made from one block may vary. However, if all alignments and sizes are always multiply of some size e.g. 4 B or sizeof(MyDataStruct), you can express all sizes, alignments, and offsets in multiples of that size instead of individual bytes. It might be more convenient, but you need to make sure to use this new unit consistently in all the places: