Added VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT, WORST_FIT, FIRST_FIT, and aliases: VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT, MIN_TIME, MIN_FRAGMENTATION.

Deleted VMA_BEST_FIT macro.
diff --git a/src/vk_mem_alloc.h b/src/vk_mem_alloc.h
index 7dd8ff2..d3be4dd 100644
--- a/src/vk_mem_alloc.h
+++ b/src/vk_mem_alloc.h
@@ -1806,6 +1806,29 @@
     */

     VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT = 0x00000040,

 

+    /** Allocation strategy that chooses smallest possible free range for the

+    allocation.

+    */

+    VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT  = 0x00010000,

+    /** Allocation strategy that chooses biggest possible free range for the

+    allocation.

+    */

+    VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT = 0x00020000,

+    /** Allocation strategy that chooses first suitable free range for the

+    allocation.

+    */

+    VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT = 0x00040000,

+

+    /** Allocation strategy that tries to minimize memory usage.

+    */

+    VMA_ALLOCATION_CREATE_STRATEGY_MIN_MEMORY_BIT = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT,

+    /** Allocation strategy that tries to minimize allocation time.

+    */

+    VMA_ALLOCATION_CREATE_STRATEGY_MIN_TIME_BIT = VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT,

+    /** Allocation strategy that tries to minimize memory fragmentation.

+    */

+    VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT = VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT,

+

     VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF

 } VmaAllocationCreateFlagBits;

 typedef VkFlags VmaAllocationCreateFlags;

@@ -2793,22 +2816,6 @@
    #define VMA_ATOMIC_UINT32 std::atomic<uint32_t>

 #endif

 

-#ifndef VMA_BEST_FIT

-    /**

-    Main parameter for function assessing how good is a free suballocation for a new

-    allocation request.

-    

-    - Set to 1 to use Best-Fit algorithm - prefer smaller blocks, as close to the

-      size of requested allocations as possible.

-    - Set to 0 to use Worst-Fit algorithm - prefer larger blocks, as large as

-      possible.

-    

-    Experiments in special testing environment showed that Best-Fit algorithm is

-    better.

-    */

-    #define VMA_BEST_FIT (1)

-#endif

-

 #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY

     /**

     Every allocation will have its own memory block.

@@ -4536,6 +4543,7 @@
         bool upperAddress,

         VmaSuballocationType allocType,

         bool canMakeOtherLost,

+        uint32_t strategy, // Always one of VMA_ALLOCATION_CREATE_STRATEGY_* flags.

         VmaAllocationRequest* pAllocationRequest) = 0;

 

     virtual bool MakeRequestedAllocationsLost(

@@ -4608,6 +4616,7 @@
         bool upperAddress,

         VmaSuballocationType allocType,

         bool canMakeOtherLost,

+        uint32_t strategy,

         VmaAllocationRequest* pAllocationRequest);

 

     virtual bool MakeRequestedAllocationsLost(

@@ -4776,6 +4785,7 @@
         bool upperAddress,

         VmaSuballocationType allocType,

         bool canMakeOtherLost,

+        uint32_t strategy,

         VmaAllocationRequest* pAllocationRequest);

 

     virtual bool MakeRequestedAllocationsLost(

@@ -5036,6 +5046,7 @@
         VmaAllocationCreateFlags allocFlags,

         void* pUserData,

         VmaSuballocationType suballocType,

+        uint32_t strategy,

         VmaAllocation* pAllocation);

 

     VkResult CreateBlock(VkDeviceSize blockSize, size_t* pNewBlockIndex);

@@ -6576,16 +6587,6 @@
 

 #endif // #if VMA_STATS_STRING_ENABLED

 

-/*

-How many suitable free suballocations to analyze before choosing best one.

-- Set to 1 to use First-Fit algorithm - first suitable free suballocation will

-  be chosen.

-- Set to UINT32_MAX to use Best-Fit/Worst-Fit algorithm - all suitable free

-  suballocations will be analized and best one will be chosen.

-- Any other value is also acceptable.

-*/

-//static const uint32_t MAX_SUITABLE_SUBALLOCATIONS_TO_CHECK = 8;

-

 bool VmaBlockMetadata_Generic::CreateAllocationRequest(

     uint32_t currentFrameIndex,

     uint32_t frameInUseCount,

@@ -6595,6 +6596,7 @@
     bool upperAddress,

     VmaSuballocationType allocType,

     bool canMakeOtherLost,

+    uint32_t strategy,

     VmaAllocationRequest* pAllocationRequest)

 {

     VMA_ASSERT(allocSize > 0);

@@ -6604,7 +6606,8 @@
     VMA_HEAVY_ASSERT(Validate());

 

     // There is not enough total free space in this block to fullfill the request: Early return.

-    if(canMakeOtherLost == false && m_SumFreeSize < allocSize + 2 * VMA_DEBUG_MARGIN)

+    if(canMakeOtherLost == false &&

+        m_SumFreeSize < allocSize + 2 * VMA_DEBUG_MARGIN)

     {

         return false;

     }

@@ -6613,7 +6616,7 @@
     const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();

     if(freeSuballocCount > 0)

     {

-        if(VMA_BEST_FIT)

+        if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT)

         {

             // Find first free suballocation with size not less than allocSize + 2 * VMA_DEBUG_MARGIN.

             VmaSuballocationList::iterator* const it = VmaBinaryFindFirstNotLess(

@@ -6643,7 +6646,7 @@
                 }

             }

         }

-        else

+        else // WORST_FIT, FIRST_FIT

         {

             // Search staring from biggest suballocations.

             for(size_t index = freeSuballocCount; index--; )

@@ -6700,7 +6703,8 @@
                 {

                     tmpAllocRequest.item = suballocIt;

 

-                    if(tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost())

+                    if(tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost() ||

+                        strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT)

                     {

                         *pAllocationRequest = tmpAllocRequest;

                     }

@@ -8306,6 +8310,7 @@
     bool upperAddress,

     VmaSuballocationType allocType,

     bool canMakeOtherLost,

+    uint32_t strategy,

     VmaAllocationRequest* pAllocationRequest)

 {

     VMA_ASSERT(allocSize > 0);

@@ -9444,6 +9449,10 @@
     const bool canCreateNewBlock =

         ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) &&

         (m_Blocks.size() < m_MaxBlockCount);

+    uint32_t strategy = createInfo.flags & (

+        VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT |

+        VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT |

+        VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT);

 

     // If linearAlgorithm is used, canMakeOtherLost is available only when used as ring buffer.

     // Which in turn is available only when maxBlockCount = 1.

@@ -9459,6 +9468,20 @@
         return VK_ERROR_FEATURE_NOT_PRESENT;

     }

 

+    // Validate strategy.

+    switch(strategy)

+    {

+    case 0:

+        strategy = VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT;

+        break;

+    case VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT:

+    case VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT:

+    case VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT:

+        break;

+    default:

+        return VK_ERROR_FEATURE_NOT_PRESENT;

+    }

+

     // Early reject: requested allocation size is larger that maximum block size for this block vector.

     if(size + 2 * VMA_DEBUG_MARGIN > m_PreferredBlockSize)

     {

@@ -9494,6 +9517,7 @@
                     allocFlagsCopy,

                     createInfo.pUserData,

                     suballocType,

+                    strategy,

                     pAllocation);

                 if(res == VK_SUCCESS)

                 {

@@ -9504,25 +9528,54 @@
         }

         else

         {

-            // Forward order in m_Blocks - prefer blocks with smallest amount of free space.

-            for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )

+            if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT)

             {

-                VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];

-                VMA_ASSERT(pCurrBlock);

-                VkResult res = AllocateFromBlock(

-                    pCurrBlock,

-                    hCurrentPool,

-                    currentFrameIndex,

-                    size,

-                    alignment,

-                    allocFlagsCopy,

-                    createInfo.pUserData,

-                    suballocType,

-                    pAllocation);

-                if(res == VK_SUCCESS)

+                // Forward order in m_Blocks - prefer blocks with smallest amount of free space.

+                for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )

                 {

-                    VMA_DEBUG_LOG("    Returned from existing block #%u", (uint32_t)blockIndex);

-                    return VK_SUCCESS;

+                    VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];

+                    VMA_ASSERT(pCurrBlock);

+                    VkResult res = AllocateFromBlock(

+                        pCurrBlock,

+                        hCurrentPool,

+                        currentFrameIndex,

+                        size,

+                        alignment,

+                        allocFlagsCopy,

+                        createInfo.pUserData,

+                        suballocType,

+                        strategy,

+                        pAllocation);

+                    if(res == VK_SUCCESS)

+                    {

+                        VMA_DEBUG_LOG("    Returned from existing block #%u", (uint32_t)blockIndex);

+                        return VK_SUCCESS;

+                    }

+                }

+            }

+            else // WORST_FIT, FIRST_FIT

+            {

+                // Backward order in m_Blocks - prefer blocks with largest amount of free space.

+                for(size_t blockIndex = m_Blocks.size(); blockIndex--; )

+                {

+                    VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];

+                    VMA_ASSERT(pCurrBlock);

+                    VkResult res = AllocateFromBlock(

+                        pCurrBlock,

+                        hCurrentPool,

+                        currentFrameIndex,

+                        size,

+                        alignment,

+                        allocFlagsCopy,

+                        createInfo.pUserData,

+                        suballocType,

+                        strategy,

+                        pAllocation);

+                    if(res == VK_SUCCESS)

+                    {

+                        VMA_DEBUG_LOG("    Returned from existing block #%u", (uint32_t)blockIndex);

+                        return VK_SUCCESS;

+                    }

                 }

             }

         }

@@ -9589,6 +9642,7 @@
                     allocFlagsCopy,

                     createInfo.pUserData,

                     suballocType,

+                    strategy,

                     pAllocation);

                 if(res == VK_SUCCESS)

                 {

@@ -9615,34 +9669,76 @@
             VkDeviceSize bestRequestCost = VK_WHOLE_SIZE;

 

             // 1. Search existing allocations.

-            // Forward order in m_Blocks - prefer blocks with smallest amount of free space.

-            for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )

+            if(strategy == VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT)

             {

-                VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];

-                VMA_ASSERT(pCurrBlock);

-                VmaAllocationRequest currRequest = {};

-                if(pCurrBlock->m_pMetadata->CreateAllocationRequest(

-                    currentFrameIndex,

-                    m_FrameInUseCount,

-                    m_BufferImageGranularity,

-                    size,

-                    alignment,

-                    (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,

-                    suballocType,

-                    canMakeOtherLost,

-                    &currRequest))

+                // Forward order in m_Blocks - prefer blocks with smallest amount of free space.

+                for(size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )

                 {

-                    const VkDeviceSize currRequestCost = currRequest.CalcCost();

-                    if(pBestRequestBlock == VMA_NULL ||

-                        currRequestCost < bestRequestCost)

+                    VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];

+                    VMA_ASSERT(pCurrBlock);

+                    VmaAllocationRequest currRequest = {};

+                    if(pCurrBlock->m_pMetadata->CreateAllocationRequest(

+                        currentFrameIndex,

+                        m_FrameInUseCount,

+                        m_BufferImageGranularity,

+                        size,

+                        alignment,

+                        (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,

+                        suballocType,

+                        canMakeOtherLost,

+                        strategy,

+                        &currRequest))

                     {

-                        pBestRequestBlock = pCurrBlock;

-                        bestRequest = currRequest;

-                        bestRequestCost = currRequestCost;

-

-                        if(bestRequestCost == 0)

+                        const VkDeviceSize currRequestCost = currRequest.CalcCost();

+                        if(pBestRequestBlock == VMA_NULL ||

+                            currRequestCost < bestRequestCost)

                         {

-                            break;

+                            pBestRequestBlock = pCurrBlock;

+                            bestRequest = currRequest;

+                            bestRequestCost = currRequestCost;

+

+                            if(bestRequestCost == 0)

+                            {

+                                break;

+                            }

+                        }

+                    }

+                }

+            }

+            else // WORST_FIT, FIRST_FIT

+            {

+                // Backward order in m_Blocks - prefer blocks with largest amount of free space.

+                for(size_t blockIndex = m_Blocks.size(); blockIndex--; )

+                {

+                    VmaDeviceMemoryBlock* const pCurrBlock = m_Blocks[blockIndex];

+                    VMA_ASSERT(pCurrBlock);

+                    VmaAllocationRequest currRequest = {};

+                    if(pCurrBlock->m_pMetadata->CreateAllocationRequest(

+                        currentFrameIndex,

+                        m_FrameInUseCount,

+                        m_BufferImageGranularity,

+                        size,

+                        alignment,

+                        (createInfo.flags & VMA_ALLOCATION_CREATE_UPPER_ADDRESS_BIT) != 0,

+                        suballocType,

+                        canMakeOtherLost,

+                        strategy,

+                        &currRequest))

+                    {

+                        const VkDeviceSize currRequestCost = currRequest.CalcCost();

+                        if(pBestRequestBlock == VMA_NULL ||

+                            currRequestCost < bestRequestCost ||

+                            strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT)

+                        {

+                            pBestRequestBlock = pCurrBlock;

+                            bestRequest = currRequest;

+                            bestRequestCost = currRequestCost;

+

+                            if(bestRequestCost == 0 ||

+                                strategy == VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT)

+                            {

+                                break;

+                            }

                         }

                     }

                 }

@@ -9835,6 +9931,7 @@
     VmaAllocationCreateFlags allocFlags,

     void* pUserData,

     VmaSuballocationType suballocType,

+    uint32_t strategy,

     VmaAllocation* pAllocation)

 {

     VMA_ASSERT((allocFlags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) == 0);

@@ -9852,6 +9949,7 @@
         isUpperAddress,

         suballocType,

         false, // canMakeOtherLost

+        strategy,

         &currRequest))

     {

         // Allocate from pCurrBlock.

@@ -10262,6 +10360,7 @@
                 false, // upperAddress

                 suballocType,

                 false, // canMakeOtherLost

+                VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT,

                 &dstAllocRequest) &&

             MoveMakesSense(

                 dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset))