TEMP started coding buddy algorithm.
diff --git a/src/vk_mem_alloc.h b/src/vk_mem_alloc.h
index 758e9f6..299b866 100644
--- a/src/vk_mem_alloc.h
+++ b/src/vk_mem_alloc.h
@@ -1836,6 +1836,13 @@
     */

     VMA_ALLOCATION_CREATE_STRATEGY_MIN_FRAGMENTATION_BIT = VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT,

 

+    /** A bit mask to extract only `STRATEGY` bits from entire set of flags.

+    */

+    VMA_ALLOCATION_CREATE_STRATEGY_MASK =

+        VMA_ALLOCATION_CREATE_STRATEGY_BEST_FIT_BIT |

+        VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT |

+        VMA_ALLOCATION_CREATE_STRATEGY_FIRST_FIT_BIT,

+

     VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF

 } VmaAllocationCreateFlagBits;

 typedef VkFlags VmaAllocationCreateFlags;

@@ -1977,6 +1984,15 @@
 */

     VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT = 0x00000004,

 

+    /** TODO */

+    VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT = 0x00000008,

+

+    /** Bit mask to extract only `ALGORITHM` bits from entire set of flags.

+    */

+    VMA_POOL_CREATE_ALGORITHM_MASK =

+        VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT |

+        VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT,

+

     VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF

 } VmaPoolCreateFlagBits;

 typedef VkFlags VmaPoolCreateFlags;

@@ -2940,16 +2956,45 @@
 

 // Division with mathematical rounding to nearest number.

 template <typename T>

-inline T VmaRoundDiv(T x, T y)

+static inline T VmaRoundDiv(T x, T y)

 {

 	return (x + (y / (T)2)) / y;

 }

 

+// Returns smallest power of 2 greater or equal to v.

+static inline uint32_t VmaNextPow2(uint32_t v)

+{

+	v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v;

+}

+// Returns biggest power of 2 less or equal to v.

+/*

+static inline uint32_t VmaPrevPow2(uint32_t v)

+{

+

+}

+*/

+

 static inline bool VmaStrIsEmpty(const char* pStr)

 {

     return pStr == VMA_NULL || *pStr == '\0';

 }

 

+static const char* VmaAlgorithmToStr(uint32_t algorithm)

+{

+    switch(algorithm)

+    {

+    case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT:

+        return "Linear";

+    case VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT:

+        return "Buddy";

+    case 0:

+        return "Default";

+    default:

+        VMA_ASSERT(0);

+        return "";

+    }

+}

+

 #ifndef VMA_SORT

 

 template<typename Iterator, typename Compare>

@@ -4869,6 +4914,96 @@
     void CleanupAfterFree();

 };

 

+class VmaBlockMetadata_Buddy : public VmaBlockMetadata

+{

+    VMA_CLASS_NO_COPY(VmaBlockMetadata_Buddy)

+public:

+    VmaBlockMetadata_Buddy(VmaAllocator hAllocator);

+    virtual ~VmaBlockMetadata_Buddy();

+    virtual void Init(VkDeviceSize size);

+

+    virtual bool Validate() const;

+    virtual size_t GetAllocationCount() const;

+    virtual VkDeviceSize GetSumFreeSize() const;

+    virtual VkDeviceSize GetUnusedRangeSizeMax() const;

+    virtual bool IsEmpty() const;

+

+    virtual void CalcAllocationStatInfo(VmaStatInfo& outInfo) const;

+    virtual void AddPoolStats(VmaPoolStats& inoutStats) const;

+

+#if VMA_STATS_STRING_ENABLED

+    virtual void PrintDetailedMap(class VmaJsonWriter& json) const;

+#endif

+

+    virtual bool CreateAllocationRequest(

+        uint32_t currentFrameIndex,

+        uint32_t frameInUseCount,

+        VkDeviceSize bufferImageGranularity,

+        VkDeviceSize allocSize,

+        VkDeviceSize allocAlignment,

+        bool upperAddress,

+        VmaSuballocationType allocType,

+        bool canMakeOtherLost,

+        uint32_t strategy,

+        VmaAllocationRequest* pAllocationRequest);

+

+    virtual bool MakeRequestedAllocationsLost(

+        uint32_t currentFrameIndex,

+        uint32_t frameInUseCount,

+        VmaAllocationRequest* pAllocationRequest);

+

+    virtual uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);

+

+    virtual VkResult CheckCorruption(const void* pBlockData);

+

+    virtual void Alloc(

+        const VmaAllocationRequest& request,

+        VmaSuballocationType type,

+        VkDeviceSize allocSize,

+        bool upperAddress,

+        VmaAllocation hAllocation);

+

+    virtual void Free(const VmaAllocation allocation);

+    virtual void FreeAtOffset(VkDeviceSize offset);

+

+private:

+    static const size_t MAX_LEVELS = 30;

+

+    struct Node

+    {

+        enum TYPE

+        {

+            TYPE_FREE,

+            TYPE_ALLOCATION,

+            TYPE_SPLIT,

+            TYPE_COUNT

+        } type;

+        Node* parent;

+        Node* buddy;

+        union

+        {

+            struct

+            {

+                Node* nextFree;

+            } free;

+            struct

+            {

+                VmaAllocation alloc;

+            } allocation;

+            struct

+            {

+                Node* leftChild;

+            } split;

+        };

+    };

+

+    Node* m_Root;

+    Node* m_FreeList[MAX_LEVELS];

+

+    void DeleteNode(Node* node);

+    bool ValidateNode(const Node* parent, const Node* curr) const;

+};

+

 /*

 Represents a single block of device memory (`VkDeviceMemory`) with all the

 data about its regions (aka suballocations, #VmaAllocation), assigned and free.

@@ -4896,7 +5031,7 @@
         VkDeviceMemory newMemory,

         VkDeviceSize newSize,

         uint32_t id,

-        bool linearAlgorithm);

+        uint32_t algorithm);

     // Always call before destruction.

     void Destroy(VmaAllocator allocator);

     

@@ -4968,7 +5103,7 @@
         uint32_t frameInUseCount,

         bool isCustomPool,

         bool explicitBlockSize,

-        bool linearAlgorithm);

+        uint32_t algorithm);

     ~VmaBlockVector();

 

     VkResult CreateMinBlocks();

@@ -4977,7 +5112,7 @@
     VkDeviceSize GetPreferredBlockSize() const { return m_PreferredBlockSize; }

     VkDeviceSize GetBufferImageGranularity() const { return m_BufferImageGranularity; }

     uint32_t GetFrameInUseCount() const { return m_FrameInUseCount; }

-    bool UsesLinearAlgorithm() const { return m_LinearAlgorithm; }

+    uint32_t GetAlgorithm() const { return m_Algorithm; }

 

     void GetPoolStats(VmaPoolStats* pStats);

 

@@ -5031,7 +5166,7 @@
     const uint32_t m_FrameInUseCount;

     const bool m_IsCustomPool;

     const bool m_ExplicitBlockSize;

-    const bool m_LinearAlgorithm;

+    const uint32_t m_Algorithm;

     bool m_HasEmptyBlock;

     VMA_MUTEX m_Mutex;

     // Incrementally sorted by sumFreeSize, ascending.

@@ -9090,6 +9225,190 @@
 

 

 ////////////////////////////////////////////////////////////////////////////////

+// class VmaBlockMetadata_Buddy

+

+VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy(VmaAllocator hAllocator) :

+    m_Root(VMA_NULL)

+{

+    memset(m_FreeList, 0, sizeof(m_FreeList));

+}

+

+VmaBlockMetadata_Buddy::~VmaBlockMetadata_Buddy()

+{

+    DeleteNode(m_Root);

+}

+

+void VmaBlockMetadata_Buddy::Init(VkDeviceSize size)

+{

+    VmaBlockMetadata::Init(size);

+

+    Node* rootNode = new Node();

+    rootNode->type = Node::TYPE_FREE;

+    rootNode->parent = VMA_NULL;

+    rootNode->buddy = VMA_NULL;

+    rootNode->free.nextFree = VMA_NULL;

+

+    m_FreeList[0] = rootNode;

+}

+

+bool VmaBlockMetadata_Buddy::Validate() const

+{

+    if(!ValidateNode(VMA_NULL, m_Root))

+    {

+        return false;

+    }

+

+    return true;

+}

+

+size_t VmaBlockMetadata_Buddy::GetAllocationCount() const

+{

+    return 0; // TODO

+}

+

+VkDeviceSize VmaBlockMetadata_Buddy::GetSumFreeSize() const

+{

+    return 0; // TODO

+}

+

+VkDeviceSize VmaBlockMetadata_Buddy::VmaBlockMetadata_Buddy::GetUnusedRangeSizeMax() const

+{

+    return 0; // TODO

+}

+

+bool VmaBlockMetadata_Buddy::IsEmpty() const

+{

+    return m_Root->type == Node::TYPE_FREE;

+}

+

+void VmaBlockMetadata_Buddy::CalcAllocationStatInfo(VmaStatInfo& outInfo) const

+{

+    // TODO

+}

+

+void VmaBlockMetadata_Buddy::AddPoolStats(VmaPoolStats& inoutStats) const

+{

+    // TODO

+}

+

+#if VMA_STATS_STRING_ENABLED

+

+void VmaBlockMetadata_Buddy::PrintDetailedMap(class VmaJsonWriter& json) const

+{

+    // TODO

+}

+

+#endif // #if VMA_STATS_STRING_ENABLED

+

+bool VmaBlockMetadata_Buddy::CreateAllocationRequest(

+    uint32_t currentFrameIndex,

+    uint32_t frameInUseCount,

+    VkDeviceSize bufferImageGranularity,

+    VkDeviceSize allocSize,

+    VkDeviceSize allocAlignment,

+    bool upperAddress,

+    VmaSuballocationType allocType,

+    bool canMakeOtherLost,

+    uint32_t strategy,

+    VmaAllocationRequest* pAllocationRequest)

+{

+    // TODO

+    return false;

+}

+

+bool VmaBlockMetadata_Buddy::MakeRequestedAllocationsLost(

+    uint32_t currentFrameIndex,

+    uint32_t frameInUseCount,

+    VmaAllocationRequest* pAllocationRequest)

+{

+    return false; // TODO

+}

+

+uint32_t VmaBlockMetadata_Buddy::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)

+{

+    return 0; // TODO

+}

+

+VkResult VmaBlockMetadata_Buddy::CheckCorruption(const void* pBlockData)

+{

+    return VK_SUCCESS; // TODO

+}

+

+void VmaBlockMetadata_Buddy::Alloc(

+    const VmaAllocationRequest& request,

+    VmaSuballocationType type,

+    VkDeviceSize allocSize,

+    bool upperAddress,

+    VmaAllocation hAllocation)

+{

+}

+

+void VmaBlockMetadata_Buddy::Free(const VmaAllocation allocation)

+{

+}

+

+void VmaBlockMetadata_Buddy::FreeAtOffset(VkDeviceSize offset)

+{

+}

+

+void VmaBlockMetadata_Buddy::DeleteNode(Node* node)

+{

+    if(node->type == Node::TYPE_SPLIT)

+    {

+        DeleteNode(node->split.leftChild->buddy);

+        DeleteNode(node->split.leftChild);

+    }

+

+    delete node;

+}

+

+bool VmaBlockMetadata_Buddy::ValidateNode(const Node* parent, const Node* curr) const

+{

+    if(curr->parent != parent)

+    {

+        return false;

+    }

+    if((curr->buddy == VMA_NULL) != (parent == VMA_NULL))

+    {

+        return false;

+    }

+    if(curr->buddy != VMA_NULL && curr->buddy->buddy != curr)

+    {

+        return false;

+    }

+    switch(curr->type)

+    {

+    case Node::TYPE_FREE:

+        break;

+    case Node::TYPE_ALLOCATION:

+        if(curr->allocation.alloc == VK_NULL_HANDLE)

+        {

+            return false;

+        }

+        break;

+    case Node::TYPE_SPLIT:

+        if(curr->split.leftChild == VMA_NULL)

+        {

+            return false;

+        }

+        if(!ValidateNode(curr, curr->split.leftChild))

+        {

+            return false;

+        }

+        if(!ValidateNode(curr, curr->split.leftChild->buddy))

+        {

+            return false;

+        }

+        break;

+    default:

+        return false;

+    }

+

+    return true;

+}

+

+

+////////////////////////////////////////////////////////////////////////////////

 // class VmaDeviceMemoryBlock

 

 VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) :

@@ -9108,7 +9427,7 @@
     VkDeviceMemory newMemory,

     VkDeviceSize newSize,

     uint32_t id,

-    bool linearAlgorithm)

+    uint32_t algorithm)

 {

     VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);

 

@@ -9116,12 +9435,18 @@
     m_Id = id;

     m_hMemory = newMemory;

 

-    if(linearAlgorithm)

+    switch(algorithm)

     {

+    case VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT:

         m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Linear)(hAllocator);

-    }

-    else

-    {

+        break;

+    case VMA_POOL_CREATE_BUDDY_ALGORITHM_BIT:

+        m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Buddy)(hAllocator);

+        break;

+    default:

+        VMA_ASSERT(0);

+        // Fall-through.

+    case 0:

         m_pMetadata = vma_new(hAllocator, VmaBlockMetadata_Generic)(hAllocator);

     }

     m_pMetadata->Init(newSize);

@@ -9351,7 +9676,7 @@
         createInfo.frameInUseCount,

         true, // isCustomPool

         createInfo.blockSize != 0, // explicitBlockSize

-        (createInfo.flags & VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) != 0), // linearAlgorithm

+        createInfo.flags & VMA_POOL_CREATE_ALGORITHM_MASK), // algorithm

     m_Id(0)

 {

 }

@@ -9374,7 +9699,7 @@
     uint32_t frameInUseCount,

     bool isCustomPool,

     bool explicitBlockSize,

-    bool linearAlgorithm) :

+    uint32_t algorithm) :

     m_hAllocator(hAllocator),

     m_MemoryTypeIndex(memoryTypeIndex),

     m_PreferredBlockSize(preferredBlockSize),

@@ -9384,7 +9709,7 @@
     m_FrameInUseCount(frameInUseCount),

     m_IsCustomPool(isCustomPool),

     m_ExplicitBlockSize(explicitBlockSize),

-    m_LinearAlgorithm(linearAlgorithm),

+    m_Algorithm(algorithm),

     m_Blocks(VmaStlAllocator<VmaDeviceMemoryBlock*>(hAllocator->GetAllocationCallbacks())),

     m_HasEmptyBlock(false),

     m_pDefragmentator(VMA_NULL),

@@ -9464,21 +9789,18 @@
     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);

+    uint32_t strategy = createInfo.flags & VMA_ALLOCATION_CREATE_STRATEGY_MASK;

 

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

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

-    if(m_LinearAlgorithm && m_MaxBlockCount > 1)

+    if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT && m_MaxBlockCount > 1)

     {

         canMakeOtherLost = false;

     }

 

     // Upper address can only be used with linear allocator and within single memory block.

     if(isUpperAddress &&

-        (!m_LinearAlgorithm || m_MaxBlockCount > 1))

+        (m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT || m_MaxBlockCount > 1))

     {

         return VK_ERROR_FEATURE_NOT_PRESENT;

     }

@@ -9516,7 +9838,7 @@
         VmaAllocationCreateFlags allocFlagsCopy = createInfo.flags;

         allocFlagsCopy &= ~VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT;

 

-        if(m_LinearAlgorithm)

+        if(m_Algorithm == VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)

         {

             // Use only last block.

             if(!m_Blocks.empty())

@@ -9923,7 +10245,7 @@
 

 void VmaBlockVector::IncrementallySortBlocks()

 {

-    if(!m_LinearAlgorithm)

+    if(m_Algorithm != VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT)

     {

         // Bubble sort only until first swap.

         for(size_t i = 1; i < m_Blocks.size(); ++i)

@@ -10034,7 +10356,7 @@
         mem,

         allocInfo.allocationSize,

         m_NextBlockId++,

-        m_LinearAlgorithm);

+        m_Algorithm);

 

     m_Blocks.push_back(pBlock);

     if(pNewBlockIndex != VMA_NULL)

@@ -10083,10 +10405,10 @@
             json.WriteNumber(m_FrameInUseCount);

         }

 

-        if(m_LinearAlgorithm)

+        if(m_Algorithm != 0)

         {

-            json.WriteString("LinearAlgorithm");

-            json.WriteBool(true);

+            json.WriteString("Algorithm");

+            json.WriteString(VmaAlgorithmToStr(m_Algorithm));

         }

     }

     else

@@ -10267,7 +10589,7 @@
     m_Allocations(VmaStlAllocator<AllocationInfo>(hAllocator->GetAllocationCallbacks())),

     m_Blocks(VmaStlAllocator<BlockInfo*>(hAllocator->GetAllocationCallbacks()))

 {

-    VMA_ASSERT(!pBlockVector->UsesLinearAlgorithm());

+    VMA_ASSERT(pBlockVector->GetAlgorithm() == 0);

 }

 

 VmaDefragmentator::~VmaDefragmentator()

@@ -11782,7 +12104,7 @@
             if(hAllocPool != VK_NULL_HANDLE)

             {

                 // Pools with linear algorithm are not defragmented.

-                if(!hAllocPool->m_BlockVector.UsesLinearAlgorithm())

+                if(hAllocPool->m_BlockVector.GetAlgorithm() == 0)

                 {

                     pAllocBlockVector = &hAllocPool->m_BlockVector;

                 }

@@ -11988,8 +12310,6 @@
 {

     VMA_DEBUG_LOG("  CreatePool: MemoryTypeIndex=%u, flags=%u", pCreateInfo->memoryTypeIndex, pCreateInfo->flags);

 

-    const bool isLinearAlgorithm = (pCreateInfo->flags & VMA_POOL_CREATE_LINEAR_ALGORITHM_BIT) != 0;

-

     VmaPoolCreateInfo newCreateInfo = *pCreateInfo;

 

     if(newCreateInfo.maxBlockCount == 0)