25 #ifndef AMD_VULKAN_MEMORY_ALLOCATOR_H 26 #define AMD_VULKAN_MEMORY_ALLOCATOR_H 738 #include <ThirdParty/Vulkan/Include/vulkan/vulkan.h> 740 VK_DEFINE_HANDLE(VmaAllocator)
742 typedef
void (VKAPI_PTR *PFN_vmaAllocateDeviceMemoryFunction)(
744 VmaAllocator allocator,
746 VkDeviceMemory memory,
749 typedef
void (VKAPI_PTR *PFN_vmaFreeDeviceMemoryFunction)(
750 VmaAllocator allocator,
752 VkDeviceMemory memory,
762 typedef struct VmaDeviceMemoryCallbacks {
764 PFN_vmaAllocateDeviceMemoryFunction pfnAllocate;
766 PFN_vmaFreeDeviceMemoryFunction pfnFree;
767 } VmaDeviceMemoryCallbacks;
770 typedef enum VmaAllocatorCreateFlagBits {
775 VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT = 0x00000001,
797 VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT = 0x00000002,
799 VMA_ALLOCATOR_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
800 } VmaAllocatorCreateFlagBits;
801 typedef VkFlags VmaAllocatorCreateFlags;
807 typedef struct VmaVulkanFunctions {
808 PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
809 PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
810 PFN_vkAllocateMemory vkAllocateMemory;
811 PFN_vkFreeMemory vkFreeMemory;
812 PFN_vkMapMemory vkMapMemory;
813 PFN_vkUnmapMemory vkUnmapMemory;
814 PFN_vkBindBufferMemory vkBindBufferMemory;
815 PFN_vkBindImageMemory vkBindImageMemory;
816 PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
817 PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
818 PFN_vkCreateBuffer vkCreateBuffer;
819 PFN_vkDestroyBuffer vkDestroyBuffer;
820 PFN_vkCreateImage vkCreateImage;
821 PFN_vkDestroyImage vkDestroyImage;
822 PFN_vkGetBufferMemoryRequirements2KHR vkGetBufferMemoryRequirements2KHR;
823 PFN_vkGetImageMemoryRequirements2KHR vkGetImageMemoryRequirements2KHR;
824 } VmaVulkanFunctions;
827 typedef struct VmaAllocatorCreateInfo
830 VmaAllocatorCreateFlags flags;
833 VkPhysicalDevice physicalDevice;
839 VkDeviceSize preferredLargeHeapBlockSize;
842 const VkAllocationCallbacks* pAllocationCallbacks;
845 const VmaDeviceMemoryCallbacks* pDeviceMemoryCallbacks;
859 uint32_t frameInUseCount;
883 const VkDeviceSize* pHeapSizeLimit;
895 const VmaVulkanFunctions* pVulkanFunctions;
896 } VmaAllocatorCreateInfo;
899 VkResult vmaCreateAllocator(
900 const VmaAllocatorCreateInfo* pCreateInfo,
901 VmaAllocator* pAllocator);
904 void vmaDestroyAllocator(
905 VmaAllocator allocator);
911 void vmaGetPhysicalDeviceProperties(
912 VmaAllocator allocator,
913 const VkPhysicalDeviceProperties** ppPhysicalDeviceProperties);
919 void vmaGetMemoryProperties(
920 VmaAllocator allocator,
921 const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties);
929 void vmaGetMemoryTypeProperties(
930 VmaAllocator allocator,
931 uint32_t memoryTypeIndex,
932 VkMemoryPropertyFlags* pFlags);
942 void vmaSetCurrentFrameIndex(
943 VmaAllocator allocator,
944 uint32_t frameIndex);
948 typedef struct VmaStatInfo
953 uint32_t allocationCount;
955 uint32_t unusedRangeCount;
957 VkDeviceSize usedBytes;
959 VkDeviceSize unusedBytes;
960 VkDeviceSize allocationSizeMin, allocationSizeAvg, allocationSizeMax;
961 VkDeviceSize unusedRangeSizeMin, unusedRangeSizeAvg, unusedRangeSizeMax;
965 typedef struct VmaStats
967 VmaStatInfo memoryType[VK_MAX_MEMORY_TYPES];
968 VmaStatInfo memoryHeap[VK_MAX_MEMORY_HEAPS];
973 void vmaCalculateStats(
974 VmaAllocator allocator,
977 #define VMA_STATS_STRING_ENABLED 1 979 #if VMA_STATS_STRING_ENABLED 984 void vmaBuildStatsString(
985 VmaAllocator allocator,
986 char** ppStatsString,
987 VkBool32 detailedMap);
989 void vmaFreeStatsString(
990 VmaAllocator allocator,
993 #endif // #if VMA_STATS_STRING_ENABLED 995 VK_DEFINE_HANDLE(VmaPool)
997 typedef enum VmaMemoryUsage
1002 VMA_MEMORY_USAGE_UNKNOWN = 0,
1019 VMA_MEMORY_USAGE_GPU_ONLY = 1,
1029 VMA_MEMORY_USAGE_CPU_ONLY = 2,
1036 VMA_MEMORY_USAGE_CPU_TO_GPU = 3,
1045 VMA_MEMORY_USAGE_GPU_TO_CPU = 4,
1046 VMA_MEMORY_USAGE_MAX_ENUM = 0x7FFFFFFF
1050 typedef enum VmaAllocationCreateFlagBits {
1062 VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT = 0x00000001,
1073 VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT = 0x00000002,
1086 VMA_ALLOCATION_CREATE_MAPPED_BIT = 0x00000004,
1099 VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT = 0x00000008,
1106 VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT = 0x00000010,
1112 VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT = 0x00000020,
1114 VMA_ALLOCATION_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
1115 } VmaAllocationCreateFlagBits;
1116 typedef VkFlags VmaAllocationCreateFlags;
1118 typedef struct VmaAllocationCreateInfo
1121 VmaAllocationCreateFlags flags;
1127 VmaMemoryUsage usage;
1132 VkMemoryPropertyFlags requiredFlags;
1137 VkMemoryPropertyFlags preferredFlags;
1145 uint32_t memoryTypeBits;
1159 } VmaAllocationCreateInfo;
1175 VkResult vmaFindMemoryTypeIndex(
1176 VmaAllocator allocator,
1177 uint32_t memoryTypeBits,
1178 const VmaAllocationCreateInfo* pAllocationCreateInfo,
1179 uint32_t* pMemoryTypeIndex);
1182 typedef enum VmaPoolCreateFlagBits {
1200 VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT = 0x00000002,
1202 VMA_POOL_CREATE_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
1203 } VmaPoolCreateFlagBits;
1204 typedef VkFlags VmaPoolCreateFlags;
1208 typedef struct VmaPoolCreateInfo {
1211 uint32_t memoryTypeIndex;
1214 VmaPoolCreateFlags flags;
1219 VkDeviceSize blockSize;
1224 size_t minBlockCount;
1232 size_t maxBlockCount;
1246 uint32_t frameInUseCount;
1247 } VmaPoolCreateInfo;
1251 typedef struct VmaPoolStats {
1257 VkDeviceSize unusedSize;
1260 size_t allocationCount;
1263 size_t unusedRangeCount;
1270 VkDeviceSize unusedRangeSizeMax;
1279 VkResult vmaCreatePool(
1280 VmaAllocator allocator,
1281 const VmaPoolCreateInfo* pCreateInfo,
1286 void vmaDestroyPool(
1287 VmaAllocator allocator,
1296 void vmaGetPoolStats(
1297 VmaAllocator allocator,
1299 VmaPoolStats* pPoolStats);
1307 void vmaMakePoolAllocationsLost(
1308 VmaAllocator allocator,
1310 size_t* pLostAllocationCount);
1312 VK_DEFINE_HANDLE(VmaAllocation)
1316 typedef struct VmaAllocationInfo {
1321 uint32_t memoryType;
1330 VkDeviceMemory deviceMemory;
1335 VkDeviceSize offset;
1355 } VmaAllocationInfo;
1367 VkResult vmaAllocateMemory(
1368 VmaAllocator allocator,
1369 const VkMemoryRequirements* pVkMemoryRequirements,
1370 const VmaAllocationCreateInfo* pCreateInfo,
1371 VmaAllocation* pAllocation,
1372 VmaAllocationInfo* pAllocationInfo);
1380 VkResult vmaAllocateMemoryForBuffer(
1381 VmaAllocator allocator,
1383 const VmaAllocationCreateInfo* pCreateInfo,
1384 VmaAllocation* pAllocation,
1385 VmaAllocationInfo* pAllocationInfo);
1388 VkResult vmaAllocateMemoryForImage(
1389 VmaAllocator allocator,
1391 const VmaAllocationCreateInfo* pCreateInfo,
1392 VmaAllocation* pAllocation,
1393 VmaAllocationInfo* pAllocationInfo);
1397 VmaAllocator allocator,
1398 VmaAllocation allocation);
1401 void vmaGetAllocationInfo(
1402 VmaAllocator allocator,
1403 VmaAllocation allocation,
1404 VmaAllocationInfo* pAllocationInfo);
1419 void vmaSetAllocationUserData(
1420 VmaAllocator allocator,
1421 VmaAllocation allocation,
1434 void vmaCreateLostAllocation(
1435 VmaAllocator allocator,
1436 VmaAllocation* pAllocation);
1472 VkResult vmaMapMemory(
1473 VmaAllocator allocator,
1474 VmaAllocation allocation,
1481 void vmaUnmapMemory(
1482 VmaAllocator allocator,
1483 VmaAllocation allocation);
1486 typedef struct VmaDefragmentationInfo {
1491 VkDeviceSize maxBytesToMove;
1496 uint32_t maxAllocationsToMove;
1497 } VmaDefragmentationInfo;
1500 typedef struct VmaDefragmentationStats {
1502 VkDeviceSize bytesMoved;
1504 VkDeviceSize bytesFreed;
1506 uint32_t allocationsMoved;
1508 uint32_t deviceMemoryBlocksFreed;
1509 } VmaDefragmentationStats;
1587 VkResult vmaDefragment(
1588 VmaAllocator allocator,
1589 VmaAllocation* pAllocations,
1590 size_t allocationCount,
1591 VkBool32* pAllocationsChanged,
1592 const VmaDefragmentationInfo *pDefragmentationInfo,
1593 VmaDefragmentationStats* pDefragmentationStats);
1621 VkResult vmaCreateBuffer(
1622 VmaAllocator allocator,
1623 const VkBufferCreateInfo* pBufferCreateInfo,
1624 const VmaAllocationCreateInfo* pAllocationCreateInfo,
1626 VmaAllocation* pAllocation,
1627 VmaAllocationInfo* pAllocationInfo);
1640 void vmaDestroyBuffer(
1641 VmaAllocator allocator,
1643 VmaAllocation allocation);
1646 VkResult vmaCreateImage(
1647 VmaAllocator allocator,
1648 const VkImageCreateInfo* pImageCreateInfo,
1649 const VmaAllocationCreateInfo* pAllocationCreateInfo,
1651 VmaAllocation* pAllocation,
1652 VmaAllocationInfo* pAllocationInfo);
1665 void vmaDestroyImage(
1666 VmaAllocator allocator,
1668 VmaAllocation allocation);
1674 #endif // AMD_VULKAN_MEMORY_ALLOCATOR_H 1677 #ifdef __INTELLISENSE__ 1678 #define VMA_IMPLEMENTATION 1681 #ifdef VMA_IMPLEMENTATION 1682 #undef VMA_IMPLEMENTATION 1704 #if !defined(VMA_STATIC_VULKAN_FUNCTIONS) && !defined(VK_NO_PROTOTYPES) 1705 #define VMA_STATIC_VULKAN_FUNCTIONS 1 1717 #if VMA_USE_STL_CONTAINERS 1718 #define VMA_USE_STL_VECTOR 1 1719 #define VMA_USE_STL_UNORDERED_MAP 1 1720 #define VMA_USE_STL_LIST 1 1723 #if VMA_USE_STL_VECTOR 1727 #if VMA_USE_STL_UNORDERED_MAP 1728 #include <unordered_map> 1731 #if VMA_USE_STL_LIST 1740 #include <algorithm> 1744 #if !defined(_WIN32) && !defined(__APPLE__) 1748 #if defined(__APPLE__) 1750 void *aligned_alloc(
size_t alignment,
size_t size)
1753 posix_memalign(&pointer, alignment, size);
1761 #define VMA_ASSERT(expr) assert(expr) 1763 #define VMA_ASSERT(expr) 1769 #ifndef VMA_HEAVY_ASSERT 1771 #define VMA_HEAVY_ASSERT(expr) //VMA_ASSERT(expr) 1773 #define VMA_HEAVY_ASSERT(expr) 1779 #define VMA_NULL nullptr 1782 #ifndef VMA_ALIGN_OF 1783 #define VMA_ALIGN_OF(type) (__alignof(type)) 1786 #ifndef VMA_SYSTEM_ALIGNED_MALLOC 1788 #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (_aligned_malloc((size), (alignment))) 1790 #define VMA_SYSTEM_ALIGNED_MALLOC(size, alignment) (aligned_alloc((alignment), (size) )) 1794 #ifndef VMA_SYSTEM_FREE 1796 #define VMA_SYSTEM_FREE(ptr) _aligned_free(ptr) 1798 #define VMA_SYSTEM_FREE(ptr) free(ptr) 1803 #define VMA_MIN(v1, v2) (std::min((v1), (v2))) 1807 #define VMA_MAX(v1, v2) (std::max((v1), (v2))) 1811 #define VMA_SWAP(v1, v2) std::swap((v1), (v2)) 1815 #define VMA_SORT(beg, end, cmp) std::sort(beg, end, cmp) 1818 #ifndef VMA_DEBUG_LOG 1819 #define VMA_DEBUG_LOG(format, ...) 1829 #if VMA_STATS_STRING_ENABLED 1830 static inline void VmaUint32ToStr(
char* outStr,
size_t strLen, uint32_t num)
1832 snprintf(outStr, strLen,
"%u", static_cast<unsigned int>(num));
1834 static inline void VmaUint64ToStr(
char* outStr,
size_t strLen, uint64_t num)
1836 snprintf(outStr, strLen,
"%llu", static_cast<unsigned long long>(num));
1838 static inline void VmaPtrToStr(
char* outStr,
size_t strLen,
const void* ptr)
1840 snprintf(outStr, strLen,
"%p", ptr);
1850 void Lock() { m_Mutex.lock(); }
1851 void Unlock() { m_Mutex.unlock(); }
1855 #define VMA_MUTEX VmaMutex 1866 #ifndef VMA_ATOMIC_UINT32 1867 #define VMA_ATOMIC_UINT32 std::atomic<uint32_t> 1870 #ifndef VMA_BEST_FIT 1883 #define VMA_BEST_FIT (1) 1886 #ifndef VMA_DEBUG_ALWAYS_DEDICATED_MEMORY 1891 #define VMA_DEBUG_ALWAYS_DEDICATED_MEMORY (0) 1894 #ifndef VMA_DEBUG_ALIGNMENT 1899 #define VMA_DEBUG_ALIGNMENT (1) 1902 #ifndef VMA_DEBUG_MARGIN 1907 #define VMA_DEBUG_MARGIN (0) 1910 #ifndef VMA_DEBUG_GLOBAL_MUTEX 1915 #define VMA_DEBUG_GLOBAL_MUTEX (0) 1918 #ifndef VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY 1923 #define VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY (1) 1926 #ifndef VMA_SMALL_HEAP_MAX_SIZE 1927 #define VMA_SMALL_HEAP_MAX_SIZE (1024ull * 1024 * 1024) 1931 #ifndef VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE 1932 #define VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE (256ull * 1024 * 1024) 1936 static const uint32_t VMA_FRAME_INDEX_LOST = UINT32_MAX;
1942 static VkAllocationCallbacks VmaEmptyAllocationCallbacks = {
1943 VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL, VMA_NULL };
1946 static inline uint32_t VmaCountBitsSet(uint32_t v)
1948 uint32_t c = v - ((v >> 1) & 0x55555555);
1949 c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
1950 c = ((c >> 4) + c) & 0x0F0F0F0F;
1951 c = ((c >> 8) + c) & 0x00FF00FF;
1952 c = ((c >> 16) + c) & 0x0000FFFF;
1958 template <
typename T>
1959 static inline T VmaAlignUp(T val, T align)
1961 return (val + align - 1) / align * align;
1965 template <
typename T>
1966 inline T VmaRoundDiv(T x, T y)
1968 return (x + (y / (T)2)) / y;
1973 template<
typename Iterator,
typename Compare>
1974 Iterator VmaQuickSortPartition(Iterator beg, Iterator end, Compare cmp)
1976 Iterator centerValue = end; --centerValue;
1977 Iterator insertIndex = beg;
1978 for(Iterator memTypeIndex = beg; memTypeIndex < centerValue; ++memTypeIndex)
1980 if(cmp(*memTypeIndex, *centerValue))
1982 if(insertIndex != memTypeIndex)
1984 VMA_SWAP(*memTypeIndex, *insertIndex);
1989 if(insertIndex != centerValue)
1991 VMA_SWAP(*insertIndex, *centerValue);
1996 template<
typename Iterator,
typename Compare>
1997 void VmaQuickSort(Iterator beg, Iterator end, Compare cmp)
2001 Iterator it = VmaQuickSortPartition<Iterator, Compare>(beg, end, cmp);
2002 VmaQuickSort<Iterator, Compare>(beg, it, cmp);
2003 VmaQuickSort<Iterator, Compare>(it + 1, end, cmp);
2007 #define VMA_SORT(beg, end, cmp) VmaQuickSort(beg, end, cmp) 2009 #endif // #ifndef VMA_SORT 2018 static inline bool VmaBlocksOnSamePage(
2019 VkDeviceSize resourceAOffset,
2020 VkDeviceSize resourceASize,
2021 VkDeviceSize resourceBOffset,
2022 VkDeviceSize pageSize)
2024 VMA_ASSERT(resourceAOffset + resourceASize <= resourceBOffset && resourceASize > 0 && pageSize > 0);
2025 VkDeviceSize resourceAEnd = resourceAOffset + resourceASize - 1;
2026 VkDeviceSize resourceAEndPage = resourceAEnd & ~(pageSize - 1);
2027 VkDeviceSize resourceBStart = resourceBOffset;
2028 VkDeviceSize resourceBStartPage = resourceBStart & ~(pageSize - 1);
2029 return resourceAEndPage == resourceBStartPage;
2032 enum VmaSuballocationType
2034 VMA_SUBALLOCATION_TYPE_FREE = 0,
2035 VMA_SUBALLOCATION_TYPE_UNKNOWN = 1,
2036 VMA_SUBALLOCATION_TYPE_BUFFER = 2,
2037 VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN = 3,
2038 VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR = 4,
2039 VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL = 5,
2040 VMA_SUBALLOCATION_TYPE_MAX_ENUM = 0x7FFFFFFF
2049 static inline bool VmaIsBufferImageGranularityConflict(
2050 VmaSuballocationType suballocType1,
2051 VmaSuballocationType suballocType2)
2053 if(suballocType1 > suballocType2)
2055 VMA_SWAP(suballocType1, suballocType2);
2058 switch(suballocType1)
2060 case VMA_SUBALLOCATION_TYPE_FREE:
2062 case VMA_SUBALLOCATION_TYPE_UNKNOWN:
2064 case VMA_SUBALLOCATION_TYPE_BUFFER:
2066 suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
2067 suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
2068 case VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN:
2070 suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN ||
2071 suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR ||
2072 suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
2073 case VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR:
2075 suballocType2 == VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL;
2076 case VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL:
2088 VmaMutexLock(VMA_MUTEX& mutex,
bool useMutex) :
2089 m_pMutex(useMutex ? &mutex : VMA_NULL)
2106 VMA_MUTEX* m_pMutex;
2109 #if VMA_DEBUG_GLOBAL_MUTEX 2110 static VMA_MUTEX gDebugGlobalMutex;
2111 #define VMA_DEBUG_GLOBAL_MUTEX_LOCK VmaMutexLock debugGlobalMutexLock(gDebugGlobalMutex, true); 2113 #define VMA_DEBUG_GLOBAL_MUTEX_LOCK 2117 static const VkDeviceSize VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER = 16;
2128 template <
typename IterT,
typename KeyT,
typename CmpT>
2129 static IterT VmaBinaryFindFirstNotLess(IterT beg, IterT end,
const KeyT &key, CmpT cmp)
2131 size_t down = 0, up = (end - beg);
2134 const size_t mid = (down + up) / 2;
2135 if(cmp(*(beg+mid), key))
2150 static void* VmaMalloc(
const VkAllocationCallbacks* pAllocationCallbacks,
size_t size,
size_t alignment)
2152 if((pAllocationCallbacks != VMA_NULL) &&
2153 (pAllocationCallbacks->pfnAllocation != VMA_NULL))
2155 return (*pAllocationCallbacks->pfnAllocation)(
2156 pAllocationCallbacks->pUserData,
2159 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
2163 return VMA_SYSTEM_ALIGNED_MALLOC(size, alignment);
2167 static void VmaFree(
const VkAllocationCallbacks* pAllocationCallbacks,
void* ptr)
2169 if((pAllocationCallbacks != VMA_NULL) &&
2170 (pAllocationCallbacks->pfnFree != VMA_NULL))
2172 (*pAllocationCallbacks->pfnFree)(pAllocationCallbacks->pUserData, ptr);
2176 VMA_SYSTEM_FREE(ptr);
2180 template<
typename T>
2181 static T* VmaAllocate(
const VkAllocationCallbacks* pAllocationCallbacks)
2183 return (T*)VmaMalloc(pAllocationCallbacks,
sizeof(T), VMA_ALIGN_OF(T));
2186 template<
typename T>
2187 static T* VmaAllocateArray(
const VkAllocationCallbacks* pAllocationCallbacks,
size_t count)
2189 return (T*)VmaMalloc(pAllocationCallbacks,
sizeof(T) * count, VMA_ALIGN_OF(T));
2192 #define vma_new(allocator, type) new(VmaAllocate<type>(allocator))(type) 2194 #define vma_new_array(allocator, type, count) new(VmaAllocateArray<type>((allocator), (count)))(type) 2196 template<
typename T>
2197 static void vma_delete(
const VkAllocationCallbacks* pAllocationCallbacks, T* ptr)
2200 VmaFree(pAllocationCallbacks, ptr);
2203 template<
typename T>
2204 static void vma_delete_array(
const VkAllocationCallbacks* pAllocationCallbacks, T* ptr,
size_t count)
2208 for(
size_t i = count; i--; )
2212 VmaFree(pAllocationCallbacks, ptr);
2217 template<
typename T>
2218 class VmaStlAllocator
2221 const VkAllocationCallbacks*
const m_pCallbacks;
2222 typedef T value_type;
2224 VmaStlAllocator(
const VkAllocationCallbacks* pCallbacks) : m_pCallbacks(pCallbacks) { }
2225 template<
typename U> VmaStlAllocator(
const VmaStlAllocator<U>& src) : m_pCallbacks(src.m_pCallbacks) { }
2227 T* allocate(
size_t n) {
return VmaAllocateArray<T>(m_pCallbacks, n); }
2228 void deallocate(T* p,
size_t n) { VmaFree(m_pCallbacks, p); }
2230 template<
typename U>
2231 bool operator==(
const VmaStlAllocator<U>& rhs)
const 2233 return m_pCallbacks == rhs.m_pCallbacks;
2235 template<
typename U>
2236 bool operator!=(
const VmaStlAllocator<U>& rhs)
const 2238 return m_pCallbacks != rhs.m_pCallbacks;
2241 VmaStlAllocator& operator=(
const VmaStlAllocator& x) =
delete;
2244 #if VMA_USE_STL_VECTOR 2246 #define VmaVector std::vector 2248 template<
typename T,
typename allocatorT>
2249 static void VmaVectorInsert(std::vector<T, allocatorT>& vec,
size_t index,
const T& item)
2251 vec.insert(vec.begin() + index, item);
2254 template<
typename T,
typename allocatorT>
2255 static void VmaVectorRemove(std::vector<T, allocatorT>& vec,
size_t index)
2257 vec.erase(vec.begin() + index);
2260 #else // #if VMA_USE_STL_VECTOR 2265 template<
typename T,
typename AllocatorT>
2269 typedef T value_type;
2271 VmaVector(
const AllocatorT& allocator) :
2272 m_Allocator(allocator),
2279 VmaVector(
size_t count,
const AllocatorT& allocator) :
2280 m_Allocator(allocator),
2281 m_pArray(count ? (T*)VmaAllocateArray<T>(allocator.m_pCallbacks, count) : VMA_NULL),
2287 VmaVector(
const VmaVector<T, AllocatorT>& src) :
2288 m_Allocator(src.m_Allocator),
2289 m_pArray(src.m_Count ? (T*)VmaAllocateArray<T>(src.m_Allocator.m_pCallbacks, src.m_Count) : VMA_NULL),
2290 m_Count(src.m_Count),
2291 m_Capacity(src.m_Count)
2295 memcpy(m_pArray, src.m_pArray, m_Count *
sizeof(T));
2301 VmaFree(m_Allocator.m_pCallbacks, m_pArray);
2304 VmaVector& operator=(
const VmaVector<T, AllocatorT>& rhs)
2308 resize(rhs.m_Count);
2311 memcpy(m_pArray, rhs.m_pArray, m_Count *
sizeof(T));
2317 bool empty()
const {
return m_Count == 0; }
2318 size_t size()
const {
return m_Count; }
2319 T* data() {
return m_pArray; }
2320 const T* data()
const {
return m_pArray; }
2322 T& operator[](
size_t index)
2324 VMA_HEAVY_ASSERT(index < m_Count);
2325 return m_pArray[index];
2327 const T& operator[](
size_t index)
const 2329 VMA_HEAVY_ASSERT(index < m_Count);
2330 return m_pArray[index];
2335 VMA_HEAVY_ASSERT(m_Count > 0);
2338 const T& front()
const 2340 VMA_HEAVY_ASSERT(m_Count > 0);
2345 VMA_HEAVY_ASSERT(m_Count > 0);
2346 return m_pArray[m_Count - 1];
2348 const T& back()
const 2350 VMA_HEAVY_ASSERT(m_Count > 0);
2351 return m_pArray[m_Count - 1];
2354 void reserve(
size_t newCapacity,
bool freeMemory =
false)
2356 newCapacity = VMA_MAX(newCapacity, m_Count);
2358 if((newCapacity < m_Capacity) && !freeMemory)
2360 newCapacity = m_Capacity;
2363 if(newCapacity != m_Capacity)
2365 T*
const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator, newCapacity) : VMA_NULL;
2368 memcpy(newArray, m_pArray, m_Count *
sizeof(T));
2370 VmaFree(m_Allocator.m_pCallbacks, m_pArray);
2371 m_Capacity = newCapacity;
2372 m_pArray = newArray;
2376 void resize(
size_t newCount,
bool freeMemory =
false)
2378 size_t newCapacity = m_Capacity;
2379 if(newCount > m_Capacity)
2381 newCapacity = VMA_MAX(newCount, VMA_MAX(m_Capacity * 3 / 2, (
size_t)8));
2385 newCapacity = newCount;
2388 if(newCapacity != m_Capacity)
2390 T*
const newArray = newCapacity ? VmaAllocateArray<T>(m_Allocator.m_pCallbacks, newCapacity) : VMA_NULL;
2391 const size_t elementsToCopy = VMA_MIN(m_Count, newCount);
2392 if(elementsToCopy != 0)
2394 memcpy(newArray, m_pArray, elementsToCopy *
sizeof(T));
2396 VmaFree(m_Allocator.m_pCallbacks, m_pArray);
2397 m_Capacity = newCapacity;
2398 m_pArray = newArray;
2404 void clear(
bool freeMemory =
false)
2406 resize(0, freeMemory);
2409 void insert(
size_t index,
const T& src)
2411 VMA_HEAVY_ASSERT(index <= m_Count);
2412 const size_t oldCount = size();
2413 resize(oldCount + 1);
2414 if(index < oldCount)
2416 memmove(m_pArray + (index + 1), m_pArray + index, (oldCount - index) *
sizeof(T));
2418 m_pArray[index] = src;
2421 void remove(
size_t index)
2423 VMA_HEAVY_ASSERT(index < m_Count);
2424 const size_t oldCount = size();
2425 if(index < oldCount - 1)
2427 memmove(m_pArray + index, m_pArray + (index + 1), (oldCount - index - 1) *
sizeof(T));
2429 resize(oldCount - 1);
2432 void push_back(
const T& src)
2434 const size_t newIndex = size();
2435 resize(newIndex + 1);
2436 m_pArray[newIndex] = src;
2441 VMA_HEAVY_ASSERT(m_Count > 0);
2445 void push_front(
const T& src)
2452 VMA_HEAVY_ASSERT(m_Count > 0);
2456 typedef T* iterator;
2458 iterator begin() {
return m_pArray; }
2459 iterator end() {
return m_pArray + m_Count; }
2462 AllocatorT m_Allocator;
2468 template<
typename T,
typename allocatorT>
2469 static void VmaVectorInsert(VmaVector<T, allocatorT>& vec,
size_t index,
const T& item)
2471 vec.insert(index, item);
2474 template<
typename T,
typename allocatorT>
2475 static void VmaVectorRemove(VmaVector<T, allocatorT>& vec,
size_t index)
2480 #endif // #if VMA_USE_STL_VECTOR 2482 template<
typename CmpLess,
typename VectorT>
2483 size_t VmaVectorInsertSorted(VectorT& vector,
const typename VectorT::value_type& value)
2485 const size_t indexToInsert = VmaBinaryFindFirstNotLess(
2487 vector.data() + vector.size(),
2489 CmpLess()) - vector.data();
2490 VmaVectorInsert(vector, indexToInsert, value);
2491 return indexToInsert;
2494 template<
typename CmpLess,
typename VectorT>
2495 bool VmaVectorRemoveSorted(VectorT& vector,
const typename VectorT::value_type& value)
2498 typename VectorT::iterator it = VmaBinaryFindFirstNotLess(
2503 if((it != vector.end()) && !comparator(*it, value) && !comparator(value, *it))
2505 size_t indexToRemove = it - vector.begin();
2506 VmaVectorRemove(vector, indexToRemove);
2512 template<
typename CmpLess,
typename VectorT>
2513 size_t VmaVectorFindSorted(
const VectorT& vector,
const typename VectorT::value_type& value)
2516 typename VectorT::iterator it = VmaBinaryFindFirstNotLess(
2518 vector.data() + vector.size(),
2521 if(it != vector.size() && !comparator(*it, value) && !comparator(value, *it))
2523 return it - vector.begin();
2527 return vector.size();
2539 template<
typename T>
2540 class VmaPoolAllocator
2543 VmaPoolAllocator(
const VkAllocationCallbacks* pAllocationCallbacks,
size_t itemsPerBlock);
2544 ~VmaPoolAllocator();
2552 uint32_t NextFreeIndex;
2559 uint32_t FirstFreeIndex;
2562 const VkAllocationCallbacks* m_pAllocationCallbacks;
2563 size_t m_ItemsPerBlock;
2564 VmaVector< ItemBlock, VmaStlAllocator<ItemBlock> > m_ItemBlocks;
2566 ItemBlock& CreateNewBlock();
2569 template<
typename T>
2570 VmaPoolAllocator<T>::VmaPoolAllocator(
const VkAllocationCallbacks* pAllocationCallbacks,
size_t itemsPerBlock) :
2571 m_pAllocationCallbacks(pAllocationCallbacks),
2572 m_ItemsPerBlock(itemsPerBlock),
2573 m_ItemBlocks(VmaStlAllocator<ItemBlock>(pAllocationCallbacks))
2575 VMA_ASSERT(itemsPerBlock > 0);
2578 template<
typename T>
2579 VmaPoolAllocator<T>::~VmaPoolAllocator()
2584 template<
typename T>
2585 void VmaPoolAllocator<T>::Clear()
2587 for(
size_t i = m_ItemBlocks.size(); i--; )
2588 vma_delete_array(m_pAllocationCallbacks, m_ItemBlocks[i].pItems, m_ItemsPerBlock);
2589 m_ItemBlocks.clear();
2592 template<
typename T>
2593 T* VmaPoolAllocator<T>::Alloc()
2595 for(
size_t i = m_ItemBlocks.size(); i--; )
2597 ItemBlock& block = m_ItemBlocks[i];
2599 if(block.FirstFreeIndex != UINT32_MAX)
2601 Item*
const pItem = &block.pItems[block.FirstFreeIndex];
2602 block.FirstFreeIndex = pItem->NextFreeIndex;
2603 return &pItem->Value;
2608 ItemBlock& newBlock = CreateNewBlock();
2609 Item*
const pItem = &newBlock.pItems[0];
2610 newBlock.FirstFreeIndex = pItem->NextFreeIndex;
2611 return &pItem->Value;
2614 template<
typename T>
2615 void VmaPoolAllocator<T>::Free(T* ptr)
2618 for(
size_t i = 0; i < m_ItemBlocks.size(); ++i)
2620 ItemBlock& block = m_ItemBlocks[i];
2624 memcpy(&pItemPtr, &ptr,
sizeof(pItemPtr));
2627 if((pItemPtr >= block.pItems) && (pItemPtr < block.pItems + m_ItemsPerBlock))
2629 const uint32_t index =
static_cast<uint32_t
>(pItemPtr - block.pItems);
2630 pItemPtr->NextFreeIndex = block.FirstFreeIndex;
2631 block.FirstFreeIndex = index;
2635 VMA_ASSERT(0 &&
"Pointer doesn't belong to this memory pool.");
2638 template<
typename T>
2639 typename VmaPoolAllocator<T>::ItemBlock& VmaPoolAllocator<T>::CreateNewBlock()
2641 ItemBlock newBlock = {
2642 vma_new_array(m_pAllocationCallbacks, Item, m_ItemsPerBlock), 0 };
2644 m_ItemBlocks.push_back(newBlock);
2647 for(uint32_t i = 0; i < m_ItemsPerBlock - 1; ++i)
2648 newBlock.pItems[i].NextFreeIndex = i + 1;
2649 newBlock.pItems[m_ItemsPerBlock - 1].NextFreeIndex = UINT32_MAX;
2650 return m_ItemBlocks.back();
2656 #if VMA_USE_STL_LIST 2658 #define VmaList std::list 2660 #else // #if VMA_USE_STL_LIST 2662 template<
typename T>
2671 template<
typename T>
2675 typedef VmaListItem<T> ItemType;
2677 VmaRawList(
const VkAllocationCallbacks* pAllocationCallbacks);
2681 size_t GetCount()
const {
return m_Count; }
2682 bool IsEmpty()
const {
return m_Count == 0; }
2684 ItemType* Front() {
return m_pFront; }
2685 const ItemType* Front()
const {
return m_pFront; }
2686 ItemType* Back() {
return m_pBack; }
2687 const ItemType* Back()
const {
return m_pBack; }
2689 ItemType* PushBack();
2690 ItemType* PushFront();
2691 ItemType* PushBack(
const T& value);
2692 ItemType* PushFront(
const T& value);
2697 ItemType* InsertBefore(ItemType* pItem);
2699 ItemType* InsertAfter(ItemType* pItem);
2701 ItemType* InsertBefore(ItemType* pItem,
const T& value);
2702 ItemType* InsertAfter(ItemType* pItem,
const T& value);
2704 void Remove(ItemType* pItem);
2707 const VkAllocationCallbacks*
const m_pAllocationCallbacks;
2708 VmaPoolAllocator<ItemType> m_ItemAllocator;
2714 VmaRawList(
const VmaRawList<T>& src);
2715 VmaRawList<T>& operator=(
const VmaRawList<T>& rhs);
2718 template<
typename T>
2719 VmaRawList<T>::VmaRawList(
const VkAllocationCallbacks* pAllocationCallbacks) :
2720 m_pAllocationCallbacks(pAllocationCallbacks),
2721 m_ItemAllocator(pAllocationCallbacks, 128),
2728 template<
typename T>
2729 VmaRawList<T>::~VmaRawList()
2735 template<
typename T>
2736 void VmaRawList<T>::Clear()
2738 if(IsEmpty() ==
false)
2740 ItemType* pItem = m_pBack;
2741 while(pItem != VMA_NULL)
2743 ItemType*
const pPrevItem = pItem->pPrev;
2744 m_ItemAllocator.Free(pItem);
2747 m_pFront = VMA_NULL;
2753 template<
typename T>
2754 VmaListItem<T>* VmaRawList<T>::PushBack()
2756 ItemType*
const pNewItem = m_ItemAllocator.Alloc();
2757 pNewItem->pNext = VMA_NULL;
2760 pNewItem->pPrev = VMA_NULL;
2761 m_pFront = pNewItem;
2767 pNewItem->pPrev = m_pBack;
2768 m_pBack->pNext = pNewItem;
2775 template<
typename T>
2776 VmaListItem<T>* VmaRawList<T>::PushFront()
2778 ItemType*
const pNewItem = m_ItemAllocator.Alloc();
2779 pNewItem->pPrev = VMA_NULL;
2782 pNewItem->pNext = VMA_NULL;
2783 m_pFront = pNewItem;
2789 pNewItem->pNext = m_pFront;
2790 m_pFront->pPrev = pNewItem;
2791 m_pFront = pNewItem;
2797 template<
typename T>
2798 VmaListItem<T>* VmaRawList<T>::PushBack(
const T& value)
2800 ItemType*
const pNewItem = PushBack();
2801 pNewItem->Value = value;
2805 template<
typename T>
2806 VmaListItem<T>* VmaRawList<T>::PushFront(
const T& value)
2808 ItemType*
const pNewItem = PushFront();
2809 pNewItem->Value = value;
2813 template<
typename T>
2814 void VmaRawList<T>::PopBack()
2816 VMA_HEAVY_ASSERT(m_Count > 0);
2817 ItemType*
const pBackItem = m_pBack;
2818 ItemType*
const pPrevItem = pBackItem->pPrev;
2819 if(pPrevItem != VMA_NULL)
2821 pPrevItem->pNext = VMA_NULL;
2823 m_pBack = pPrevItem;
2824 m_ItemAllocator.Free(pBackItem);
2828 template<
typename T>
2829 void VmaRawList<T>::PopFront()
2831 VMA_HEAVY_ASSERT(m_Count > 0);
2832 ItemType*
const pFrontItem = m_pFront;
2833 ItemType*
const pNextItem = pFrontItem->pNext;
2834 if(pNextItem != VMA_NULL)
2836 pNextItem->pPrev = VMA_NULL;
2838 m_pFront = pNextItem;
2839 m_ItemAllocator.Free(pFrontItem);
2843 template<
typename T>
2844 void VmaRawList<T>::Remove(ItemType* pItem)
2846 VMA_HEAVY_ASSERT(pItem != VMA_NULL);
2847 VMA_HEAVY_ASSERT(m_Count > 0);
2849 if(pItem->pPrev != VMA_NULL)
2851 pItem->pPrev->pNext = pItem->pNext;
2855 VMA_HEAVY_ASSERT(m_pFront == pItem);
2856 m_pFront = pItem->pNext;
2859 if(pItem->pNext != VMA_NULL)
2861 pItem->pNext->pPrev = pItem->pPrev;
2865 VMA_HEAVY_ASSERT(m_pBack == pItem);
2866 m_pBack = pItem->pPrev;
2869 m_ItemAllocator.Free(pItem);
2873 template<
typename T>
2874 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem)
2876 if(pItem != VMA_NULL)
2878 ItemType*
const prevItem = pItem->pPrev;
2879 ItemType*
const newItem = m_ItemAllocator.Alloc();
2880 newItem->pPrev = prevItem;
2881 newItem->pNext = pItem;
2882 pItem->pPrev = newItem;
2883 if(prevItem != VMA_NULL)
2885 prevItem->pNext = newItem;
2889 VMA_HEAVY_ASSERT(m_pFront == pItem);
2899 template<
typename T>
2900 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem)
2902 if(pItem != VMA_NULL)
2904 ItemType*
const nextItem = pItem->pNext;
2905 ItemType*
const newItem = m_ItemAllocator.Alloc();
2906 newItem->pNext = nextItem;
2907 newItem->pPrev = pItem;
2908 pItem->pNext = newItem;
2909 if(nextItem != VMA_NULL)
2911 nextItem->pPrev = newItem;
2915 VMA_HEAVY_ASSERT(m_pBack == pItem);
2925 template<
typename T>
2926 VmaListItem<T>* VmaRawList<T>::InsertBefore(ItemType* pItem,
const T& value)
2928 ItemType*
const newItem = InsertBefore(pItem);
2929 newItem->Value = value;
2933 template<
typename T>
2934 VmaListItem<T>* VmaRawList<T>::InsertAfter(ItemType* pItem,
const T& value)
2936 ItemType*
const newItem = InsertAfter(pItem);
2937 newItem->Value = value;
2941 template<
typename T,
typename AllocatorT>
2954 T& operator*()
const 2956 VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
2957 return m_pItem->Value;
2959 T* operator->()
const 2961 VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
2962 return &m_pItem->Value;
2965 iterator& operator++()
2967 VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
2968 m_pItem = m_pItem->pNext;
2971 iterator& operator--()
2973 if(m_pItem != VMA_NULL)
2975 m_pItem = m_pItem->pPrev;
2979 VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
2980 m_pItem = m_pList->Back();
2985 iterator operator++(
int)
2987 iterator result = *
this;
2991 iterator operator--(
int)
2993 iterator result = *
this;
2998 bool operator==(
const iterator& rhs)
const 3000 VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
3001 return m_pItem == rhs.m_pItem;
3003 bool operator!=(
const iterator& rhs)
const 3005 VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
3006 return m_pItem != rhs.m_pItem;
3010 VmaRawList<T>* m_pList;
3011 VmaListItem<T>* m_pItem;
3013 iterator(VmaRawList<T>* pList, VmaListItem<T>* pItem) :
3019 friend class VmaList<T, AllocatorT>;
3022 class const_iterator
3031 const_iterator(
const iterator& src) :
3032 m_pList(src.m_pList),
3033 m_pItem(src.m_pItem)
3037 const T& operator*()
const 3039 VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
3040 return m_pItem->Value;
3042 const T* operator->()
const 3044 VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
3045 return &m_pItem->Value;
3048 const_iterator& operator++()
3050 VMA_HEAVY_ASSERT(m_pItem != VMA_NULL);
3051 m_pItem = m_pItem->pNext;
3054 const_iterator& operator--()
3056 if(m_pItem != VMA_NULL)
3058 m_pItem = m_pItem->pPrev;
3062 VMA_HEAVY_ASSERT(!m_pList->IsEmpty());
3063 m_pItem = m_pList->Back();
3068 const_iterator operator++(
int)
3070 const_iterator result = *
this;
3074 const_iterator operator--(
int)
3076 const_iterator result = *
this;
3081 bool operator==(
const const_iterator& rhs)
const 3083 VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
3084 return m_pItem == rhs.m_pItem;
3086 bool operator!=(
const const_iterator& rhs)
const 3088 VMA_HEAVY_ASSERT(m_pList == rhs.m_pList);
3089 return m_pItem != rhs.m_pItem;
3093 const_iterator(
const VmaRawList<T>* pList,
const VmaListItem<T>* pItem) :
3099 const VmaRawList<T>* m_pList;
3100 const VmaListItem<T>* m_pItem;
3102 friend class VmaList<T, AllocatorT>;
3105 VmaList(
const AllocatorT& allocator) : m_RawList(allocator.m_pCallbacks) { }
3107 bool empty()
const {
return m_RawList.IsEmpty(); }
3108 size_t size()
const {
return m_RawList.GetCount(); }
3110 iterator begin() {
return iterator(&m_RawList, m_RawList.Front()); }
3111 iterator end() {
return iterator(&m_RawList, VMA_NULL); }
3113 const_iterator cbegin()
const {
return const_iterator(&m_RawList, m_RawList.Front()); }
3114 const_iterator cend()
const {
return const_iterator(&m_RawList, VMA_NULL); }
3116 void clear() { m_RawList.Clear(); }
3117 void push_back(
const T& value) { m_RawList.PushBack(value); }
3118 void erase(iterator it) { m_RawList.Remove(it.m_pItem); }
3119 iterator insert(iterator it,
const T& value) {
return iterator(&m_RawList, m_RawList.InsertBefore(it.m_pItem, value)); }
3122 VmaRawList<T> m_RawList;
3125 #endif // #if VMA_USE_STL_LIST 3133 #if VMA_USE_STL_UNORDERED_MAP 3135 #define VmaPair std::pair 3137 #define VMA_MAP_TYPE(KeyT, ValueT) \ 3138 std::unordered_map< KeyT, ValueT, std::hash<KeyT>, std::equal_to<KeyT>, VmaStlAllocator< std::pair<KeyT, ValueT> > > 3140 #else // #if VMA_USE_STL_UNORDERED_MAP 3142 template<
typename T1,
typename T2>
3148 VmaPair() : first(), second() { }
3149 VmaPair(
const T1& firstSrc,
const T2& secondSrc) : first(firstSrc), second(secondSrc) { }
3155 template<
typename KeyT,
typename ValueT>
3159 typedef VmaPair<KeyT, ValueT> PairType;
3160 typedef PairType* iterator;
3162 VmaMap(
const VmaStlAllocator<PairType>& allocator) : m_Vector(allocator) { }
3164 iterator begin() {
return m_Vector.begin(); }
3165 iterator end() {
return m_Vector.end(); }
3167 void insert(
const PairType& pair);
3168 iterator find(
const KeyT& key);
3169 void erase(iterator it);
3172 VmaVector< PairType, VmaStlAllocator<PairType> > m_Vector;
3175 #define VMA_MAP_TYPE(KeyT, ValueT) VmaMap<KeyT, ValueT> 3177 template<
typename FirstT,
typename SecondT>
3178 struct VmaPairFirstLess
3180 bool operator()(
const VmaPair<FirstT, SecondT>& lhs,
const VmaPair<FirstT, SecondT>& rhs)
const 3182 return lhs.first < rhs.first;
3184 bool operator()(
const VmaPair<FirstT, SecondT>& lhs,
const FirstT& rhsFirst)
const 3186 return lhs.first < rhsFirst;
3190 template<
typename KeyT,
typename ValueT>
3191 void VmaMap<KeyT, ValueT>::insert(
const PairType& pair)
3193 const size_t indexToInsert = VmaBinaryFindFirstNotLess(
3195 m_Vector.data() + m_Vector.size(),
3197 VmaPairFirstLess<KeyT, ValueT>()) - m_Vector.data();
3198 VmaVectorInsert(m_Vector, indexToInsert, pair);
3201 template<
typename KeyT,
typename ValueT>
3202 VmaPair<KeyT, ValueT>* VmaMap<KeyT, ValueT>::find(
const KeyT& key)
3204 PairType* it = VmaBinaryFindFirstNotLess(
3206 m_Vector.data() + m_Vector.size(),
3208 VmaPairFirstLess<KeyT, ValueT>());
3209 if((it != m_Vector.end()) && (it->first == key))
3215 return m_Vector.end();
3219 template<
typename KeyT,
typename ValueT>
3220 void VmaMap<KeyT, ValueT>::erase(iterator it)
3222 VmaVectorRemove(m_Vector, it - m_Vector.begin());
3225 #endif // #if VMA_USE_STL_UNORDERED_MAP 3231 class VmaDeviceMemoryBlock;
3233 struct VmaAllocation_T
3236 static const uint8_t MAP_COUNT_FLAG_PERSISTENT_MAP = 0x80;
3240 FLAG_USER_DATA_STRING = 0x01,
3244 enum ALLOCATION_TYPE
3246 ALLOCATION_TYPE_NONE,
3247 ALLOCATION_TYPE_BLOCK,
3248 ALLOCATION_TYPE_DEDICATED,
3251 VmaAllocation_T(uint32_t currentFrameIndex,
bool userDataString) :
3254 m_pUserData(VMA_NULL),
3255 m_LastUseFrameIndex(currentFrameIndex),
3256 m_Type((uint8_t)ALLOCATION_TYPE_NONE),
3257 m_SuballocationType((uint8_t)VMA_SUBALLOCATION_TYPE_UNKNOWN),
3259 m_Flags(userDataString ? (uint8_t)FLAG_USER_DATA_STRING : 0)
3265 VMA_ASSERT((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) == 0 &&
"Allocation was not unmapped before destruction.");
3268 VMA_ASSERT(m_pUserData == VMA_NULL);
3271 void InitBlockAllocation(
3273 VmaDeviceMemoryBlock* block,
3274 VkDeviceSize offset,
3275 VkDeviceSize alignment,
3277 VmaSuballocationType suballocationType,
3281 VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
3282 VMA_ASSERT(block != VMA_NULL);
3283 m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
3284 m_Alignment = alignment;
3286 m_MapCount = mapped ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
3287 m_SuballocationType = (uint8_t)suballocationType;
3288 m_BlockAllocation.m_hPool = hPool;
3289 m_BlockAllocation.m_Block = block;
3290 m_BlockAllocation.m_Offset = offset;
3291 m_BlockAllocation.m_CanBecomeLost = canBecomeLost;
3296 VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
3297 VMA_ASSERT(m_LastUseFrameIndex.load() == VMA_FRAME_INDEX_LOST);
3298 m_Type = (uint8_t)ALLOCATION_TYPE_BLOCK;
3299 m_BlockAllocation.m_hPool = VK_NULL_HANDLE;
3300 m_BlockAllocation.m_Block = VMA_NULL;
3301 m_BlockAllocation.m_Offset = 0;
3302 m_BlockAllocation.m_CanBecomeLost =
true;
3305 void ChangeBlockAllocation(
3306 VmaAllocator hAllocator,
3307 VmaDeviceMemoryBlock* block,
3308 VkDeviceSize offset);
3311 void InitDedicatedAllocation(
3312 uint32_t memoryTypeIndex,
3313 VkDeviceMemory hMemory,
3314 VmaSuballocationType suballocationType,
3318 VMA_ASSERT(m_Type == ALLOCATION_TYPE_NONE);
3319 VMA_ASSERT(hMemory != VK_NULL_HANDLE);
3320 m_Type = (uint8_t)ALLOCATION_TYPE_DEDICATED;
3323 m_SuballocationType = (uint8_t)suballocationType;
3324 m_MapCount = (pMappedData != VMA_NULL) ? MAP_COUNT_FLAG_PERSISTENT_MAP : 0;
3325 m_DedicatedAllocation.m_MemoryTypeIndex = memoryTypeIndex;
3326 m_DedicatedAllocation.m_hMemory = hMemory;
3327 m_DedicatedAllocation.m_pMappedData = pMappedData;
3330 ALLOCATION_TYPE GetType()
const {
return (ALLOCATION_TYPE)m_Type; }
3331 VkDeviceSize GetAlignment()
const {
return m_Alignment; }
3332 VkDeviceSize GetSize()
const {
return m_Size; }
3333 bool IsUserDataString()
const {
return (m_Flags & FLAG_USER_DATA_STRING) != 0; }
3334 void* GetUserData()
const {
return m_pUserData; }
3335 void SetUserData(VmaAllocator hAllocator,
void* pUserData);
3336 VmaSuballocationType GetSuballocationType()
const {
return (VmaSuballocationType)m_SuballocationType; }
3338 VmaDeviceMemoryBlock* GetBlock()
const 3340 VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
3341 return m_BlockAllocation.m_Block;
3343 VkDeviceSize GetOffset()
const;
3344 VkDeviceMemory GetMemory()
const;
3345 uint32_t GetMemoryTypeIndex()
const;
3346 bool IsPersistentMap()
const {
return (m_MapCount & MAP_COUNT_FLAG_PERSISTENT_MAP) != 0; }
3347 void* GetMappedData()
const;
3348 bool CanBecomeLost()
const;
3349 VmaPool GetPool()
const;
3351 uint32_t GetLastUseFrameIndex()
const 3353 return m_LastUseFrameIndex.load();
3355 bool CompareExchangeLastUseFrameIndex(uint32_t& expected, uint32_t desired)
3357 return m_LastUseFrameIndex.compare_exchange_weak(expected, desired);
3367 bool MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
3369 void DedicatedAllocCalcStatsInfo(VmaStatInfo& outInfo)
3371 VMA_ASSERT(m_Type == ALLOCATION_TYPE_DEDICATED);
3372 outInfo.blockCount = 1;
3373 outInfo.allocationCount = 1;
3374 outInfo.unusedRangeCount = 0;
3375 outInfo.usedBytes = m_Size;
3376 outInfo.unusedBytes = 0;
3377 outInfo.allocationSizeMin = outInfo.allocationSizeMax = m_Size;
3378 outInfo.unusedRangeSizeMin = UINT64_MAX;
3379 outInfo.unusedRangeSizeMax = 0;
3382 void BlockAllocMap();
3383 void BlockAllocUnmap();
3384 VkResult DedicatedAllocMap(VmaAllocator hAllocator,
void** ppData);
3385 void DedicatedAllocUnmap(VmaAllocator hAllocator);
3388 VkDeviceSize m_Alignment;
3389 VkDeviceSize m_Size;
3391 VMA_ATOMIC_UINT32 m_LastUseFrameIndex;
3393 uint8_t m_SuballocationType;
3400 struct BlockAllocation
3403 VmaDeviceMemoryBlock* m_Block;
3404 VkDeviceSize m_Offset;
3405 bool m_CanBecomeLost;
3409 struct DedicatedAllocation
3411 uint32_t m_MemoryTypeIndex;
3412 VkDeviceMemory m_hMemory;
3413 void* m_pMappedData;
3419 BlockAllocation m_BlockAllocation;
3421 DedicatedAllocation m_DedicatedAllocation;
3424 void FreeUserDataString(VmaAllocator hAllocator);
3431 struct VmaSuballocation
3433 VkDeviceSize offset;
3435 VmaAllocation hAllocation;
3436 VmaSuballocationType type;
3439 typedef VmaList< VmaSuballocation, VmaStlAllocator<VmaSuballocation> > VmaSuballocationList;
3442 static const VkDeviceSize VMA_LOST_ALLOCATION_COST = 1048576;
3457 struct VmaAllocationRequest
3459 VkDeviceSize offset;
3460 VkDeviceSize sumFreeSize;
3461 VkDeviceSize sumItemSize;
3462 VmaSuballocationList::iterator item;
3463 size_t itemsToMakeLostCount;
3465 VkDeviceSize CalcCost()
const 3467 return sumItemSize + itemsToMakeLostCount * VMA_LOST_ALLOCATION_COST;
3475 class VmaBlockMetadata
3478 VmaBlockMetadata(VmaAllocator hAllocator);
3479 ~VmaBlockMetadata();
3480 void Init(VkDeviceSize size);
3483 bool Validate()
const;
3484 VkDeviceSize GetSize()
const {
return m_Size; }
3485 size_t GetAllocationCount()
const {
return m_Suballocations.size() - m_FreeCount; }
3486 VkDeviceSize GetSumFreeSize()
const {
return m_SumFreeSize; }
3487 VkDeviceSize GetUnusedRangeSizeMax()
const;
3489 bool IsEmpty()
const;
3491 void CalcAllocationStatInfo(VmaStatInfo& outInfo)
const;
3492 void AddPoolStats(VmaPoolStats& inoutStats)
const;
3494 #if VMA_STATS_STRING_ENABLED 3495 void PrintDetailedMap(
class VmaJsonWriter& json)
const;
3499 void CreateFirstAllocationRequest(VmaAllocationRequest* pAllocationRequest);
3504 bool CreateAllocationRequest(
3505 uint32_t currentFrameIndex,
3506 uint32_t frameInUseCount,
3507 VkDeviceSize bufferImageGranularity,
3508 VkDeviceSize allocSize,
3509 VkDeviceSize allocAlignment,
3510 VmaSuballocationType allocType,
3511 bool canMakeOtherLost,
3512 VmaAllocationRequest* pAllocationRequest);
3514 bool MakeRequestedAllocationsLost(
3515 uint32_t currentFrameIndex,
3516 uint32_t frameInUseCount,
3517 VmaAllocationRequest* pAllocationRequest);
3519 uint32_t MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount);
3523 const VmaAllocationRequest& request,
3524 VmaSuballocationType type,
3525 VkDeviceSize allocSize,
3526 VmaAllocation hAllocation);
3529 void Free(
const VmaAllocation allocation);
3530 void FreeAtOffset(VkDeviceSize offset);
3533 VkDeviceSize m_Size;
3534 uint32_t m_FreeCount;
3535 VkDeviceSize m_SumFreeSize;
3536 VmaSuballocationList m_Suballocations;
3539 VmaVector< VmaSuballocationList::iterator, VmaStlAllocator< VmaSuballocationList::iterator > > m_FreeSuballocationsBySize;
3541 bool ValidateFreeSuballocationList()
const;
3545 bool CheckAllocation(
3546 uint32_t currentFrameIndex,
3547 uint32_t frameInUseCount,
3548 VkDeviceSize bufferImageGranularity,
3549 VkDeviceSize allocSize,
3550 VkDeviceSize allocAlignment,
3551 VmaSuballocationType allocType,
3552 VmaSuballocationList::const_iterator suballocItem,
3553 bool canMakeOtherLost,
3554 VkDeviceSize* pOffset,
3555 size_t* itemsToMakeLostCount,
3556 VkDeviceSize* pSumFreeSize,
3557 VkDeviceSize* pSumItemSize)
const;
3559 void MergeFreeWithNext(VmaSuballocationList::iterator item);
3563 VmaSuballocationList::iterator FreeSuballocation(VmaSuballocationList::iterator suballocItem);
3566 void RegisterFreeSuballocation(VmaSuballocationList::iterator item);
3569 void UnregisterFreeSuballocation(VmaSuballocationList::iterator item);
3573 class VmaDeviceMemoryMapping
3576 VmaDeviceMemoryMapping();
3577 ~VmaDeviceMemoryMapping();
3579 void* GetMappedData()
const {
return m_pMappedData; }
3582 VkResult Map(VmaAllocator hAllocator, VkDeviceMemory hMemory, uint32_t count,
void **ppData);
3583 void Unmap(VmaAllocator hAllocator, VkDeviceMemory hMemory, uint32_t count);
3587 uint32_t m_MapCount;
3588 void* m_pMappedData;
3597 class VmaDeviceMemoryBlock
3600 uint32_t m_MemoryTypeIndex;
3601 VkDeviceMemory m_hMemory;
3602 VmaDeviceMemoryMapping m_Mapping;
3603 VmaBlockMetadata m_Metadata;
3605 VmaDeviceMemoryBlock(VmaAllocator hAllocator);
3607 ~VmaDeviceMemoryBlock()
3609 VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
3614 uint32_t newMemoryTypeIndex,
3615 VkDeviceMemory newMemory,
3616 VkDeviceSize newSize);
3618 void Destroy(VmaAllocator allocator);
3621 bool Validate()
const;
3624 VkResult Map(VmaAllocator hAllocator, uint32_t count,
void** ppData);
3625 void Unmap(VmaAllocator hAllocator, uint32_t count);
3628 struct VmaPointerLess
3630 bool operator()(
const void* lhs,
const void* rhs)
const 3636 class VmaDefragmentator;
3644 struct VmaBlockVector
3647 VmaAllocator hAllocator,
3648 uint32_t memoryTypeIndex,
3649 VkDeviceSize preferredBlockSize,
3650 size_t minBlockCount,
3651 size_t maxBlockCount,
3652 VkDeviceSize bufferImageGranularity,
3653 uint32_t frameInUseCount,
3657 VkResult CreateMinBlocks();
3659 uint32_t GetMemoryTypeIndex()
const {
return m_MemoryTypeIndex; }
3660 VkDeviceSize GetPreferredBlockSize()
const {
return m_PreferredBlockSize; }
3661 VkDeviceSize GetBufferImageGranularity()
const {
return m_BufferImageGranularity; }
3662 uint32_t GetFrameInUseCount()
const {
return m_FrameInUseCount; }
3664 void GetPoolStats(VmaPoolStats* pStats);
3666 bool IsEmpty()
const {
return m_Blocks.empty(); }
3669 VmaPool hCurrentPool,
3670 uint32_t currentFrameIndex,
3671 const VkMemoryRequirements& vkMemReq,
3672 const VmaAllocationCreateInfo& createInfo,
3673 VmaSuballocationType suballocType,
3674 VmaAllocation* pAllocation);
3677 VmaAllocation hAllocation);
3680 void AddStats(VmaStats* pStats);
3682 #if VMA_STATS_STRING_ENABLED 3683 void PrintDetailedMap(
class VmaJsonWriter& json);
3686 void MakePoolAllocationsLost(
3687 uint32_t currentFrameIndex,
3688 size_t* pLostAllocationCount);
3690 VmaDefragmentator* EnsureDefragmentator(
3691 VmaAllocator hAllocator,
3692 uint32_t currentFrameIndex);
3694 VkResult Defragment(
3695 VmaDefragmentationStats* pDefragmentationStats,
3696 VkDeviceSize& maxBytesToMove,
3697 uint32_t& maxAllocationsToMove);
3699 void DestroyDefragmentator();
3702 friend class VmaDefragmentator;
3704 const VmaAllocator m_hAllocator;
3705 const uint32_t m_MemoryTypeIndex;
3706 const VkDeviceSize m_PreferredBlockSize;
3707 const size_t m_MinBlockCount;
3708 const size_t m_MaxBlockCount;
3709 const VkDeviceSize m_BufferImageGranularity;
3710 const uint32_t m_FrameInUseCount;
3711 const bool m_IsCustomPool;
3714 VmaVector< VmaDeviceMemoryBlock*, VmaStlAllocator<VmaDeviceMemoryBlock*> > m_Blocks;
3718 bool m_HasEmptyBlock;
3719 VmaDefragmentator* m_pDefragmentator;
3721 size_t CalcMaxBlockSize()
const;
3724 void Remove(VmaDeviceMemoryBlock* pBlock);
3728 void IncrementallySortBlocks();
3730 VkResult CreateBlock(VkDeviceSize blockSize,
size_t* pNewBlockIndex);
3736 VmaBlockVector m_BlockVector;
3740 VmaAllocator hAllocator,
3741 const VmaPoolCreateInfo& createInfo);
3744 VmaBlockVector& GetBlockVector() {
return m_BlockVector; }
3746 #if VMA_STATS_STRING_ENABLED 3751 class VmaDefragmentator
3753 const VmaAllocator m_hAllocator;
3754 VmaBlockVector*
const m_pBlockVector;
3755 uint32_t m_CurrentFrameIndex;
3756 VkDeviceSize m_BytesMoved;
3757 uint32_t m_AllocationsMoved;
3759 struct AllocationInfo
3761 VmaAllocation m_hAllocation;
3762 VkBool32* m_pChanged;
3765 m_hAllocation(VK_NULL_HANDLE),
3766 m_pChanged(VMA_NULL)
3771 struct AllocationInfoSizeGreater
3773 bool operator()(
const AllocationInfo& lhs,
const AllocationInfo& rhs)
const 3775 return lhs.m_hAllocation->GetSize() > rhs.m_hAllocation->GetSize();
3780 VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
3784 VmaDeviceMemoryBlock* m_pBlock;
3785 bool m_HasNonMovableAllocations;
3786 VmaVector< AllocationInfo, VmaStlAllocator<AllocationInfo> > m_Allocations;
3788 BlockInfo(
const VkAllocationCallbacks* pAllocationCallbacks) :
3790 m_HasNonMovableAllocations(true),
3791 m_Allocations(pAllocationCallbacks),
3792 m_pMappedDataForDefragmentation(VMA_NULL)
3796 void CalcHasNonMovableAllocations()
3798 const size_t blockAllocCount = m_pBlock->m_Metadata.GetAllocationCount();
3799 const size_t defragmentAllocCount = m_Allocations.size();
3800 m_HasNonMovableAllocations = blockAllocCount != defragmentAllocCount;
3803 void SortAllocationsBySizeDescecnding()
3805 VMA_SORT(m_Allocations.begin(), m_Allocations.end(), AllocationInfoSizeGreater());
3808 VkResult EnsureMapping(VmaAllocator hAllocator,
void** ppMappedData);
3809 void Unmap(VmaAllocator hAllocator);
3813 void* m_pMappedDataForDefragmentation;
3816 struct BlockPointerLess
3818 bool operator()(
const BlockInfo* pLhsBlockInfo,
const VmaDeviceMemoryBlock* pRhsBlock)
const 3820 return pLhsBlockInfo->m_pBlock < pRhsBlock;
3822 bool operator()(
const BlockInfo* pLhsBlockInfo,
const BlockInfo* pRhsBlockInfo)
const 3824 return pLhsBlockInfo->m_pBlock < pRhsBlockInfo->m_pBlock;
3830 struct BlockInfoCompareMoveDestination
3832 bool operator()(
const BlockInfo* pLhsBlockInfo,
const BlockInfo* pRhsBlockInfo)
const 3834 if(pLhsBlockInfo->m_HasNonMovableAllocations && !pRhsBlockInfo->m_HasNonMovableAllocations)
3838 if(!pLhsBlockInfo->m_HasNonMovableAllocations && pRhsBlockInfo->m_HasNonMovableAllocations)
3842 if(pLhsBlockInfo->m_pBlock->m_Metadata.GetSumFreeSize() < pRhsBlockInfo->m_pBlock->m_Metadata.GetSumFreeSize())
3850 typedef VmaVector< BlockInfo*, VmaStlAllocator<BlockInfo*> > BlockInfoVector;
3851 BlockInfoVector m_Blocks;
3853 VkResult DefragmentRound(
3854 VkDeviceSize maxBytesToMove,
3855 uint32_t maxAllocationsToMove);
3857 static bool MoveMakesSense(
3858 size_t dstBlockIndex, VkDeviceSize dstOffset,
3859 size_t srcBlockIndex, VkDeviceSize srcOffset);
3863 VmaAllocator hAllocator,
3864 VmaBlockVector* pBlockVector,
3865 uint32_t currentFrameIndex);
3867 ~VmaDefragmentator();
3869 VkDeviceSize GetBytesMoved()
const {
return m_BytesMoved; }
3870 uint32_t GetAllocationsMoved()
const {
return m_AllocationsMoved; }
3872 void AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged);
3874 VkResult Defragment(
3875 VkDeviceSize maxBytesToMove,
3876 uint32_t maxAllocationsToMove);
3880 struct VmaAllocator_T
3883 bool m_UseKhrDedicatedAllocation;
3885 bool m_AllocationCallbacksSpecified;
3886 VkAllocationCallbacks m_AllocationCallbacks;
3887 VmaDeviceMemoryCallbacks m_DeviceMemoryCallbacks;
3890 VkDeviceSize m_HeapSizeLimit[VK_MAX_MEMORY_HEAPS];
3891 VMA_MUTEX m_HeapSizeLimitMutex;
3893 VkPhysicalDeviceProperties m_PhysicalDeviceProperties;
3894 VkPhysicalDeviceMemoryProperties m_MemProps;
3897 VmaBlockVector* m_pBlockVectors[VK_MAX_MEMORY_TYPES];
3900 typedef VmaVector< VmaAllocation, VmaStlAllocator<VmaAllocation> > AllocationVectorType;
3901 AllocationVectorType* m_pDedicatedAllocations[VK_MAX_MEMORY_TYPES];
3902 VMA_MUTEX m_DedicatedAllocationsMutex[VK_MAX_MEMORY_TYPES];
3904 VmaAllocator_T(
const VmaAllocatorCreateInfo* pCreateInfo);
3907 const VkAllocationCallbacks* GetAllocationCallbacks()
const 3909 return m_AllocationCallbacksSpecified ? &m_AllocationCallbacks : 0;
3911 const VmaVulkanFunctions& GetVulkanFunctions()
const 3913 return m_VulkanFunctions;
3916 VkDeviceSize GetBufferImageGranularity()
const 3919 static_cast<VkDeviceSize>(VMA_DEBUG_MIN_BUFFER_IMAGE_GRANULARITY),
3920 m_PhysicalDeviceProperties.limits.bufferImageGranularity);
3923 uint32_t GetMemoryHeapCount()
const {
return m_MemProps.memoryHeapCount; }
3924 uint32_t GetMemoryTypeCount()
const {
return m_MemProps.memoryTypeCount; }
3926 uint32_t MemoryTypeIndexToHeapIndex(uint32_t memTypeIndex)
const 3928 VMA_ASSERT(memTypeIndex < m_MemProps.memoryTypeCount);
3929 return m_MemProps.memoryTypes[memTypeIndex].heapIndex;
3932 void GetBufferMemoryRequirements(
3934 VkMemoryRequirements& memReq,
3935 bool& requiresDedicatedAllocation,
3936 bool& prefersDedicatedAllocation)
const;
3937 void GetImageMemoryRequirements(
3939 VkMemoryRequirements& memReq,
3940 bool& requiresDedicatedAllocation,
3941 bool& prefersDedicatedAllocation)
const;
3944 VkResult AllocateMemory(
3945 const VkMemoryRequirements& vkMemReq,
3946 bool requiresDedicatedAllocation,
3947 bool prefersDedicatedAllocation,
3948 VkBuffer dedicatedBuffer,
3949 VkImage dedicatedImage,
3950 const VmaAllocationCreateInfo& createInfo,
3951 VmaSuballocationType suballocType,
3952 VmaAllocation* pAllocation);
3955 void FreeMemory(
const VmaAllocation allocation);
3957 void CalculateStats(VmaStats* pStats);
3959 #if VMA_STATS_STRING_ENABLED 3960 void PrintDetailedMap(
class VmaJsonWriter& json);
3963 VkResult Defragment(
3964 VmaAllocation* pAllocations,
3965 size_t allocationCount,
3966 VkBool32* pAllocationsChanged,
3967 const VmaDefragmentationInfo* pDefragmentationInfo,
3968 VmaDefragmentationStats* pDefragmentationStats);
3970 void GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo);
3972 VkResult CreatePool(
const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool);
3973 void DestroyPool(VmaPool pool);
3974 void GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats);
3976 void SetCurrentFrameIndex(uint32_t frameIndex);
3978 void MakePoolAllocationsLost(
3980 size_t* pLostAllocationCount);
3982 void CreateLostAllocation(VmaAllocation* pAllocation);
3984 VkResult AllocateVulkanMemory(
const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory);
3985 void FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory);
3987 VkResult Map(VmaAllocation hAllocation,
void** ppData);
3988 void Unmap(VmaAllocation hAllocation);
3991 VkDeviceSize m_PreferredLargeHeapBlockSize;
3993 VkPhysicalDevice m_PhysicalDevice;
3994 VMA_ATOMIC_UINT32 m_CurrentFrameIndex;
3996 VMA_MUTEX m_PoolsMutex;
3998 VmaVector<VmaPool, VmaStlAllocator<VmaPool> > m_Pools;
4000 VmaVulkanFunctions m_VulkanFunctions;
4002 void ImportVulkanFunctions(
const VmaVulkanFunctions* pVulkanFunctions);
4004 VkDeviceSize CalcPreferredBlockSize(uint32_t memTypeIndex);
4006 VkResult AllocateMemoryOfType(
4007 const VkMemoryRequirements& vkMemReq,
4008 bool dedicatedAllocation,
4009 VkBuffer dedicatedBuffer,
4010 VkImage dedicatedImage,
4011 const VmaAllocationCreateInfo& createInfo,
4012 uint32_t memTypeIndex,
4013 VmaSuballocationType suballocType,
4014 VmaAllocation* pAllocation);
4017 VkResult AllocateDedicatedMemory(
4019 VmaSuballocationType suballocType,
4020 uint32_t memTypeIndex,
4022 bool isUserDataString,
4024 VkBuffer dedicatedBuffer,
4025 VkImage dedicatedImage,
4026 VmaAllocation* pAllocation);
4029 void FreeDedicatedMemory(VmaAllocation allocation);
4035 static void* VmaMalloc(VmaAllocator hAllocator,
size_t size,
size_t alignment)
4037 return VmaMalloc(&hAllocator->m_AllocationCallbacks, size, alignment);
4040 static void VmaFree(VmaAllocator hAllocator,
void* ptr)
4042 VmaFree(&hAllocator->m_AllocationCallbacks, ptr);
4045 template<
typename T>
4046 static T* VmaAllocate(VmaAllocator hAllocator)
4048 return (T*)VmaMalloc(hAllocator,
sizeof(T), VMA_ALIGN_OF(T));
4051 template<
typename T>
4052 static T* VmaAllocateArray(VmaAllocator hAllocator,
size_t count)
4054 return (T*)VmaMalloc(hAllocator,
sizeof(T) * count, VMA_ALIGN_OF(T));
4057 template<
typename T>
4058 static void vma_delete(VmaAllocator hAllocator, T* ptr)
4063 VmaFree(hAllocator, ptr);
4067 template<
typename T>
4068 static void vma_delete_array(VmaAllocator hAllocator, T* ptr,
size_t count)
4072 for(
size_t i = count; i--; )
4074 VmaFree(hAllocator, ptr);
4081 #if VMA_STATS_STRING_ENABLED 4083 class VmaStringBuilder
4086 VmaStringBuilder(VmaAllocator alloc) : m_Data(VmaStlAllocator<char>(alloc->GetAllocationCallbacks())) { }
4087 size_t GetLength()
const {
return m_Data.size(); }
4088 const char* GetData()
const {
return m_Data.data(); }
4090 void Add(
char ch) { m_Data.push_back(ch); }
4091 void Add(
const char* pStr);
4092 void AddNewLine() { Add(
'\n'); }
4093 void AddNumber(uint32_t num);
4094 void AddNumber(uint64_t num);
4095 void AddPointer(
const void* ptr);
4098 VmaVector< char, VmaStlAllocator<char> > m_Data;
4101 void VmaStringBuilder::Add(
const char* pStr)
4103 const size_t strLen = strlen(pStr);
4106 const size_t oldCount = m_Data.size();
4107 m_Data.resize(oldCount + strLen);
4108 memcpy(m_Data.data() + oldCount, pStr, strLen);
4112 void VmaStringBuilder::AddNumber(uint32_t num)
4115 VmaUint32ToStr(buf,
sizeof(buf), num);
4119 void VmaStringBuilder::AddNumber(uint64_t num)
4122 VmaUint64ToStr(buf,
sizeof(buf), num);
4126 void VmaStringBuilder::AddPointer(
const void* ptr)
4129 VmaPtrToStr(buf,
sizeof(buf), ptr);
4133 #endif // #if VMA_STATS_STRING_ENABLED 4138 #if VMA_STATS_STRING_ENABLED 4143 VmaJsonWriter(
const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb);
4146 void BeginObject(
bool singleLine =
false);
4149 void BeginArray(
bool singleLine =
false);
4152 void WriteString(
const char* pStr);
4153 void BeginString(
const char* pStr = VMA_NULL);
4154 void ContinueString(
const char* pStr);
4155 void ContinueString(uint32_t n);
4156 void ContinueString(uint64_t n);
4157 void ContinueString_Pointer(
const void* ptr);
4158 void EndString(
const char* pStr = VMA_NULL);
4160 void WriteNumber(uint32_t n);
4161 void WriteNumber(uint64_t n);
4162 void WriteBool(
bool b);
4166 static const char*
const INDENT;
4168 enum COLLECTION_TYPE
4170 COLLECTION_TYPE_OBJECT,
4171 COLLECTION_TYPE_ARRAY,
4175 COLLECTION_TYPE type;
4176 uint32_t valueCount;
4177 bool singleLineMode;
4180 VmaStringBuilder& m_SB;
4181 VmaVector< StackItem, VmaStlAllocator<StackItem> > m_Stack;
4182 bool m_InsideString;
4184 void BeginValue(
bool isString);
4185 void WriteIndent(
bool oneLess =
false);
4188 const char*
const VmaJsonWriter::INDENT =
" ";
4190 VmaJsonWriter::VmaJsonWriter(
const VkAllocationCallbacks* pAllocationCallbacks, VmaStringBuilder& sb) :
4192 m_Stack(VmaStlAllocator<StackItem>(pAllocationCallbacks)),
4193 m_InsideString(false)
4197 VmaJsonWriter::~VmaJsonWriter()
4199 VMA_ASSERT(!m_InsideString);
4200 VMA_ASSERT(m_Stack.empty());
4203 void VmaJsonWriter::BeginObject(
bool singleLine)
4205 VMA_ASSERT(!m_InsideString);
4211 item.type = COLLECTION_TYPE_OBJECT;
4212 item.valueCount = 0;
4213 item.singleLineMode = singleLine;
4214 m_Stack.push_back(item);
4217 void VmaJsonWriter::EndObject()
4219 VMA_ASSERT(!m_InsideString);
4224 VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_OBJECT);
4228 void VmaJsonWriter::BeginArray(
bool singleLine)
4230 VMA_ASSERT(!m_InsideString);
4236 item.type = COLLECTION_TYPE_ARRAY;
4237 item.valueCount = 0;
4238 item.singleLineMode = singleLine;
4239 m_Stack.push_back(item);
4242 void VmaJsonWriter::EndArray()
4244 VMA_ASSERT(!m_InsideString);
4249 VMA_ASSERT(!m_Stack.empty() && m_Stack.back().type == COLLECTION_TYPE_ARRAY);
4253 void VmaJsonWriter::WriteString(
const char* pStr)
4259 void VmaJsonWriter::BeginString(
const char* pStr)
4261 VMA_ASSERT(!m_InsideString);
4265 m_InsideString =
true;
4266 if(pStr != VMA_NULL && pStr[0] !=
'\0')
4268 ContinueString(pStr);
4272 void VmaJsonWriter::ContinueString(
const char* pStr)
4274 VMA_ASSERT(m_InsideString);
4276 const size_t strLen = strlen(pStr);
4277 for(
size_t i = 0; i < strLen; ++i)
4310 VMA_ASSERT(0 &&
"Character not currently supported.");
4316 void VmaJsonWriter::ContinueString(uint32_t n)
4318 VMA_ASSERT(m_InsideString);
4322 void VmaJsonWriter::ContinueString(uint64_t n)
4324 VMA_ASSERT(m_InsideString);
4328 void VmaJsonWriter::ContinueString_Pointer(
const void* ptr)
4330 VMA_ASSERT(m_InsideString);
4331 m_SB.AddPointer(ptr);
4334 void VmaJsonWriter::EndString(
const char* pStr)
4336 VMA_ASSERT(m_InsideString);
4337 if(pStr != VMA_NULL && pStr[0] !=
'\0')
4339 ContinueString(pStr);
4342 m_InsideString =
false;
4345 void VmaJsonWriter::WriteNumber(uint32_t n)
4347 VMA_ASSERT(!m_InsideString);
4352 void VmaJsonWriter::WriteNumber(uint64_t n)
4354 VMA_ASSERT(!m_InsideString);
4359 void VmaJsonWriter::WriteBool(
bool b)
4361 VMA_ASSERT(!m_InsideString);
4363 m_SB.Add(b ?
"true" :
"false");
4366 void VmaJsonWriter::WriteNull()
4368 VMA_ASSERT(!m_InsideString);
4373 void VmaJsonWriter::BeginValue(
bool isString)
4375 if(!m_Stack.empty())
4377 StackItem& currItem = m_Stack.back();
4378 if(currItem.type == COLLECTION_TYPE_OBJECT &&
4379 currItem.valueCount % 2 == 0)
4381 VMA_ASSERT(isString);
4384 if(currItem.type == COLLECTION_TYPE_OBJECT &&
4385 currItem.valueCount % 2 != 0)
4389 else if(currItem.valueCount > 0)
4398 ++currItem.valueCount;
4402 void VmaJsonWriter::WriteIndent(
bool oneLess)
4404 if(!m_Stack.empty() && !m_Stack.back().singleLineMode)
4408 size_t count = m_Stack.size();
4409 if(count > 0 && oneLess)
4413 for(
size_t i = 0; i < count; ++i)
4420 #endif // #if VMA_STATS_STRING_ENABLED 4424 void VmaAllocation_T::SetUserData(VmaAllocator hAllocator,
void* pUserData)
4426 if(IsUserDataString())
4428 VMA_ASSERT(pUserData == VMA_NULL || pUserData != m_pUserData);
4430 FreeUserDataString(hAllocator);
4432 if(pUserData != VMA_NULL)
4434 const char*
const newStrSrc = (
char*)pUserData;
4435 const size_t newStrLen = strlen(newStrSrc);
4436 char*
const newStrDst = vma_new_array(hAllocator,
char, newStrLen + 1);
4437 memcpy(newStrDst, newStrSrc, newStrLen + 1);
4438 m_pUserData = newStrDst;
4443 m_pUserData = pUserData;
4447 void VmaAllocation_T::ChangeBlockAllocation(
4448 VmaAllocator hAllocator,
4449 VmaDeviceMemoryBlock* block,
4450 VkDeviceSize offset)
4452 VMA_ASSERT(block != VMA_NULL);
4453 VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
4456 if(block != m_BlockAllocation.m_Block)
4458 uint32_t mapRefCount = m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP;
4459 if(IsPersistentMap())
4461 m_BlockAllocation.m_Block->Unmap(hAllocator, mapRefCount);
4462 block->Map(hAllocator, mapRefCount, VMA_NULL);
4465 m_BlockAllocation.m_Block = block;
4466 m_BlockAllocation.m_Offset = offset;
4469 VkDeviceSize VmaAllocation_T::GetOffset()
const 4473 case ALLOCATION_TYPE_BLOCK:
4474 return m_BlockAllocation.m_Offset;
4475 case ALLOCATION_TYPE_DEDICATED:
4483 VkDeviceMemory VmaAllocation_T::GetMemory()
const 4487 case ALLOCATION_TYPE_BLOCK:
4488 return m_BlockAllocation.m_Block->m_hMemory;
4489 case ALLOCATION_TYPE_DEDICATED:
4490 return m_DedicatedAllocation.m_hMemory;
4493 return VK_NULL_HANDLE;
4497 uint32_t VmaAllocation_T::GetMemoryTypeIndex()
const 4501 case ALLOCATION_TYPE_BLOCK:
4502 return m_BlockAllocation.m_Block->m_MemoryTypeIndex;
4503 case ALLOCATION_TYPE_DEDICATED:
4504 return m_DedicatedAllocation.m_MemoryTypeIndex;
4511 void* VmaAllocation_T::GetMappedData()
const 4515 case ALLOCATION_TYPE_BLOCK:
4518 void* pBlockData = m_BlockAllocation.m_Block->m_Mapping.GetMappedData();
4519 VMA_ASSERT(pBlockData != VMA_NULL);
4520 return (
char*)pBlockData + m_BlockAllocation.m_Offset;
4527 case ALLOCATION_TYPE_DEDICATED:
4528 VMA_ASSERT((m_DedicatedAllocation.m_pMappedData != VMA_NULL) == (m_MapCount != 0));
4529 return m_DedicatedAllocation.m_pMappedData;
4536 bool VmaAllocation_T::CanBecomeLost()
const 4540 case ALLOCATION_TYPE_BLOCK:
4541 return m_BlockAllocation.m_CanBecomeLost;
4542 case ALLOCATION_TYPE_DEDICATED:
4550 VmaPool VmaAllocation_T::GetPool()
const 4552 VMA_ASSERT(m_Type == ALLOCATION_TYPE_BLOCK);
4553 return m_BlockAllocation.m_hPool;
4556 bool VmaAllocation_T::MakeLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
4558 VMA_ASSERT(CanBecomeLost());
4564 uint32_t localLastUseFrameIndex = GetLastUseFrameIndex();
4567 if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
4572 else if(localLastUseFrameIndex + frameInUseCount >= currentFrameIndex)
4578 if(CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, VMA_FRAME_INDEX_LOST))
4588 void VmaAllocation_T::FreeUserDataString(VmaAllocator hAllocator)
4590 VMA_ASSERT(IsUserDataString());
4591 if(m_pUserData != VMA_NULL)
4593 char*
const oldStr = (
char*)m_pUserData;
4594 const size_t oldStrLen = strlen(oldStr);
4595 vma_delete_array(hAllocator, oldStr, oldStrLen + 1);
4596 m_pUserData = VMA_NULL;
4600 void VmaAllocation_T::BlockAllocMap()
4602 VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
4604 if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
4610 VMA_ASSERT(0 &&
"Allocation mapped too many times simultaneously.");
4614 void VmaAllocation_T::BlockAllocUnmap()
4616 VMA_ASSERT(GetType() == ALLOCATION_TYPE_BLOCK);
4618 if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
4624 VMA_ASSERT(0 &&
"Unmapping allocation not previously mapped.");
4628 VkResult VmaAllocation_T::DedicatedAllocMap(VmaAllocator hAllocator,
void** ppData)
4630 VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
4634 if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) < 0x7F)
4636 VMA_ASSERT(m_DedicatedAllocation.m_pMappedData != VMA_NULL);
4637 *ppData = m_DedicatedAllocation.m_pMappedData;
4643 VMA_ASSERT(0 &&
"Dedicated allocation mapped too many times simultaneously.");
4644 return VK_ERROR_MEMORY_MAP_FAILED;
4649 VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
4650 hAllocator->m_hDevice,
4651 m_DedicatedAllocation.m_hMemory,
4656 if(result == VK_SUCCESS)
4658 m_DedicatedAllocation.m_pMappedData = *ppData;
4665 void VmaAllocation_T::DedicatedAllocUnmap(VmaAllocator hAllocator)
4667 VMA_ASSERT(GetType() == ALLOCATION_TYPE_DEDICATED);
4669 if((m_MapCount & ~MAP_COUNT_FLAG_PERSISTENT_MAP) != 0)
4674 m_DedicatedAllocation.m_pMappedData = VMA_NULL;
4675 (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(
4676 hAllocator->m_hDevice,
4677 m_DedicatedAllocation.m_hMemory);
4682 VMA_ASSERT(0 &&
"Unmapping dedicated allocation not previously mapped.");
4686 #if VMA_STATS_STRING_ENABLED 4689 static const char* VMA_SUBALLOCATION_TYPE_NAMES[] = {
4698 static void VmaPrintStatInfo(VmaJsonWriter& json,
const VmaStatInfo& stat)
4702 json.WriteString(
"Blocks");
4703 json.WriteNumber(stat.blockCount);
4705 json.WriteString(
"Allocations");
4706 json.WriteNumber(stat.allocationCount);
4708 json.WriteString(
"UnusedRanges");
4709 json.WriteNumber(stat.unusedRangeCount);
4711 json.WriteString(
"UsedBytes");
4712 json.WriteNumber(stat.usedBytes);
4714 json.WriteString(
"UnusedBytes");
4715 json.WriteNumber(stat.unusedBytes);
4717 if(stat.allocationCount > 1)
4719 json.WriteString(
"AllocationSize");
4720 json.BeginObject(
true);
4721 json.WriteString(
"Min");
4722 json.WriteNumber(stat.allocationSizeMin);
4723 json.WriteString(
"Avg");
4724 json.WriteNumber(stat.allocationSizeAvg);
4725 json.WriteString(
"Max");
4726 json.WriteNumber(stat.allocationSizeMax);
4730 if(stat.unusedRangeCount > 1)
4732 json.WriteString(
"UnusedRangeSize");
4733 json.BeginObject(
true);
4734 json.WriteString(
"Min");
4735 json.WriteNumber(stat.unusedRangeSizeMin);
4736 json.WriteString(
"Avg");
4737 json.WriteNumber(stat.unusedRangeSizeAvg);
4738 json.WriteString(
"Max");
4739 json.WriteNumber(stat.unusedRangeSizeMax);
4746 #endif // #if VMA_STATS_STRING_ENABLED 4748 struct VmaSuballocationItemSizeLess
4751 const VmaSuballocationList::iterator lhs,
4752 const VmaSuballocationList::iterator rhs)
const 4754 return lhs->size < rhs->size;
4757 const VmaSuballocationList::iterator lhs,
4758 VkDeviceSize rhsSize)
const 4760 return lhs->size < rhsSize;
4767 VmaBlockMetadata::VmaBlockMetadata(VmaAllocator hAllocator) :
4771 m_Suballocations(VmaStlAllocator<VmaSuballocation>(hAllocator->GetAllocationCallbacks())),
4772 m_FreeSuballocationsBySize(VmaStlAllocator<VmaSuballocationList::iterator>(hAllocator->GetAllocationCallbacks()))
4776 VmaBlockMetadata::~VmaBlockMetadata()
4780 void VmaBlockMetadata::Init(VkDeviceSize size)
4784 m_SumFreeSize = size;
4786 VmaSuballocation suballoc = {};
4787 suballoc.offset = 0;
4788 suballoc.size = size;
4789 suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
4790 suballoc.hAllocation = VK_NULL_HANDLE;
4792 m_Suballocations.push_back(suballoc);
4793 VmaSuballocationList::iterator suballocItem = m_Suballocations.end();
4795 m_FreeSuballocationsBySize.push_back(suballocItem);
4798 bool VmaBlockMetadata::Validate()
const 4800 if(m_Suballocations.empty())
4806 VkDeviceSize calculatedOffset = 0;
4808 uint32_t calculatedFreeCount = 0;
4810 VkDeviceSize calculatedSumFreeSize = 0;
4813 size_t freeSuballocationsToRegister = 0;
4815 bool prevFree =
false;
4817 for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
4818 suballocItem != m_Suballocations.cend();
4821 const VmaSuballocation& subAlloc = *suballocItem;
4824 if(subAlloc.offset != calculatedOffset)
4829 const bool currFree = (subAlloc.type == VMA_SUBALLOCATION_TYPE_FREE);
4831 if(prevFree && currFree)
4836 if(currFree != (subAlloc.hAllocation == VK_NULL_HANDLE))
4843 calculatedSumFreeSize += subAlloc.size;
4844 ++calculatedFreeCount;
4845 if(subAlloc.size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
4847 ++freeSuballocationsToRegister;
4852 if(subAlloc.hAllocation->GetOffset() != subAlloc.offset)
4856 if(subAlloc.hAllocation->GetSize() != subAlloc.size)
4862 calculatedOffset += subAlloc.size;
4863 prevFree = currFree;
4868 if(m_FreeSuballocationsBySize.size() != freeSuballocationsToRegister)
4873 VkDeviceSize lastSize = 0;
4874 for(
size_t i = 0; i < m_FreeSuballocationsBySize.size(); ++i)
4876 VmaSuballocationList::iterator suballocItem = m_FreeSuballocationsBySize[i];
4879 if(suballocItem->type != VMA_SUBALLOCATION_TYPE_FREE)
4884 if(suballocItem->size < lastSize)
4889 lastSize = suballocItem->size;
4893 if(!ValidateFreeSuballocationList() ||
4894 (calculatedOffset != m_Size) ||
4895 (calculatedSumFreeSize != m_SumFreeSize) ||
4896 (calculatedFreeCount != m_FreeCount))
4904 VkDeviceSize VmaBlockMetadata::GetUnusedRangeSizeMax()
const 4906 if(!m_FreeSuballocationsBySize.empty())
4908 return m_FreeSuballocationsBySize.back()->size;
4916 bool VmaBlockMetadata::IsEmpty()
const 4918 return (m_Suballocations.size() == 1) && (m_FreeCount == 1);
4921 void VmaBlockMetadata::CalcAllocationStatInfo(VmaStatInfo& outInfo)
const 4923 outInfo.blockCount = 1;
4925 const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
4926 outInfo.allocationCount = rangeCount - m_FreeCount;
4927 outInfo.unusedRangeCount = m_FreeCount;
4929 outInfo.unusedBytes = m_SumFreeSize;
4930 outInfo.usedBytes = m_Size - outInfo.unusedBytes;
4932 outInfo.allocationSizeMin = UINT64_MAX;
4933 outInfo.allocationSizeMax = 0;
4934 outInfo.unusedRangeSizeMin = UINT64_MAX;
4935 outInfo.unusedRangeSizeMax = 0;
4937 for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
4938 suballocItem != m_Suballocations.cend();
4941 const VmaSuballocation& suballoc = *suballocItem;
4942 if(suballoc.type != VMA_SUBALLOCATION_TYPE_FREE)
4944 outInfo.allocationSizeMin = VMA_MIN(outInfo.allocationSizeMin, suballoc.size);
4945 outInfo.allocationSizeMax = VMA_MAX(outInfo.allocationSizeMax, suballoc.size);
4949 outInfo.unusedRangeSizeMin = VMA_MIN(outInfo.unusedRangeSizeMin, suballoc.size);
4950 outInfo.unusedRangeSizeMax = VMA_MAX(outInfo.unusedRangeSizeMax, suballoc.size);
4955 void VmaBlockMetadata::AddPoolStats(VmaPoolStats& inoutStats)
const 4957 const uint32_t rangeCount = (uint32_t)m_Suballocations.size();
4959 inoutStats.size += m_Size;
4960 inoutStats.unusedSize += m_SumFreeSize;
4961 inoutStats.allocationCount += rangeCount - m_FreeCount;
4962 inoutStats.unusedRangeCount += m_FreeCount;
4963 inoutStats.unusedRangeSizeMax = VMA_MAX(inoutStats.unusedRangeSizeMax, GetUnusedRangeSizeMax());
4966 #if VMA_STATS_STRING_ENABLED 4968 void VmaBlockMetadata::PrintDetailedMap(
class VmaJsonWriter& json)
const 4972 json.WriteString(
"TotalBytes");
4973 json.WriteNumber(m_Size);
4975 json.WriteString(
"UnusedBytes");
4976 json.WriteNumber(m_SumFreeSize);
4978 json.WriteString(
"Allocations");
4979 json.WriteNumber((uint64_t)m_Suballocations.size() - m_FreeCount);
4981 json.WriteString(
"UnusedRanges");
4982 json.WriteNumber(m_FreeCount);
4984 json.WriteString(
"Suballocations");
4987 for(VmaSuballocationList::const_iterator suballocItem = m_Suballocations.cbegin();
4988 suballocItem != m_Suballocations.cend();
4989 ++suballocItem, ++i)
4991 json.BeginObject(
true);
4993 json.WriteString(
"Type");
4994 json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[suballocItem->type]);
4996 json.WriteString(
"Size");
4997 json.WriteNumber(suballocItem->size);
4999 json.WriteString(
"Offset");
5000 json.WriteNumber(suballocItem->offset);
5002 if(suballocItem->type != VMA_SUBALLOCATION_TYPE_FREE)
5004 const void* pUserData = suballocItem->hAllocation->GetUserData();
5005 if(pUserData != VMA_NULL)
5007 json.WriteString(
"UserData");
5008 if(suballocItem->hAllocation->IsUserDataString())
5010 json.WriteString((
const char*)pUserData);
5015 json.ContinueString_Pointer(pUserData);
5028 #endif // #if VMA_STATS_STRING_ENABLED 5040 void VmaBlockMetadata::CreateFirstAllocationRequest(VmaAllocationRequest* pAllocationRequest)
5042 VMA_ASSERT(IsEmpty());
5043 pAllocationRequest->offset = 0;
5044 pAllocationRequest->sumFreeSize = m_SumFreeSize;
5045 pAllocationRequest->sumItemSize = 0;
5046 pAllocationRequest->item = m_Suballocations.begin();
5047 pAllocationRequest->itemsToMakeLostCount = 0;
5050 bool VmaBlockMetadata::CreateAllocationRequest(
5051 uint32_t currentFrameIndex,
5052 uint32_t frameInUseCount,
5053 VkDeviceSize bufferImageGranularity,
5054 VkDeviceSize allocSize,
5055 VkDeviceSize allocAlignment,
5056 VmaSuballocationType allocType,
5057 bool canMakeOtherLost,
5058 VmaAllocationRequest* pAllocationRequest)
5060 VMA_ASSERT(allocSize > 0);
5061 VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
5062 VMA_ASSERT(pAllocationRequest != VMA_NULL);
5063 VMA_HEAVY_ASSERT(Validate());
5066 if(canMakeOtherLost ==
false && m_SumFreeSize < allocSize)
5072 const size_t freeSuballocCount = m_FreeSuballocationsBySize.size();
5073 if(freeSuballocCount > 0)
5078 VmaSuballocationList::iterator*
const it = VmaBinaryFindFirstNotLess(
5079 m_FreeSuballocationsBySize.data(),
5080 m_FreeSuballocationsBySize.data() + freeSuballocCount,
5082 VmaSuballocationItemSizeLess());
5083 size_t index = it - m_FreeSuballocationsBySize.data();
5084 for(; index < freeSuballocCount; ++index)
5089 bufferImageGranularity,
5093 m_FreeSuballocationsBySize[index],
5095 &pAllocationRequest->offset,
5096 &pAllocationRequest->itemsToMakeLostCount,
5097 &pAllocationRequest->sumFreeSize,
5098 &pAllocationRequest->sumItemSize))
5100 pAllocationRequest->item = m_FreeSuballocationsBySize[index];
5108 for(
size_t index = freeSuballocCount; index--; )
5113 bufferImageGranularity,
5117 m_FreeSuballocationsBySize[index],
5119 &pAllocationRequest->offset,
5120 &pAllocationRequest->itemsToMakeLostCount,
5121 &pAllocationRequest->sumFreeSize,
5122 &pAllocationRequest->sumItemSize))
5124 pAllocationRequest->item = m_FreeSuballocationsBySize[index];
5131 if(canMakeOtherLost)
5135 pAllocationRequest->sumFreeSize = VK_WHOLE_SIZE;
5136 pAllocationRequest->sumItemSize = VK_WHOLE_SIZE;
5138 VmaAllocationRequest tmpAllocRequest = {};
5139 for(VmaSuballocationList::iterator suballocIt = m_Suballocations.begin();
5140 suballocIt != m_Suballocations.end();
5143 if(suballocIt->type == VMA_SUBALLOCATION_TYPE_FREE ||
5144 suballocIt->hAllocation->CanBecomeLost())
5149 bufferImageGranularity,
5155 &tmpAllocRequest.offset,
5156 &tmpAllocRequest.itemsToMakeLostCount,
5157 &tmpAllocRequest.sumFreeSize,
5158 &tmpAllocRequest.sumItemSize))
5160 tmpAllocRequest.item = suballocIt;
5162 if(tmpAllocRequest.CalcCost() < pAllocationRequest->CalcCost())
5164 *pAllocationRequest = tmpAllocRequest;
5170 if(pAllocationRequest->sumItemSize != VK_WHOLE_SIZE)
5179 bool VmaBlockMetadata::MakeRequestedAllocationsLost(
5180 uint32_t currentFrameIndex,
5181 uint32_t frameInUseCount,
5182 VmaAllocationRequest* pAllocationRequest)
5184 while(pAllocationRequest->itemsToMakeLostCount > 0)
5186 if(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE)
5188 ++pAllocationRequest->item;
5190 VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
5191 VMA_ASSERT(pAllocationRequest->item->hAllocation != VK_NULL_HANDLE);
5192 VMA_ASSERT(pAllocationRequest->item->hAllocation->CanBecomeLost());
5193 if(pAllocationRequest->item->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
5195 pAllocationRequest->item = FreeSuballocation(pAllocationRequest->item);
5196 --pAllocationRequest->itemsToMakeLostCount;
5204 VMA_HEAVY_ASSERT(Validate());
5205 VMA_ASSERT(pAllocationRequest->item != m_Suballocations.end());
5206 VMA_ASSERT(pAllocationRequest->item->type == VMA_SUBALLOCATION_TYPE_FREE);
5211 uint32_t VmaBlockMetadata::MakeAllocationsLost(uint32_t currentFrameIndex, uint32_t frameInUseCount)
5213 uint32_t lostAllocationCount = 0;
5214 for(VmaSuballocationList::iterator it = m_Suballocations.begin();
5215 it != m_Suballocations.end();
5218 if(it->type != VMA_SUBALLOCATION_TYPE_FREE &&
5219 it->hAllocation->CanBecomeLost() &&
5220 it->hAllocation->MakeLost(currentFrameIndex, frameInUseCount))
5222 it = FreeSuballocation(it);
5223 ++lostAllocationCount;
5226 return lostAllocationCount;
5229 void VmaBlockMetadata::Alloc(
5230 const VmaAllocationRequest& request,
5231 VmaSuballocationType type,
5232 VkDeviceSize allocSize,
5233 VmaAllocation hAllocation)
5235 VMA_ASSERT(request.item != m_Suballocations.end());
5236 VmaSuballocation& suballoc = *request.item;
5238 VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
5240 VMA_ASSERT(request.offset >= suballoc.offset);
5241 const VkDeviceSize paddingBegin = request.offset - suballoc.offset;
5242 VMA_ASSERT(suballoc.size >= paddingBegin + allocSize);
5243 const VkDeviceSize paddingEnd = suballoc.size - paddingBegin - allocSize;
5247 UnregisterFreeSuballocation(request.item);
5249 suballoc.offset = request.offset;
5250 suballoc.size = allocSize;
5251 suballoc.type = type;
5252 suballoc.hAllocation = hAllocation;
5257 VmaSuballocation paddingSuballoc = {};
5258 paddingSuballoc.offset = request.offset + allocSize;
5259 paddingSuballoc.size = paddingEnd;
5260 paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
5261 VmaSuballocationList::iterator next = request.item;
5263 const VmaSuballocationList::iterator paddingEndItem =
5264 m_Suballocations.insert(next, paddingSuballoc);
5265 RegisterFreeSuballocation(paddingEndItem);
5271 VmaSuballocation paddingSuballoc = {};
5272 paddingSuballoc.offset = request.offset - paddingBegin;
5273 paddingSuballoc.size = paddingBegin;
5274 paddingSuballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
5275 const VmaSuballocationList::iterator paddingBeginItem =
5276 m_Suballocations.insert(request.item, paddingSuballoc);
5277 RegisterFreeSuballocation(paddingBeginItem);
5281 m_FreeCount = m_FreeCount - 1;
5282 if(paddingBegin > 0)
5290 m_SumFreeSize -= allocSize;
5293 void VmaBlockMetadata::Free(
const VmaAllocation allocation)
5295 for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
5296 suballocItem != m_Suballocations.end();
5299 VmaSuballocation& suballoc = *suballocItem;
5300 if(suballoc.hAllocation == allocation)
5302 FreeSuballocation(suballocItem);
5303 VMA_HEAVY_ASSERT(Validate());
5307 VMA_ASSERT(0 &&
"Not found!");
5310 void VmaBlockMetadata::FreeAtOffset(VkDeviceSize offset)
5312 for(VmaSuballocationList::iterator suballocItem = m_Suballocations.begin();
5313 suballocItem != m_Suballocations.end();
5316 VmaSuballocation& suballoc = *suballocItem;
5317 if(suballoc.offset == offset)
5319 FreeSuballocation(suballocItem);
5323 VMA_ASSERT(0 &&
"Not found!");
5326 bool VmaBlockMetadata::ValidateFreeSuballocationList()
const 5328 VkDeviceSize lastSize = 0;
5329 for(
size_t i = 0, count = m_FreeSuballocationsBySize.size(); i < count; ++i)
5331 const VmaSuballocationList::iterator it = m_FreeSuballocationsBySize[i];
5333 if(it->type != VMA_SUBALLOCATION_TYPE_FREE)
5338 if(it->size < VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
5343 if(it->size < lastSize)
5349 lastSize = it->size;
5354 bool VmaBlockMetadata::CheckAllocation(
5355 uint32_t currentFrameIndex,
5356 uint32_t frameInUseCount,
5357 VkDeviceSize bufferImageGranularity,
5358 VkDeviceSize allocSize,
5359 VkDeviceSize allocAlignment,
5360 VmaSuballocationType allocType,
5361 VmaSuballocationList::const_iterator suballocItem,
5362 bool canMakeOtherLost,
5363 VkDeviceSize* pOffset,
5364 size_t* itemsToMakeLostCount,
5365 VkDeviceSize* pSumFreeSize,
5366 VkDeviceSize* pSumItemSize)
const 5368 VMA_ASSERT(allocSize > 0);
5369 VMA_ASSERT(allocType != VMA_SUBALLOCATION_TYPE_FREE);
5370 VMA_ASSERT(suballocItem != m_Suballocations.cend());
5371 VMA_ASSERT(pOffset != VMA_NULL);
5373 *itemsToMakeLostCount = 0;
5377 if(canMakeOtherLost)
5379 if(suballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
5381 *pSumFreeSize = suballocItem->size;
5385 if(suballocItem->hAllocation->CanBecomeLost() &&
5386 suballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
5388 ++*itemsToMakeLostCount;
5389 *pSumItemSize = suballocItem->size;
5398 if(m_Size - suballocItem->offset < allocSize)
5404 *pOffset = suballocItem->offset;
5407 if((VMA_DEBUG_MARGIN > 0) && suballocItem != m_Suballocations.cbegin())
5409 *pOffset += VMA_DEBUG_MARGIN;
5413 const VkDeviceSize alignment = VMA_MAX(allocAlignment, static_cast<VkDeviceSize>(VMA_DEBUG_ALIGNMENT));
5414 *pOffset = VmaAlignUp(*pOffset, alignment);
5418 if(bufferImageGranularity > 1)
5420 bool bufferImageGranularityConflict =
false;
5421 VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
5422 while(prevSuballocItem != m_Suballocations.cbegin())
5425 const VmaSuballocation& prevSuballoc = *prevSuballocItem;
5426 if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
5428 if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
5430 bufferImageGranularityConflict =
true;
5438 if(bufferImageGranularityConflict)
5440 *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
5446 if(*pOffset >= suballocItem->offset + suballocItem->size)
5452 const VkDeviceSize paddingBegin = *pOffset - suballocItem->offset;
5455 VmaSuballocationList::const_iterator next = suballocItem;
5457 const VkDeviceSize requiredEndMargin =
5458 (next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0;
5460 const VkDeviceSize totalSize = paddingBegin + allocSize + requiredEndMargin;
5462 if(suballocItem->offset + totalSize > m_Size)
5469 VmaSuballocationList::const_iterator lastSuballocItem = suballocItem;
5470 if(totalSize > suballocItem->size)
5472 VkDeviceSize remainingSize = totalSize - suballocItem->size;
5473 while(remainingSize > 0)
5476 if(lastSuballocItem == m_Suballocations.cend())
5480 if(lastSuballocItem->type == VMA_SUBALLOCATION_TYPE_FREE)
5482 *pSumFreeSize += lastSuballocItem->size;
5486 VMA_ASSERT(lastSuballocItem->hAllocation != VK_NULL_HANDLE);
5487 if(lastSuballocItem->hAllocation->CanBecomeLost() &&
5488 lastSuballocItem->hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
5490 ++*itemsToMakeLostCount;
5491 *pSumItemSize += lastSuballocItem->size;
5498 remainingSize = (lastSuballocItem->size < remainingSize) ?
5499 remainingSize - lastSuballocItem->size : 0;
5505 if(bufferImageGranularity > 1)
5507 VmaSuballocationList::const_iterator nextSuballocItem = lastSuballocItem;
5509 while(nextSuballocItem != m_Suballocations.cend())
5511 const VmaSuballocation& nextSuballoc = *nextSuballocItem;
5512 if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
5514 if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
5516 VMA_ASSERT(nextSuballoc.hAllocation != VK_NULL_HANDLE);
5517 if(nextSuballoc.hAllocation->CanBecomeLost() &&
5518 nextSuballoc.hAllocation->GetLastUseFrameIndex() + frameInUseCount < currentFrameIndex)
5520 ++*itemsToMakeLostCount;
5539 const VmaSuballocation& suballoc = *suballocItem;
5540 VMA_ASSERT(suballoc.type == VMA_SUBALLOCATION_TYPE_FREE);
5542 *pSumFreeSize = suballoc.size;
5545 if(suballoc.size < allocSize)
5551 *pOffset = suballoc.offset;
5554 if((VMA_DEBUG_MARGIN > 0) && suballocItem != m_Suballocations.cbegin())
5556 *pOffset += VMA_DEBUG_MARGIN;
5560 const VkDeviceSize alignment = VMA_MAX(allocAlignment, static_cast<VkDeviceSize>(VMA_DEBUG_ALIGNMENT));
5561 *pOffset = VmaAlignUp(*pOffset, alignment);
5565 if(bufferImageGranularity > 1)
5567 bool bufferImageGranularityConflict =
false;
5568 VmaSuballocationList::const_iterator prevSuballocItem = suballocItem;
5569 while(prevSuballocItem != m_Suballocations.cbegin())
5572 const VmaSuballocation& prevSuballoc = *prevSuballocItem;
5573 if(VmaBlocksOnSamePage(prevSuballoc.offset, prevSuballoc.size, *pOffset, bufferImageGranularity))
5575 if(VmaIsBufferImageGranularityConflict(prevSuballoc.type, allocType))
5577 bufferImageGranularityConflict =
true;
5585 if(bufferImageGranularityConflict)
5587 *pOffset = VmaAlignUp(*pOffset, bufferImageGranularity);
5592 const VkDeviceSize paddingBegin = *pOffset - suballoc.offset;
5595 VmaSuballocationList::const_iterator next = suballocItem;
5597 const VkDeviceSize requiredEndMargin =
5598 (next != m_Suballocations.cend()) ? VMA_DEBUG_MARGIN : 0;
5601 if(paddingBegin + allocSize + requiredEndMargin > suballoc.size)
5608 if(bufferImageGranularity > 1)
5610 VmaSuballocationList::const_iterator nextSuballocItem = suballocItem;
5612 while(nextSuballocItem != m_Suballocations.cend())
5614 const VmaSuballocation& nextSuballoc = *nextSuballocItem;
5615 if(VmaBlocksOnSamePage(*pOffset, allocSize, nextSuballoc.offset, bufferImageGranularity))
5617 if(VmaIsBufferImageGranularityConflict(allocType, nextSuballoc.type))
5636 void VmaBlockMetadata::MergeFreeWithNext(VmaSuballocationList::iterator item)
5638 VMA_ASSERT(item != m_Suballocations.end());
5639 VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
5641 VmaSuballocationList::iterator nextItem = item;
5643 VMA_ASSERT(nextItem != m_Suballocations.end());
5644 VMA_ASSERT(nextItem->type == VMA_SUBALLOCATION_TYPE_FREE);
5646 item->size += nextItem->size;
5648 m_Suballocations.erase(nextItem);
5651 VmaSuballocationList::iterator VmaBlockMetadata::FreeSuballocation(VmaSuballocationList::iterator suballocItem)
5654 VmaSuballocation& suballoc = *suballocItem;
5655 suballoc.type = VMA_SUBALLOCATION_TYPE_FREE;
5656 suballoc.hAllocation = VK_NULL_HANDLE;
5660 m_SumFreeSize += suballoc.size;
5663 bool mergeWithNext =
false;
5664 bool mergeWithPrev =
false;
5666 VmaSuballocationList::iterator nextItem = suballocItem;
5668 if((nextItem != m_Suballocations.end()) && (nextItem->type == VMA_SUBALLOCATION_TYPE_FREE))
5670 mergeWithNext =
true;
5673 VmaSuballocationList::iterator prevItem = suballocItem;
5674 if(suballocItem != m_Suballocations.begin())
5677 if(prevItem->type == VMA_SUBALLOCATION_TYPE_FREE)
5679 mergeWithPrev =
true;
5685 UnregisterFreeSuballocation(nextItem);
5686 MergeFreeWithNext(suballocItem);
5691 UnregisterFreeSuballocation(prevItem);
5692 MergeFreeWithNext(prevItem);
5693 RegisterFreeSuballocation(prevItem);
5698 RegisterFreeSuballocation(suballocItem);
5699 return suballocItem;
5703 void VmaBlockMetadata::RegisterFreeSuballocation(VmaSuballocationList::iterator item)
5705 VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
5706 VMA_ASSERT(item->size > 0);
5710 VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
5712 if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
5714 if(m_FreeSuballocationsBySize.empty())
5716 m_FreeSuballocationsBySize.push_back(item);
5720 VmaVectorInsertSorted<VmaSuballocationItemSizeLess>(m_FreeSuballocationsBySize, item);
5728 void VmaBlockMetadata::UnregisterFreeSuballocation(VmaSuballocationList::iterator item)
5730 VMA_ASSERT(item->type == VMA_SUBALLOCATION_TYPE_FREE);
5731 VMA_ASSERT(item->size > 0);
5735 VMA_HEAVY_ASSERT(ValidateFreeSuballocationList());
5737 if(item->size >= VMA_MIN_FREE_SUBALLOCATION_SIZE_TO_REGISTER)
5739 VmaSuballocationList::iterator*
const it = VmaBinaryFindFirstNotLess(
5740 m_FreeSuballocationsBySize.data(),
5741 m_FreeSuballocationsBySize.data() + m_FreeSuballocationsBySize.size(),
5743 VmaSuballocationItemSizeLess());
5744 for(
size_t index = it - m_FreeSuballocationsBySize.data();
5745 index < m_FreeSuballocationsBySize.size();
5748 if(m_FreeSuballocationsBySize[index] == item)
5750 VmaVectorRemove(m_FreeSuballocationsBySize, index);
5753 VMA_ASSERT((m_FreeSuballocationsBySize[index]->size == item->size) &&
"Not found.");
5755 VMA_ASSERT(0 &&
"Not found.");
5764 VmaDeviceMemoryMapping::VmaDeviceMemoryMapping() :
5766 m_pMappedData(VMA_NULL)
5770 VmaDeviceMemoryMapping::~VmaDeviceMemoryMapping()
5772 VMA_ASSERT(m_MapCount == 0 &&
"VkDeviceMemory block is being destroyed while it is still mapped.");
5775 VkResult VmaDeviceMemoryMapping::Map(VmaAllocator hAllocator, VkDeviceMemory hMemory, uint32_t count,
void **ppData)
5782 VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
5785 m_MapCount += count;
5786 VMA_ASSERT(m_pMappedData != VMA_NULL);
5787 if(ppData != VMA_NULL)
5789 *ppData = m_pMappedData;
5795 VkResult result = (*hAllocator->GetVulkanFunctions().vkMapMemory)(
5796 hAllocator->m_hDevice,
5802 if(result == VK_SUCCESS)
5804 if(ppData != VMA_NULL)
5806 *ppData = m_pMappedData;
5814 void VmaDeviceMemoryMapping::Unmap(VmaAllocator hAllocator, VkDeviceMemory hMemory, uint32_t count)
5821 VmaMutexLock lock(m_Mutex, hAllocator->m_UseMutex);
5822 if(m_MapCount >= count)
5824 m_MapCount -= count;
5827 m_pMappedData = VMA_NULL;
5828 (*hAllocator->GetVulkanFunctions().vkUnmapMemory)(hAllocator->m_hDevice, hMemory);
5833 VMA_ASSERT(0 &&
"VkDeviceMemory block is being unmapped while it was not previously mapped.");
5840 VmaDeviceMemoryBlock::VmaDeviceMemoryBlock(VmaAllocator hAllocator) :
5841 m_MemoryTypeIndex(UINT32_MAX),
5842 m_hMemory(VK_NULL_HANDLE),
5843 m_Metadata(hAllocator)
5847 void VmaDeviceMemoryBlock::Init(
5848 uint32_t newMemoryTypeIndex,
5849 VkDeviceMemory newMemory,
5850 VkDeviceSize newSize)
5852 VMA_ASSERT(m_hMemory == VK_NULL_HANDLE);
5854 m_MemoryTypeIndex = newMemoryTypeIndex;
5855 m_hMemory = newMemory;
5857 m_Metadata.Init(newSize);
5860 void VmaDeviceMemoryBlock::Destroy(VmaAllocator allocator)
5864 VMA_ASSERT(m_Metadata.IsEmpty() &&
"Some allocations were not freed before destruction of this memory block!");
5866 VMA_ASSERT(m_hMemory != VK_NULL_HANDLE);
5867 allocator->FreeVulkanMemory(m_MemoryTypeIndex, m_Metadata.GetSize(), m_hMemory);
5868 m_hMemory = VK_NULL_HANDLE;
5871 bool VmaDeviceMemoryBlock::Validate()
const 5873 if((m_hMemory == VK_NULL_HANDLE) ||
5874 (m_Metadata.GetSize() == 0))
5879 return m_Metadata.Validate();
5882 VkResult VmaDeviceMemoryBlock::Map(VmaAllocator hAllocator, uint32_t count,
void** ppData)
5884 return m_Mapping.Map(hAllocator, m_hMemory, count, ppData);
5887 void VmaDeviceMemoryBlock::Unmap(VmaAllocator hAllocator, uint32_t count)
5889 m_Mapping.Unmap(hAllocator, m_hMemory, count);
5892 static void InitStatInfo(VmaStatInfo& outInfo)
5894 memset(&outInfo, 0,
sizeof(outInfo));
5895 outInfo.allocationSizeMin = UINT64_MAX;
5896 outInfo.unusedRangeSizeMin = UINT64_MAX;
5900 static void VmaAddStatInfo(VmaStatInfo& inoutInfo,
const VmaStatInfo& srcInfo)
5902 inoutInfo.blockCount += srcInfo.blockCount;
5903 inoutInfo.allocationCount += srcInfo.allocationCount;
5904 inoutInfo.unusedRangeCount += srcInfo.unusedRangeCount;
5905 inoutInfo.usedBytes += srcInfo.usedBytes;
5906 inoutInfo.unusedBytes += srcInfo.unusedBytes;
5907 inoutInfo.allocationSizeMin = VMA_MIN(inoutInfo.allocationSizeMin, srcInfo.allocationSizeMin);
5908 inoutInfo.allocationSizeMax = VMA_MAX(inoutInfo.allocationSizeMax, srcInfo.allocationSizeMax);
5909 inoutInfo.unusedRangeSizeMin = VMA_MIN(inoutInfo.unusedRangeSizeMin, srcInfo.unusedRangeSizeMin);
5910 inoutInfo.unusedRangeSizeMax = VMA_MAX(inoutInfo.unusedRangeSizeMax, srcInfo.unusedRangeSizeMax);
5913 static void VmaPostprocessCalcStatInfo(VmaStatInfo& inoutInfo)
5915 inoutInfo.allocationSizeAvg = (inoutInfo.allocationCount > 0) ?
5916 VmaRoundDiv<VkDeviceSize>(inoutInfo.usedBytes, inoutInfo.allocationCount) : 0;
5917 inoutInfo.unusedRangeSizeAvg = (inoutInfo.unusedRangeCount > 0) ?
5918 VmaRoundDiv<VkDeviceSize>(inoutInfo.unusedBytes, inoutInfo.unusedRangeCount) : 0;
5921 VmaPool_T::VmaPool_T(
5922 VmaAllocator hAllocator,
5923 const VmaPoolCreateInfo& createInfo) :
5926 createInfo.memoryTypeIndex,
5927 createInfo.blockSize,
5928 createInfo.minBlockCount,
5929 createInfo.maxBlockCount,
5930 (createInfo.flags & VMA_POOL_CREATE_IGNORE_BUFFER_IMAGE_GRANULARITY_BIT) != 0 ? 1 : hAllocator->GetBufferImageGranularity(),
5931 createInfo.frameInUseCount,
5936 VmaPool_T::~VmaPool_T()
5940 #if VMA_STATS_STRING_ENABLED 5942 #endif // #if VMA_STATS_STRING_ENABLED 5944 VmaBlockVector::VmaBlockVector(
5945 VmaAllocator hAllocator,
5946 uint32_t memoryTypeIndex,
5947 VkDeviceSize preferredBlockSize,
5948 size_t minBlockCount,
5949 size_t maxBlockCount,
5950 VkDeviceSize bufferImageGranularity,
5951 uint32_t frameInUseCount,
5952 bool isCustomPool) :
5953 m_hAllocator(hAllocator),
5954 m_MemoryTypeIndex(memoryTypeIndex),
5955 m_PreferredBlockSize(preferredBlockSize),
5956 m_MinBlockCount(minBlockCount),
5957 m_MaxBlockCount(maxBlockCount),
5958 m_BufferImageGranularity(bufferImageGranularity),
5959 m_FrameInUseCount(frameInUseCount),
5960 m_IsCustomPool(isCustomPool),
5961 m_Blocks(VmaStlAllocator<VmaDeviceMemoryBlock*>(hAllocator->GetAllocationCallbacks())),
5962 m_HasEmptyBlock(false),
5963 m_pDefragmentator(VMA_NULL)
5967 VmaBlockVector::~VmaBlockVector()
5969 VMA_ASSERT(m_pDefragmentator == VMA_NULL);
5971 for(
size_t i = m_Blocks.size(); i--; )
5973 m_Blocks[i]->Destroy(m_hAllocator);
5974 vma_delete(m_hAllocator, m_Blocks[i]);
5978 VkResult VmaBlockVector::CreateMinBlocks()
5980 for(
size_t i = 0; i < m_MinBlockCount; ++i)
5982 VkResult res = CreateBlock(m_PreferredBlockSize, VMA_NULL);
5983 if(res != VK_SUCCESS)
5991 void VmaBlockVector::GetPoolStats(VmaPoolStats* pStats)
5994 pStats->unusedSize = 0;
5995 pStats->allocationCount = 0;
5996 pStats->unusedRangeCount = 0;
5997 pStats->unusedRangeSizeMax = 0;
5999 VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
6001 for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
6003 const VmaDeviceMemoryBlock*
const pBlock = m_Blocks[blockIndex];
6005 VMA_HEAVY_ASSERT(pBlock->Validate());
6006 pBlock->m_Metadata.AddPoolStats(*pStats);
6010 static const uint32_t VMA_ALLOCATION_TRY_COUNT = 32;
6012 VkResult VmaBlockVector::Allocate(
6013 VmaPool hCurrentPool,
6014 uint32_t currentFrameIndex,
6015 const VkMemoryRequirements& vkMemReq,
6016 const VmaAllocationCreateInfo& createInfo,
6017 VmaSuballocationType suballocType,
6018 VmaAllocation* pAllocation)
6020 const bool mapped = (createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0;
6021 const bool isUserDataString = (createInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0;
6023 VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
6027 for(
size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
6029 VmaDeviceMemoryBlock*
const pCurrBlock = m_Blocks[blockIndex];
6030 VMA_ASSERT(pCurrBlock);
6031 VmaAllocationRequest currRequest = {};
6032 if(pCurrBlock->m_Metadata.CreateAllocationRequest(
6035 m_BufferImageGranularity,
6043 VMA_ASSERT(currRequest.itemsToMakeLostCount == 0);
6047 VkResult res = pCurrBlock->Map(m_hAllocator, 1, VMA_NULL);
6048 if(res != VK_SUCCESS)
6055 if(pCurrBlock->m_Metadata.IsEmpty())
6057 m_HasEmptyBlock =
false;
6060 *pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString);
6061 pCurrBlock->m_Metadata.Alloc(currRequest, suballocType, vkMemReq.size, *pAllocation);
6062 (*pAllocation)->InitBlockAllocation(
6070 (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
6071 VMA_HEAVY_ASSERT(pCurrBlock->Validate());
6072 VMA_DEBUG_LOG(
" Returned from existing allocation #%u", (uint32_t)blockIndex);
6073 (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
6078 const bool canCreateNewBlock =
6079 ((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0) &&
6080 (m_Blocks.size() < m_MaxBlockCount);
6083 if(canCreateNewBlock)
6086 VkDeviceSize newBlockSize = m_PreferredBlockSize;
6087 uint32_t newBlockSizeShift = 0;
6088 const uint32_t NEW_BLOCK_SIZE_SHIFT_MAX = 3;
6092 if(m_IsCustomPool ==
false)
6095 const VkDeviceSize maxExistingBlockSize = CalcMaxBlockSize();
6096 for(uint32_t i = 0; i < NEW_BLOCK_SIZE_SHIFT_MAX; ++i)
6098 const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
6099 if(smallerNewBlockSize > maxExistingBlockSize && smallerNewBlockSize >= vkMemReq.size * 2)
6101 newBlockSize = smallerNewBlockSize;
6102 ++newBlockSizeShift;
6111 size_t newBlockIndex = 0;
6112 VkResult res = CreateBlock(newBlockSize, &newBlockIndex);
6114 if(m_IsCustomPool ==
false)
6116 while(res < 0 && newBlockSizeShift < NEW_BLOCK_SIZE_SHIFT_MAX)
6118 const VkDeviceSize smallerNewBlockSize = newBlockSize / 2;
6119 if(smallerNewBlockSize >= vkMemReq.size)
6121 newBlockSize = smallerNewBlockSize;
6122 ++newBlockSizeShift;
6123 res = CreateBlock(newBlockSize, &newBlockIndex);
6132 if(res == VK_SUCCESS)
6134 VmaDeviceMemoryBlock*
const pBlock = m_Blocks[newBlockIndex];
6135 VMA_ASSERT(pBlock->m_Metadata.GetSize() >= vkMemReq.size);
6139 res = pBlock->Map(m_hAllocator, 1, VMA_NULL);
6140 if(res != VK_SUCCESS)
6147 VmaAllocationRequest allocRequest;
6148 pBlock->m_Metadata.CreateFirstAllocationRequest(&allocRequest);
6149 *pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString);
6150 pBlock->m_Metadata.Alloc(allocRequest, suballocType, vkMemReq.size, *pAllocation);
6151 (*pAllocation)->InitBlockAllocation(
6154 allocRequest.offset,
6159 (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
6160 VMA_HEAVY_ASSERT(pBlock->Validate());
6161 VMA_DEBUG_LOG(
" Created new allocation Size=%llu", allocInfo.allocationSize);
6162 (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
6167 const bool canMakeOtherLost = (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_MAKE_OTHER_LOST_BIT) != 0;
6170 if(canMakeOtherLost)
6172 uint32_t tryIndex = 0;
6173 for(; tryIndex < VMA_ALLOCATION_TRY_COUNT; ++tryIndex)
6175 VmaDeviceMemoryBlock* pBestRequestBlock = VMA_NULL;
6176 VmaAllocationRequest bestRequest = {};
6177 VkDeviceSize bestRequestCost = VK_WHOLE_SIZE;
6181 for(
size_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex )
6183 VmaDeviceMemoryBlock*
const pCurrBlock = m_Blocks[blockIndex];
6184 VMA_ASSERT(pCurrBlock);
6185 VmaAllocationRequest currRequest = {};
6186 if(pCurrBlock->m_Metadata.CreateAllocationRequest(
6189 m_BufferImageGranularity,
6196 const VkDeviceSize currRequestCost = currRequest.CalcCost();
6197 if(pBestRequestBlock == VMA_NULL ||
6198 currRequestCost < bestRequestCost)
6200 pBestRequestBlock = pCurrBlock;
6201 bestRequest = currRequest;
6202 bestRequestCost = currRequestCost;
6204 if(bestRequestCost == 0)
6212 if(pBestRequestBlock != VMA_NULL)
6216 VkResult res = pBestRequestBlock->Map(m_hAllocator, 1, VMA_NULL);
6217 if(res != VK_SUCCESS)
6223 if(pBestRequestBlock->m_Metadata.MakeRequestedAllocationsLost(
6229 if(pBestRequestBlock->m_Metadata.IsEmpty())
6231 m_HasEmptyBlock =
false;
6234 *pAllocation = vma_new(m_hAllocator, VmaAllocation_T)(currentFrameIndex, isUserDataString);
6235 pBestRequestBlock->m_Metadata.Alloc(bestRequest, suballocType, vkMemReq.size, *pAllocation);
6236 (*pAllocation)->InitBlockAllocation(
6244 (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0);
6245 VMA_HEAVY_ASSERT(pBestRequestBlock->Validate());
6246 VMA_DEBUG_LOG(
" Returned from existing allocation #%u", (uint32_t)blockIndex);
6247 (*pAllocation)->SetUserData(m_hAllocator, createInfo.pUserData);
6261 if(tryIndex == VMA_ALLOCATION_TRY_COUNT)
6263 return VK_ERROR_TOO_MANY_OBJECTS;
6267 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
6270 void VmaBlockVector::Free(
6271 VmaAllocation hAllocation)
6273 VmaDeviceMemoryBlock* pBlockToDelete = VMA_NULL;
6277 VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
6279 VmaDeviceMemoryBlock* pBlock = hAllocation->GetBlock();
6281 if(hAllocation->IsPersistentMap())
6283 pBlock->m_Mapping.Unmap(m_hAllocator, pBlock->m_hMemory, 1);
6286 pBlock->m_Metadata.Free(hAllocation);
6287 VMA_HEAVY_ASSERT(pBlock->Validate());
6289 VMA_DEBUG_LOG(
" Freed from MemoryTypeIndex=%u", memTypeIndex);
6292 if(pBlock->m_Metadata.IsEmpty())
6295 if(m_HasEmptyBlock && m_Blocks.size() > m_MinBlockCount)
6297 pBlockToDelete = pBlock;
6303 m_HasEmptyBlock =
true;
6308 else if(m_HasEmptyBlock)
6310 VmaDeviceMemoryBlock* pLastBlock = m_Blocks.back();
6311 if(pLastBlock->m_Metadata.IsEmpty() && m_Blocks.size() > m_MinBlockCount)
6313 pBlockToDelete = pLastBlock;
6314 m_Blocks.pop_back();
6315 m_HasEmptyBlock =
false;
6319 IncrementallySortBlocks();
6324 if(pBlockToDelete != VMA_NULL)
6326 VMA_DEBUG_LOG(
" Deleted empty allocation");
6327 pBlockToDelete->Destroy(m_hAllocator);
6328 vma_delete(m_hAllocator, pBlockToDelete);
6332 size_t VmaBlockVector::CalcMaxBlockSize()
const 6335 for(
size_t i = m_Blocks.size(); i--; )
6337 result = VMA_MAX((uint64_t)result, (uint64_t)m_Blocks[i]->m_Metadata.GetSize());
6338 if(result >= m_PreferredBlockSize)
6346 void VmaBlockVector::Remove(VmaDeviceMemoryBlock* pBlock)
6348 for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
6350 if(m_Blocks[blockIndex] == pBlock)
6352 VmaVectorRemove(m_Blocks, blockIndex);
6359 void VmaBlockVector::IncrementallySortBlocks()
6362 for(
size_t i = 1; i < m_Blocks.size(); ++i)
6364 if(m_Blocks[i - 1]->m_Metadata.GetSumFreeSize() > m_Blocks[i]->m_Metadata.GetSumFreeSize())
6366 VMA_SWAP(m_Blocks[i - 1], m_Blocks[i]);
6372 VkResult VmaBlockVector::CreateBlock(VkDeviceSize blockSize,
size_t* pNewBlockIndex)
6374 VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
6375 allocInfo.memoryTypeIndex = m_MemoryTypeIndex;
6376 allocInfo.allocationSize = blockSize;
6377 VkDeviceMemory mem = VK_NULL_HANDLE;
6378 VkResult res = m_hAllocator->AllocateVulkanMemory(&allocInfo, &mem);
6387 VmaDeviceMemoryBlock*
const pBlock = vma_new(m_hAllocator, VmaDeviceMemoryBlock)(m_hAllocator);
6391 allocInfo.allocationSize);
6393 m_Blocks.push_back(pBlock);
6394 if(pNewBlockIndex != VMA_NULL)
6396 *pNewBlockIndex = m_Blocks.size() - 1;
6402 #if VMA_STATS_STRING_ENABLED 6404 void VmaBlockVector::PrintDetailedMap(
class VmaJsonWriter& json)
6406 VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
6412 json.WriteString(
"MemoryTypeIndex");
6413 json.WriteNumber(m_MemoryTypeIndex);
6415 json.WriteString(
"BlockSize");
6416 json.WriteNumber(m_PreferredBlockSize);
6418 json.WriteString(
"BlockCount");
6419 json.BeginObject(
true);
6420 if(m_MinBlockCount > 0)
6422 json.WriteString(
"Min");
6423 json.WriteNumber((uint64_t)m_MinBlockCount);
6425 if(m_MaxBlockCount < SIZE_MAX)
6427 json.WriteString(
"Max");
6428 json.WriteNumber((uint64_t)m_MaxBlockCount);
6430 json.WriteString(
"Cur");
6431 json.WriteNumber((uint64_t)m_Blocks.size());
6434 if(m_FrameInUseCount > 0)
6436 json.WriteString(
"FrameInUseCount");
6437 json.WriteNumber(m_FrameInUseCount);
6442 json.WriteString(
"PreferredBlockSize");
6443 json.WriteNumber(m_PreferredBlockSize);
6446 json.WriteString(
"Blocks");
6448 for(
size_t i = 0; i < m_Blocks.size(); ++i)
6450 m_Blocks[i]->m_Metadata.PrintDetailedMap(json);
6457 #endif // #if VMA_STATS_STRING_ENABLED 6459 VmaDefragmentator* VmaBlockVector::EnsureDefragmentator(
6460 VmaAllocator hAllocator,
6461 uint32_t currentFrameIndex)
6463 if(m_pDefragmentator == VMA_NULL)
6465 m_pDefragmentator = vma_new(m_hAllocator, VmaDefragmentator)(
6471 return m_pDefragmentator;
6474 VkResult VmaBlockVector::Defragment(
6475 VmaDefragmentationStats* pDefragmentationStats,
6476 VkDeviceSize& maxBytesToMove,
6477 uint32_t& maxAllocationsToMove)
6479 if(m_pDefragmentator == VMA_NULL)
6484 VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
6487 VkResult result = m_pDefragmentator->Defragment(maxBytesToMove, maxAllocationsToMove);
6490 if(pDefragmentationStats != VMA_NULL)
6492 const VkDeviceSize bytesMoved = m_pDefragmentator->GetBytesMoved();
6493 const uint32_t allocationsMoved = m_pDefragmentator->GetAllocationsMoved();
6494 pDefragmentationStats->bytesMoved += bytesMoved;
6495 pDefragmentationStats->allocationsMoved += allocationsMoved;
6496 VMA_ASSERT(bytesMoved <= maxBytesToMove);
6497 VMA_ASSERT(allocationsMoved <= maxAllocationsToMove);
6498 maxBytesToMove -= bytesMoved;
6499 maxAllocationsToMove -= allocationsMoved;
6503 m_HasEmptyBlock =
false;
6504 for(
size_t blockIndex = m_Blocks.size(); blockIndex--; )
6506 VmaDeviceMemoryBlock* pBlock = m_Blocks[blockIndex];
6507 if(pBlock->m_Metadata.IsEmpty())
6509 if(m_Blocks.size() > m_MinBlockCount)
6511 if(pDefragmentationStats != VMA_NULL)
6513 ++pDefragmentationStats->deviceMemoryBlocksFreed;
6514 pDefragmentationStats->bytesFreed += pBlock->m_Metadata.GetSize();
6517 VmaVectorRemove(m_Blocks, blockIndex);
6518 pBlock->Destroy(m_hAllocator);
6519 vma_delete(m_hAllocator, pBlock);
6523 m_HasEmptyBlock =
true;
6531 void VmaBlockVector::DestroyDefragmentator()
6533 if(m_pDefragmentator != VMA_NULL)
6535 vma_delete(m_hAllocator, m_pDefragmentator);
6536 m_pDefragmentator = VMA_NULL;
6540 void VmaBlockVector::MakePoolAllocationsLost(
6541 uint32_t currentFrameIndex,
6542 size_t* pLostAllocationCount)
6544 VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
6545 size_t lostAllocationCount = 0;
6546 for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
6548 VmaDeviceMemoryBlock*
const pBlock = m_Blocks[blockIndex];
6550 lostAllocationCount += pBlock->m_Metadata.MakeAllocationsLost(currentFrameIndex, m_FrameInUseCount);
6552 if(pLostAllocationCount != VMA_NULL)
6554 *pLostAllocationCount = lostAllocationCount;
6558 void VmaBlockVector::AddStats(VmaStats* pStats)
6560 const uint32_t memTypeIndex = m_MemoryTypeIndex;
6561 const uint32_t memHeapIndex = m_hAllocator->MemoryTypeIndexToHeapIndex(memTypeIndex);
6563 VmaMutexLock lock(m_Mutex, m_hAllocator->m_UseMutex);
6565 for(uint32_t blockIndex = 0; blockIndex < m_Blocks.size(); ++blockIndex)
6567 const VmaDeviceMemoryBlock*
const pBlock = m_Blocks[blockIndex];
6569 VMA_HEAVY_ASSERT(pBlock->Validate());
6570 VmaStatInfo allocationStatInfo;
6571 pBlock->m_Metadata.CalcAllocationStatInfo(allocationStatInfo);
6572 VmaAddStatInfo(pStats->total, allocationStatInfo);
6573 VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
6574 VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
6581 VmaDefragmentator::VmaDefragmentator(
6582 VmaAllocator hAllocator,
6583 VmaBlockVector* pBlockVector,
6584 uint32_t currentFrameIndex) :
6585 m_hAllocator(hAllocator),
6586 m_pBlockVector(pBlockVector),
6587 m_CurrentFrameIndex(currentFrameIndex),
6589 m_AllocationsMoved(0),
6590 m_Allocations(VmaStlAllocator<AllocationInfo>(hAllocator->GetAllocationCallbacks())),
6591 m_Blocks(VmaStlAllocator<BlockInfo*>(hAllocator->GetAllocationCallbacks()))
6595 VmaDefragmentator::~VmaDefragmentator()
6597 for(
size_t i = m_Blocks.size(); i--; )
6599 vma_delete(m_hAllocator, m_Blocks[i]);
6603 void VmaDefragmentator::AddAllocation(VmaAllocation hAlloc, VkBool32* pChanged)
6605 AllocationInfo allocInfo;
6606 allocInfo.m_hAllocation = hAlloc;
6607 allocInfo.m_pChanged = pChanged;
6608 m_Allocations.push_back(allocInfo);
6611 VkResult VmaDefragmentator::BlockInfo::EnsureMapping(VmaAllocator hAllocator,
void** ppMappedData)
6614 if(m_pMappedDataForDefragmentation)
6616 *ppMappedData = m_pMappedDataForDefragmentation;
6621 if(m_pBlock->m_Mapping.GetMappedData())
6623 *ppMappedData = m_pBlock->m_Mapping.GetMappedData();
6628 VkResult res = m_pBlock->Map(hAllocator, 1, &m_pMappedDataForDefragmentation);
6629 *ppMappedData = m_pMappedDataForDefragmentation;
6633 void VmaDefragmentator::BlockInfo::Unmap(VmaAllocator hAllocator)
6635 if(m_pMappedDataForDefragmentation != VMA_NULL)
6637 m_pBlock->Unmap(hAllocator, 1);
6641 VkResult VmaDefragmentator::DefragmentRound(
6642 VkDeviceSize maxBytesToMove,
6643 uint32_t maxAllocationsToMove)
6645 if(m_Blocks.empty())
6650 size_t srcBlockIndex = m_Blocks.size() - 1;
6651 size_t srcAllocIndex = SIZE_MAX;
6657 while(srcAllocIndex >= m_Blocks[srcBlockIndex]->m_Allocations.size())
6659 if(m_Blocks[srcBlockIndex]->m_Allocations.empty())
6662 if(srcBlockIndex == 0)
6669 srcAllocIndex = SIZE_MAX;
6674 srcAllocIndex = m_Blocks[srcBlockIndex]->m_Allocations.size() - 1;
6678 BlockInfo* pSrcBlockInfo = m_Blocks[srcBlockIndex];
6679 AllocationInfo& allocInfo = pSrcBlockInfo->m_Allocations[srcAllocIndex];
6681 const VkDeviceSize size = allocInfo.m_hAllocation->GetSize();
6682 const VkDeviceSize srcOffset = allocInfo.m_hAllocation->GetOffset();
6683 const VkDeviceSize alignment = allocInfo.m_hAllocation->GetAlignment();
6684 const VmaSuballocationType suballocType = allocInfo.m_hAllocation->GetSuballocationType();
6687 for(
size_t dstBlockIndex = 0; dstBlockIndex <= srcBlockIndex; ++dstBlockIndex)
6689 BlockInfo* pDstBlockInfo = m_Blocks[dstBlockIndex];
6690 VmaAllocationRequest dstAllocRequest;
6691 if(pDstBlockInfo->m_pBlock->m_Metadata.CreateAllocationRequest(
6692 m_CurrentFrameIndex,
6693 m_pBlockVector->GetFrameInUseCount(),
6694 m_pBlockVector->GetBufferImageGranularity(),
6699 &dstAllocRequest) &&
6701 dstBlockIndex, dstAllocRequest.offset, srcBlockIndex, srcOffset))
6703 VMA_ASSERT(dstAllocRequest.itemsToMakeLostCount == 0);
6706 if((m_AllocationsMoved + 1 > maxAllocationsToMove) ||
6707 (m_BytesMoved + size > maxBytesToMove))
6709 return VK_INCOMPLETE;
6712 void* pDstMappedData = VMA_NULL;
6713 VkResult res = pDstBlockInfo->EnsureMapping(m_hAllocator, &pDstMappedData);
6714 if(res != VK_SUCCESS)
6719 void* pSrcMappedData = VMA_NULL;
6720 res = pSrcBlockInfo->EnsureMapping(m_hAllocator, &pSrcMappedData);
6721 if(res != VK_SUCCESS)
6728 reinterpret_cast<char*>(pDstMappedData) + dstAllocRequest.offset,
6729 reinterpret_cast<char*>(pSrcMappedData) + srcOffset,
6730 static_cast<size_t>(size));
6732 pDstBlockInfo->m_pBlock->m_Metadata.Alloc(dstAllocRequest, suballocType, size, allocInfo.m_hAllocation);
6733 pSrcBlockInfo->m_pBlock->m_Metadata.FreeAtOffset(srcOffset);
6735 allocInfo.m_hAllocation->ChangeBlockAllocation(m_hAllocator, pDstBlockInfo->m_pBlock, dstAllocRequest.offset);
6737 if(allocInfo.m_pChanged != VMA_NULL)
6739 *allocInfo.m_pChanged = VK_TRUE;
6742 ++m_AllocationsMoved;
6743 m_BytesMoved += size;
6745 VmaVectorRemove(pSrcBlockInfo->m_Allocations, srcAllocIndex);
6753 if(srcAllocIndex > 0)
6759 if(srcBlockIndex > 0)
6762 srcAllocIndex = SIZE_MAX;
6772 VkResult VmaDefragmentator::Defragment(
6773 VkDeviceSize maxBytesToMove,
6774 uint32_t maxAllocationsToMove)
6776 if(m_Allocations.empty())
6782 const size_t blockCount = m_pBlockVector->m_Blocks.size();
6783 for(
size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
6785 BlockInfo* pBlockInfo = vma_new(m_hAllocator, BlockInfo)(m_hAllocator->GetAllocationCallbacks());
6786 pBlockInfo->m_pBlock = m_pBlockVector->m_Blocks[blockIndex];
6787 m_Blocks.push_back(pBlockInfo);
6791 VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockPointerLess());
6794 for(
size_t blockIndex = 0, allocCount = m_Allocations.size(); blockIndex < allocCount; ++blockIndex)
6796 AllocationInfo& allocInfo = m_Allocations[blockIndex];
6798 if(allocInfo.m_hAllocation->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
6800 VmaDeviceMemoryBlock* pBlock = allocInfo.m_hAllocation->GetBlock();
6801 BlockInfoVector::iterator it = VmaBinaryFindFirstNotLess(m_Blocks.begin(), m_Blocks.end(), pBlock, BlockPointerLess());
6802 if(it != m_Blocks.end() && (*it)->m_pBlock == pBlock)
6804 (*it)->m_Allocations.push_back(allocInfo);
6812 m_Allocations.clear();
6814 for(
size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
6816 BlockInfo* pBlockInfo = m_Blocks[blockIndex];
6817 pBlockInfo->CalcHasNonMovableAllocations();
6818 pBlockInfo->SortAllocationsBySizeDescecnding();
6822 VMA_SORT(m_Blocks.begin(), m_Blocks.end(), BlockInfoCompareMoveDestination());
6825 VkResult result = VK_SUCCESS;
6826 for(
size_t round = 0; (round < 2) && (result == VK_SUCCESS); ++round)
6828 result = DefragmentRound(maxBytesToMove, maxAllocationsToMove);
6832 for(
size_t blockIndex = 0; blockIndex < blockCount; ++blockIndex)
6834 m_Blocks[blockIndex]->Unmap(m_hAllocator);
6840 bool VmaDefragmentator::MoveMakesSense(
6841 size_t dstBlockIndex, VkDeviceSize dstOffset,
6842 size_t srcBlockIndex, VkDeviceSize srcOffset)
6844 if(dstBlockIndex < srcBlockIndex)
6848 if(dstBlockIndex > srcBlockIndex)
6852 if(dstOffset < srcOffset)
6862 VmaAllocator_T::VmaAllocator_T(
const VmaAllocatorCreateInfo* pCreateInfo) :
6863 m_UseMutex((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT) == 0),
6864 m_UseKhrDedicatedAllocation((pCreateInfo->flags & VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT) != 0),
6865 m_hDevice(pCreateInfo->device),
6866 m_AllocationCallbacksSpecified(pCreateInfo->pAllocationCallbacks != VMA_NULL),
6867 m_AllocationCallbacks(pCreateInfo->pAllocationCallbacks ?
6868 *pCreateInfo->pAllocationCallbacks : VmaEmptyAllocationCallbacks),
6869 m_PreferredLargeHeapBlockSize(0),
6870 m_PhysicalDevice(pCreateInfo->physicalDevice),
6871 m_CurrentFrameIndex(0),
6872 m_Pools(VmaStlAllocator<VmaPool>(GetAllocationCallbacks()))
6874 VMA_ASSERT(pCreateInfo->physicalDevice && pCreateInfo->device);
6876 memset(&m_DeviceMemoryCallbacks, 0 ,
sizeof(m_DeviceMemoryCallbacks));
6877 memset(&m_MemProps, 0,
sizeof(m_MemProps));
6878 memset(&m_PhysicalDeviceProperties, 0,
sizeof(m_PhysicalDeviceProperties));
6880 memset(&m_pBlockVectors, 0,
sizeof(m_pBlockVectors));
6881 memset(&m_pDedicatedAllocations, 0,
sizeof(m_pDedicatedAllocations));
6883 for(uint32_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
6885 m_HeapSizeLimit[i] = VK_WHOLE_SIZE;
6888 if(pCreateInfo->pDeviceMemoryCallbacks != VMA_NULL)
6890 m_DeviceMemoryCallbacks.pfnAllocate = pCreateInfo->pDeviceMemoryCallbacks->pfnAllocate;
6891 m_DeviceMemoryCallbacks.pfnFree = pCreateInfo->pDeviceMemoryCallbacks->pfnFree;
6894 ImportVulkanFunctions(pCreateInfo->pVulkanFunctions);
6896 (*m_VulkanFunctions.vkGetPhysicalDeviceProperties)(m_PhysicalDevice, &m_PhysicalDeviceProperties);
6897 (*m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties)(m_PhysicalDevice, &m_MemProps);
6899 m_PreferredLargeHeapBlockSize = (pCreateInfo->preferredLargeHeapBlockSize != 0) ?
6900 pCreateInfo->preferredLargeHeapBlockSize : static_cast<VkDeviceSize>(VMA_DEFAULT_LARGE_HEAP_BLOCK_SIZE);
6902 if(pCreateInfo->pHeapSizeLimit != VMA_NULL)
6904 for(uint32_t heapIndex = 0; heapIndex < GetMemoryHeapCount(); ++heapIndex)
6906 const VkDeviceSize limit = pCreateInfo->pHeapSizeLimit[heapIndex];
6907 if(limit != VK_WHOLE_SIZE)
6909 m_HeapSizeLimit[heapIndex] = limit;
6910 if(limit < m_MemProps.memoryHeaps[heapIndex].size)
6912 m_MemProps.memoryHeaps[heapIndex].size = limit;
6918 for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
6920 const VkDeviceSize preferredBlockSize = CalcPreferredBlockSize(memTypeIndex);
6922 m_pBlockVectors[memTypeIndex] = vma_new(
this, VmaBlockVector)(
6928 GetBufferImageGranularity(),
6929 pCreateInfo->frameInUseCount,
6933 m_pDedicatedAllocations[memTypeIndex] = vma_new(
this, AllocationVectorType)(VmaStlAllocator<VmaAllocation>(GetAllocationCallbacks()));
6937 VmaAllocator_T::~VmaAllocator_T()
6939 VMA_ASSERT(m_Pools.empty());
6941 for(
size_t i = GetMemoryTypeCount(); i--; )
6943 vma_delete(
this, m_pDedicatedAllocations[i]);
6944 vma_delete(
this, m_pBlockVectors[i]);
6948 void VmaAllocator_T::ImportVulkanFunctions(
const VmaVulkanFunctions* pVulkanFunctions)
6950 #if VMA_STATIC_VULKAN_FUNCTIONS == 1 6951 m_VulkanFunctions.vkGetPhysicalDeviceProperties = &vkGetPhysicalDeviceProperties;
6952 m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties = &vkGetPhysicalDeviceMemoryProperties;
6953 m_VulkanFunctions.vkAllocateMemory = &vkAllocateMemory;
6954 m_VulkanFunctions.vkFreeMemory = &vkFreeMemory;
6955 m_VulkanFunctions.vkMapMemory = &vkMapMemory;
6956 m_VulkanFunctions.vkUnmapMemory = &vkUnmapMemory;
6957 m_VulkanFunctions.vkBindBufferMemory = &vkBindBufferMemory;
6958 m_VulkanFunctions.vkBindImageMemory = &vkBindImageMemory;
6959 m_VulkanFunctions.vkGetBufferMemoryRequirements = &vkGetBufferMemoryRequirements;
6960 m_VulkanFunctions.vkGetImageMemoryRequirements = &vkGetImageMemoryRequirements;
6961 m_VulkanFunctions.vkCreateBuffer = &vkCreateBuffer;
6962 m_VulkanFunctions.vkDestroyBuffer = &vkDestroyBuffer;
6963 m_VulkanFunctions.vkCreateImage = &vkCreateImage;
6964 m_VulkanFunctions.vkDestroyImage = &vkDestroyImage;
6965 if(m_UseKhrDedicatedAllocation)
6967 m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR =
6968 (PFN_vkGetBufferMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice,
"vkGetBufferMemoryRequirements2KHR");
6969 m_VulkanFunctions.vkGetImageMemoryRequirements2KHR =
6970 (PFN_vkGetImageMemoryRequirements2KHR)vkGetDeviceProcAddr(m_hDevice,
"vkGetImageMemoryRequirements2KHR");
6972 #endif // #if VMA_STATIC_VULKAN_FUNCTIONS == 1 6974 #define VMA_COPY_IF_NOT_NULL(funcName) \ 6975 if(pVulkanFunctions->funcName != VMA_NULL) m_VulkanFunctions.funcName = pVulkanFunctions->funcName; 6977 if(pVulkanFunctions != VMA_NULL)
6979 VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceProperties);
6980 VMA_COPY_IF_NOT_NULL(vkGetPhysicalDeviceMemoryProperties);
6981 VMA_COPY_IF_NOT_NULL(vkAllocateMemory);
6982 VMA_COPY_IF_NOT_NULL(vkFreeMemory);
6983 VMA_COPY_IF_NOT_NULL(vkMapMemory);
6984 VMA_COPY_IF_NOT_NULL(vkUnmapMemory);
6985 VMA_COPY_IF_NOT_NULL(vkBindBufferMemory);
6986 VMA_COPY_IF_NOT_NULL(vkBindImageMemory);
6987 VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements);
6988 VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements);
6989 VMA_COPY_IF_NOT_NULL(vkCreateBuffer);
6990 VMA_COPY_IF_NOT_NULL(vkDestroyBuffer);
6991 VMA_COPY_IF_NOT_NULL(vkCreateImage);
6992 VMA_COPY_IF_NOT_NULL(vkDestroyImage);
6993 VMA_COPY_IF_NOT_NULL(vkGetBufferMemoryRequirements2KHR);
6994 VMA_COPY_IF_NOT_NULL(vkGetImageMemoryRequirements2KHR);
6997 #undef VMA_COPY_IF_NOT_NULL 7001 VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceProperties != VMA_NULL);
7002 VMA_ASSERT(m_VulkanFunctions.vkGetPhysicalDeviceMemoryProperties != VMA_NULL);
7003 VMA_ASSERT(m_VulkanFunctions.vkAllocateMemory != VMA_NULL);
7004 VMA_ASSERT(m_VulkanFunctions.vkFreeMemory != VMA_NULL);
7005 VMA_ASSERT(m_VulkanFunctions.vkMapMemory != VMA_NULL);
7006 VMA_ASSERT(m_VulkanFunctions.vkUnmapMemory != VMA_NULL);
7007 VMA_ASSERT(m_VulkanFunctions.vkBindBufferMemory != VMA_NULL);
7008 VMA_ASSERT(m_VulkanFunctions.vkBindImageMemory != VMA_NULL);
7009 VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements != VMA_NULL);
7010 VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements != VMA_NULL);
7011 VMA_ASSERT(m_VulkanFunctions.vkCreateBuffer != VMA_NULL);
7012 VMA_ASSERT(m_VulkanFunctions.vkDestroyBuffer != VMA_NULL);
7013 VMA_ASSERT(m_VulkanFunctions.vkCreateImage != VMA_NULL);
7014 VMA_ASSERT(m_VulkanFunctions.vkDestroyImage != VMA_NULL);
7015 if(m_UseKhrDedicatedAllocation)
7017 VMA_ASSERT(m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR != VMA_NULL);
7018 VMA_ASSERT(m_VulkanFunctions.vkGetImageMemoryRequirements2KHR != VMA_NULL);
7022 VkDeviceSize VmaAllocator_T::CalcPreferredBlockSize(uint32_t memTypeIndex)
7024 const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
7025 const VkDeviceSize heapSize = m_MemProps.memoryHeaps[heapIndex].size;
7026 const bool isSmallHeap = heapSize <= VMA_SMALL_HEAP_MAX_SIZE;
7027 return isSmallHeap ? (heapSize / 8) : m_PreferredLargeHeapBlockSize;
7030 VkResult VmaAllocator_T::AllocateMemoryOfType(
7031 const VkMemoryRequirements& vkMemReq,
7032 bool dedicatedAllocation,
7033 VkBuffer dedicatedBuffer,
7034 VkImage dedicatedImage,
7035 const VmaAllocationCreateInfo& createInfo,
7036 uint32_t memTypeIndex,
7037 VmaSuballocationType suballocType,
7038 VmaAllocation* pAllocation)
7040 VMA_ASSERT(pAllocation != VMA_NULL);
7041 VMA_DEBUG_LOG(
" AllocateMemory: MemoryTypeIndex=%u, Size=%llu", memTypeIndex, vkMemReq.size);
7043 VmaAllocationCreateInfo finalCreateInfo = createInfo;
7046 if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
7047 (m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
7049 finalCreateInfo.flags &= ~VMA_ALLOCATION_CREATE_MAPPED_BIT;
7052 VmaBlockVector*
const blockVector = m_pBlockVectors[memTypeIndex];
7053 VMA_ASSERT(blockVector);
7055 const VkDeviceSize preferredBlockSize = blockVector->GetPreferredBlockSize();
7056 bool preferDedicatedMemory =
7057 VMA_DEBUG_ALWAYS_DEDICATED_MEMORY ||
7058 dedicatedAllocation ||
7060 vkMemReq.size > preferredBlockSize / 2;
7062 if(preferDedicatedMemory &&
7063 (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) == 0 &&
7064 finalCreateInfo.pool == VK_NULL_HANDLE)
7066 finalCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
7069 if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0)
7071 if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
7073 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
7077 return AllocateDedicatedMemory(
7081 (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
7082 (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
7083 finalCreateInfo.pUserData,
7091 VkResult res = blockVector->Allocate(
7093 m_CurrentFrameIndex.load(),
7098 if(res == VK_SUCCESS)
7104 if((finalCreateInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
7106 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
7110 res = AllocateDedicatedMemory(
7114 (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0,
7115 (finalCreateInfo.flags & VMA_ALLOCATION_CREATE_USER_DATA_COPY_STRING_BIT) != 0,
7116 finalCreateInfo.pUserData,
7120 if(res == VK_SUCCESS)
7123 VMA_DEBUG_LOG(
" Allocated as DedicatedMemory");
7129 VMA_DEBUG_LOG(
" vkAllocateMemory FAILED");
7136 VkResult VmaAllocator_T::AllocateDedicatedMemory(
7138 VmaSuballocationType suballocType,
7139 uint32_t memTypeIndex,
7141 bool isUserDataString,
7143 VkBuffer dedicatedBuffer,
7144 VkImage dedicatedImage,
7145 VmaAllocation* pAllocation)
7147 VMA_ASSERT(pAllocation);
7149 VkMemoryAllocateInfo allocInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
7150 allocInfo.memoryTypeIndex = memTypeIndex;
7151 allocInfo.allocationSize = size;
7153 VkMemoryDedicatedAllocateInfoKHR dedicatedAllocInfo = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR };
7154 if(m_UseKhrDedicatedAllocation)
7156 if(dedicatedBuffer != VK_NULL_HANDLE)
7158 VMA_ASSERT(dedicatedImage == VK_NULL_HANDLE);
7159 dedicatedAllocInfo.buffer = dedicatedBuffer;
7160 allocInfo.pNext = &dedicatedAllocInfo;
7162 else if(dedicatedImage != VK_NULL_HANDLE)
7164 dedicatedAllocInfo.image = dedicatedImage;
7165 allocInfo.pNext = &dedicatedAllocInfo;
7170 VkDeviceMemory hMemory = VK_NULL_HANDLE;
7171 VkResult res = AllocateVulkanMemory(&allocInfo, &hMemory);
7174 VMA_DEBUG_LOG(
" vkAllocateMemory FAILED");
7178 void* pMappedData = VMA_NULL;
7181 res = (*m_VulkanFunctions.vkMapMemory)(
7190 VMA_DEBUG_LOG(
" vkMapMemory FAILED");
7191 FreeVulkanMemory(memTypeIndex, size, hMemory);
7196 *pAllocation = vma_new(
this, VmaAllocation_T)(m_CurrentFrameIndex.load(), isUserDataString);
7197 (*pAllocation)->InitDedicatedAllocation(memTypeIndex, hMemory, suballocType, pMappedData, size);
7198 (*pAllocation)->SetUserData(
this, pUserData);
7202 VmaMutexLock lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
7203 AllocationVectorType* pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
7204 VMA_ASSERT(pDedicatedAllocations);
7205 VmaVectorInsertSorted<VmaPointerLess>(*pDedicatedAllocations, *pAllocation);
7208 VMA_DEBUG_LOG(
" Allocated DedicatedMemory MemoryTypeIndex=#%u", memTypeIndex);
7213 void VmaAllocator_T::GetBufferMemoryRequirements(
7215 VkMemoryRequirements& memReq,
7216 bool& requiresDedicatedAllocation,
7217 bool& prefersDedicatedAllocation)
const 7219 if(m_UseKhrDedicatedAllocation)
7221 VkBufferMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR };
7222 memReqInfo.buffer = hBuffer;
7224 VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
7226 VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
7227 memReq2.pNext = &memDedicatedReq;
7229 (*m_VulkanFunctions.vkGetBufferMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
7231 memReq = memReq2.memoryRequirements;
7232 requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
7233 prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
7237 (*m_VulkanFunctions.vkGetBufferMemoryRequirements)(m_hDevice, hBuffer, &memReq);
7238 requiresDedicatedAllocation =
false;
7239 prefersDedicatedAllocation =
false;
7243 void VmaAllocator_T::GetImageMemoryRequirements(
7245 VkMemoryRequirements& memReq,
7246 bool& requiresDedicatedAllocation,
7247 bool& prefersDedicatedAllocation)
const 7249 if(m_UseKhrDedicatedAllocation)
7251 VkImageMemoryRequirementsInfo2KHR memReqInfo = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR };
7252 memReqInfo.image = hImage;
7254 VkMemoryDedicatedRequirementsKHR memDedicatedReq = { VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR };
7256 VkMemoryRequirements2KHR memReq2 = { VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR };
7257 memReq2.pNext = &memDedicatedReq;
7259 (*m_VulkanFunctions.vkGetImageMemoryRequirements2KHR)(m_hDevice, &memReqInfo, &memReq2);
7261 memReq = memReq2.memoryRequirements;
7262 requiresDedicatedAllocation = (memDedicatedReq.requiresDedicatedAllocation != VK_FALSE);
7263 prefersDedicatedAllocation = (memDedicatedReq.prefersDedicatedAllocation != VK_FALSE);
7267 (*m_VulkanFunctions.vkGetImageMemoryRequirements)(m_hDevice, hImage, &memReq);
7268 requiresDedicatedAllocation =
false;
7269 prefersDedicatedAllocation =
false;
7273 VkResult VmaAllocator_T::AllocateMemory(
7274 const VkMemoryRequirements& vkMemReq,
7275 bool requiresDedicatedAllocation,
7276 bool prefersDedicatedAllocation,
7277 VkBuffer dedicatedBuffer,
7278 VkImage dedicatedImage,
7279 const VmaAllocationCreateInfo& createInfo,
7280 VmaSuballocationType suballocType,
7281 VmaAllocation* pAllocation)
7283 if((createInfo.flags & VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT) != 0 &&
7284 (createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
7286 VMA_ASSERT(0 &&
"Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT together with VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT makes no sense.");
7287 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
7289 if((createInfo.flags & VMA_ALLOCATION_CREATE_MAPPED_BIT) != 0 &&
7290 (createInfo.flags & VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT) != 0)
7292 VMA_ASSERT(0 &&
"Specifying VMA_ALLOCATION_CREATE_MAPPED_BIT together with VMA_ALLOCATION_CREATE_CAN_BECOME_LOST_BIT is invalid.");
7293 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
7295 if(requiresDedicatedAllocation)
7297 if((createInfo.flags & VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT) != 0)
7299 VMA_ASSERT(0 &&
"VMA_ALLOCATION_CREATE_NEVER_ALLOCATE_BIT specified while dedicated allocation is required.");
7300 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
7302 if(createInfo.pool != VK_NULL_HANDLE)
7304 VMA_ASSERT(0 &&
"Pool specified while dedicated allocation is required.");
7305 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
7308 if((createInfo.pool != VK_NULL_HANDLE) &&
7309 ((createInfo.flags & (VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT)) != 0))
7311 VMA_ASSERT(0 &&
"Specifying VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT when pool != null is invalid.");
7312 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
7315 if(createInfo.pool != VK_NULL_HANDLE)
7317 return createInfo.pool->m_BlockVector.Allocate(
7319 m_CurrentFrameIndex.load(),
7328 uint32_t memoryTypeBits = vkMemReq.memoryTypeBits;
7329 uint32_t memTypeIndex = UINT32_MAX;
7330 VkResult res = vmaFindMemoryTypeIndex(
this, memoryTypeBits, &createInfo, &memTypeIndex);
7331 if(res == VK_SUCCESS)
7333 res = AllocateMemoryOfType(
7335 requiresDedicatedAllocation || prefersDedicatedAllocation,
7343 if(res == VK_SUCCESS)
7353 memoryTypeBits &= ~(1u << memTypeIndex);
7355 res = vmaFindMemoryTypeIndex(
this, memoryTypeBits, &createInfo, &memTypeIndex);
7356 if(res == VK_SUCCESS)
7358 res = AllocateMemoryOfType(
7360 requiresDedicatedAllocation || prefersDedicatedAllocation,
7368 if(res == VK_SUCCESS)
7378 return VK_ERROR_OUT_OF_DEVICE_MEMORY;
7389 void VmaAllocator_T::FreeMemory(
const VmaAllocation allocation)
7391 VMA_ASSERT(allocation);
7393 if(allocation->CanBecomeLost() ==
false ||
7394 allocation->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST)
7396 switch(allocation->GetType())
7398 case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
7400 VmaBlockVector* pBlockVector = VMA_NULL;
7401 VmaPool hPool = allocation->GetPool();
7402 if(hPool != VK_NULL_HANDLE)
7404 pBlockVector = &hPool->m_BlockVector;
7408 const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
7409 pBlockVector = m_pBlockVectors[memTypeIndex];
7411 pBlockVector->Free(allocation);
7414 case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
7415 FreeDedicatedMemory(allocation);
7422 allocation->SetUserData(
this, VMA_NULL);
7423 vma_delete(
this, allocation);
7426 void VmaAllocator_T::CalculateStats(VmaStats* pStats)
7429 InitStatInfo(pStats->total);
7430 for(
size_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i)
7431 InitStatInfo(pStats->memoryType[i]);
7432 for(
size_t i = 0; i < VK_MAX_MEMORY_HEAPS; ++i)
7433 InitStatInfo(pStats->memoryHeap[i]);
7436 for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
7438 VmaBlockVector*
const pBlockVector = m_pBlockVectors[memTypeIndex];
7439 VMA_ASSERT(pBlockVector);
7440 pBlockVector->AddStats(pStats);
7445 VmaMutexLock lock(m_PoolsMutex, m_UseMutex);
7446 for(
size_t poolIndex = 0, poolCount = m_Pools.size(); poolIndex < poolCount; ++poolIndex)
7448 m_Pools[poolIndex]->GetBlockVector().AddStats(pStats);
7453 for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
7455 const uint32_t memHeapIndex = MemoryTypeIndexToHeapIndex(memTypeIndex);
7456 VmaMutexLock dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
7457 AllocationVectorType*
const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex];
7458 VMA_ASSERT(pDedicatedAllocVector);
7459 for(
size_t allocIndex = 0, allocCount = pDedicatedAllocVector->size(); allocIndex < allocCount; ++allocIndex)
7461 VmaStatInfo allocationStatInfo;
7462 (*pDedicatedAllocVector)[allocIndex]->DedicatedAllocCalcStatsInfo(allocationStatInfo);
7463 VmaAddStatInfo(pStats->total, allocationStatInfo);
7464 VmaAddStatInfo(pStats->memoryType[memTypeIndex], allocationStatInfo);
7465 VmaAddStatInfo(pStats->memoryHeap[memHeapIndex], allocationStatInfo);
7470 VmaPostprocessCalcStatInfo(pStats->total);
7471 for(
size_t i = 0; i < GetMemoryTypeCount(); ++i)
7472 VmaPostprocessCalcStatInfo(pStats->memoryType[i]);
7473 for(
size_t i = 0; i < GetMemoryHeapCount(); ++i)
7474 VmaPostprocessCalcStatInfo(pStats->memoryHeap[i]);
7477 static const uint32_t VMA_VENDOR_ID_AMD = 4098;
7479 VkResult VmaAllocator_T::Defragment(
7480 VmaAllocation* pAllocations,
7481 size_t allocationCount,
7482 VkBool32* pAllocationsChanged,
7483 const VmaDefragmentationInfo* pDefragmentationInfo,
7484 VmaDefragmentationStats* pDefragmentationStats)
7486 if(pAllocationsChanged != VMA_NULL)
7488 memset(pAllocationsChanged, 0,
sizeof(*pAllocationsChanged));
7490 if(pDefragmentationStats != VMA_NULL)
7492 memset(pDefragmentationStats, 0,
sizeof(*pDefragmentationStats));
7495 const uint32_t currentFrameIndex = m_CurrentFrameIndex.load();
7497 VmaMutexLock poolsLock(m_PoolsMutex, m_UseMutex);
7499 const size_t poolCount = m_Pools.size();
7502 for(
size_t allocIndex = 0; allocIndex < allocationCount; ++allocIndex)
7504 VmaAllocation hAlloc = pAllocations[allocIndex];
7506 const uint32_t memTypeIndex = hAlloc->GetMemoryTypeIndex();
7508 if((hAlloc->GetType() == VmaAllocation_T::ALLOCATION_TYPE_BLOCK) &&
7510 ((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0) &&
7512 (hAlloc->GetLastUseFrameIndex() != VMA_FRAME_INDEX_LOST))
7514 VmaBlockVector* pAllocBlockVector = VMA_NULL;
7516 const VmaPool hAllocPool = hAlloc->GetPool();
7518 if(hAllocPool != VK_NULL_HANDLE)
7520 pAllocBlockVector = &hAllocPool->GetBlockVector();
7525 pAllocBlockVector = m_pBlockVectors[memTypeIndex];
7528 VmaDefragmentator*
const pDefragmentator = pAllocBlockVector->EnsureDefragmentator(
this, currentFrameIndex);
7530 VkBool32*
const pChanged = (pAllocationsChanged != VMA_NULL) ?
7531 &pAllocationsChanged[allocIndex] : VMA_NULL;
7532 pDefragmentator->AddAllocation(hAlloc, pChanged);
7536 VkResult result = VK_SUCCESS;
7540 VkDeviceSize maxBytesToMove = SIZE_MAX;
7541 uint32_t maxAllocationsToMove = UINT32_MAX;
7542 if(pDefragmentationInfo != VMA_NULL)
7544 maxBytesToMove = pDefragmentationInfo->maxBytesToMove;
7545 maxAllocationsToMove = pDefragmentationInfo->maxAllocationsToMove;
7549 for(uint32_t memTypeIndex = 0;
7550 (memTypeIndex < GetMemoryTypeCount()) && (result == VK_SUCCESS);
7554 if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
7556 result = m_pBlockVectors[memTypeIndex]->Defragment(
7557 pDefragmentationStats,
7559 maxAllocationsToMove);
7564 for(
size_t poolIndex = 0; (poolIndex < poolCount) && (result == VK_SUCCESS); ++poolIndex)
7566 result = m_Pools[poolIndex]->GetBlockVector().Defragment(
7567 pDefragmentationStats,
7569 maxAllocationsToMove);
7575 for(
size_t poolIndex = poolCount; poolIndex--; )
7577 m_Pools[poolIndex]->GetBlockVector().DestroyDefragmentator();
7581 for(uint32_t memTypeIndex = GetMemoryTypeCount(); memTypeIndex--; )
7583 if((m_MemProps.memoryTypes[memTypeIndex].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
7585 m_pBlockVectors[memTypeIndex]->DestroyDefragmentator();
7592 void VmaAllocator_T::GetAllocationInfo(VmaAllocation hAllocation, VmaAllocationInfo* pAllocationInfo)
7594 if(hAllocation->CanBecomeLost())
7600 uint32_t localCurrFrameIndex = m_CurrentFrameIndex.load();
7601 uint32_t localLastUseFrameIndex = hAllocation->GetLastUseFrameIndex();
7604 if(localLastUseFrameIndex == VMA_FRAME_INDEX_LOST)
7606 pAllocationInfo->memoryType = UINT32_MAX;
7607 pAllocationInfo->deviceMemory = VK_NULL_HANDLE;
7608 pAllocationInfo->offset = 0;
7609 pAllocationInfo->size = hAllocation->GetSize();
7610 pAllocationInfo->pMappedData = VMA_NULL;
7611 pAllocationInfo->pUserData = hAllocation->GetUserData();
7614 else if(localLastUseFrameIndex == localCurrFrameIndex)
7616 pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
7617 pAllocationInfo->deviceMemory = hAllocation->GetMemory();
7618 pAllocationInfo->offset = hAllocation->GetOffset();
7619 pAllocationInfo->size = hAllocation->GetSize();
7620 pAllocationInfo->pMappedData = VMA_NULL;
7621 pAllocationInfo->pUserData = hAllocation->GetUserData();
7626 if(hAllocation->CompareExchangeLastUseFrameIndex(localLastUseFrameIndex, localCurrFrameIndex))
7628 localLastUseFrameIndex = localCurrFrameIndex;
7635 pAllocationInfo->memoryType = hAllocation->GetMemoryTypeIndex();
7636 pAllocationInfo->deviceMemory = hAllocation->GetMemory();
7637 pAllocationInfo->offset = hAllocation->GetOffset();
7638 pAllocationInfo->size = hAllocation->GetSize();
7639 pAllocationInfo->pMappedData = hAllocation->GetMappedData();
7640 pAllocationInfo->pUserData = hAllocation->GetUserData();
7644 VkResult VmaAllocator_T::CreatePool(
const VmaPoolCreateInfo* pCreateInfo, VmaPool* pPool)
7646 VMA_DEBUG_LOG(
" CreatePool: MemoryTypeIndex=%u", pCreateInfo->memoryTypeIndex);
7648 VmaPoolCreateInfo newCreateInfo = *pCreateInfo;
7650 if(newCreateInfo.maxBlockCount == 0)
7652 newCreateInfo.maxBlockCount = SIZE_MAX;
7654 if(newCreateInfo.blockSize == 0)
7656 newCreateInfo.blockSize = CalcPreferredBlockSize(newCreateInfo.memoryTypeIndex);
7659 *pPool = vma_new(
this, VmaPool_T)(
this, newCreateInfo);
7661 VkResult res = (*pPool)->m_BlockVector.CreateMinBlocks();
7662 if(res != VK_SUCCESS)
7664 vma_delete(
this, *pPool);
7671 VmaMutexLock lock(m_PoolsMutex, m_UseMutex);
7672 VmaVectorInsertSorted<VmaPointerLess>(m_Pools, *pPool);
7678 void VmaAllocator_T::DestroyPool(VmaPool pool)
7682 VmaMutexLock lock(m_PoolsMutex, m_UseMutex);
7683 bool success = VmaVectorRemoveSorted<VmaPointerLess>(m_Pools, pool);
7684 VMA_ASSERT(success &&
"Pool not found in Allocator.");
7687 vma_delete(
this, pool);
7690 void VmaAllocator_T::GetPoolStats(VmaPool pool, VmaPoolStats* pPoolStats)
7692 pool->m_BlockVector.GetPoolStats(pPoolStats);
7695 void VmaAllocator_T::SetCurrentFrameIndex(uint32_t frameIndex)
7697 m_CurrentFrameIndex.store(frameIndex);
7700 void VmaAllocator_T::MakePoolAllocationsLost(
7702 size_t* pLostAllocationCount)
7704 hPool->m_BlockVector.MakePoolAllocationsLost(
7705 m_CurrentFrameIndex.load(),
7706 pLostAllocationCount);
7709 void VmaAllocator_T::CreateLostAllocation(VmaAllocation* pAllocation)
7711 *pAllocation = vma_new(
this, VmaAllocation_T)(VMA_FRAME_INDEX_LOST,
false);
7712 (*pAllocation)->InitLost();
7715 VkResult VmaAllocator_T::AllocateVulkanMemory(
const VkMemoryAllocateInfo* pAllocateInfo, VkDeviceMemory* pMemory)
7717 const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(pAllocateInfo->memoryTypeIndex);
7720 if(m_HeapSizeLimit[heapIndex] != VK_WHOLE_SIZE)
7722 VmaMutexLock lock(m_HeapSizeLimitMutex, m_UseMutex);
7723 if(m_HeapSizeLimit[heapIndex] >= pAllocateInfo->allocationSize)
7725 res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory);
7726 if(res == VK_SUCCESS)
7728 m_HeapSizeLimit[heapIndex] -= pAllocateInfo->allocationSize;
7733 res = VK_ERROR_OUT_OF_DEVICE_MEMORY;
7738 res = (*m_VulkanFunctions.vkAllocateMemory)(m_hDevice, pAllocateInfo, GetAllocationCallbacks(), pMemory);
7741 if(res == VK_SUCCESS && m_DeviceMemoryCallbacks.pfnAllocate != VMA_NULL)
7743 (*m_DeviceMemoryCallbacks.pfnAllocate)(
this, pAllocateInfo->memoryTypeIndex, *pMemory, pAllocateInfo->allocationSize);
7749 void VmaAllocator_T::FreeVulkanMemory(uint32_t memoryType, VkDeviceSize size, VkDeviceMemory hMemory)
7751 if(m_DeviceMemoryCallbacks.pfnFree != VMA_NULL)
7753 (*m_DeviceMemoryCallbacks.pfnFree)(
this, memoryType, hMemory, size);
7756 (*m_VulkanFunctions.vkFreeMemory)(m_hDevice, hMemory, GetAllocationCallbacks());
7758 const uint32_t heapIndex = MemoryTypeIndexToHeapIndex(memoryType);
7759 if(m_HeapSizeLimit[heapIndex] != VK_WHOLE_SIZE)
7761 VmaMutexLock lock(m_HeapSizeLimitMutex, m_UseMutex);
7762 m_HeapSizeLimit[heapIndex] += size;
7766 VkResult VmaAllocator_T::Map(VmaAllocation hAllocation,
void** ppData)
7768 if(hAllocation->CanBecomeLost())
7770 return VK_ERROR_MEMORY_MAP_FAILED;
7773 switch(hAllocation->GetType())
7775 case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
7777 VmaDeviceMemoryBlock*
const pBlock = hAllocation->GetBlock();
7778 char *pBytes = VMA_NULL;
7779 VkResult res = pBlock->Map(
this, 1, (
void**)&pBytes);
7780 if(res == VK_SUCCESS)
7782 *ppData = pBytes + (ptrdiff_t)hAllocation->GetOffset();
7783 hAllocation->BlockAllocMap();
7787 case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
7788 return hAllocation->DedicatedAllocMap(
this, ppData);
7791 return VK_ERROR_MEMORY_MAP_FAILED;
7795 void VmaAllocator_T::Unmap(VmaAllocation hAllocation)
7797 switch(hAllocation->GetType())
7799 case VmaAllocation_T::ALLOCATION_TYPE_BLOCK:
7801 VmaDeviceMemoryBlock*
const pBlock = hAllocation->GetBlock();
7802 hAllocation->BlockAllocUnmap();
7803 pBlock->Unmap(
this, 1);
7806 case VmaAllocation_T::ALLOCATION_TYPE_DEDICATED:
7807 hAllocation->DedicatedAllocUnmap(
this);
7814 void VmaAllocator_T::FreeDedicatedMemory(VmaAllocation allocation)
7816 VMA_ASSERT(allocation && allocation->GetType() == VmaAllocation_T::ALLOCATION_TYPE_DEDICATED);
7818 const uint32_t memTypeIndex = allocation->GetMemoryTypeIndex();
7820 VmaMutexLock lock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
7821 AllocationVectorType*
const pDedicatedAllocations = m_pDedicatedAllocations[memTypeIndex];
7822 VMA_ASSERT(pDedicatedAllocations);
7823 bool success = VmaVectorRemoveSorted<VmaPointerLess>(*pDedicatedAllocations, allocation);
7824 VMA_ASSERT(success);
7827 VkDeviceMemory hMemory = allocation->GetMemory();
7829 if(allocation->GetMappedData() != VMA_NULL)
7831 (*m_VulkanFunctions.vkUnmapMemory)(m_hDevice, hMemory);
7834 FreeVulkanMemory(memTypeIndex, allocation->GetSize(), hMemory);
7836 VMA_DEBUG_LOG(
" Freed DedicatedMemory MemoryTypeIndex=%u", memTypeIndex);
7839 #if VMA_STATS_STRING_ENABLED 7841 void VmaAllocator_T::PrintDetailedMap(VmaJsonWriter& json)
7843 bool dedicatedAllocationsStarted =
false;
7844 for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
7846 VmaMutexLock dedicatedAllocationsLock(m_DedicatedAllocationsMutex[memTypeIndex], m_UseMutex);
7847 AllocationVectorType*
const pDedicatedAllocVector = m_pDedicatedAllocations[memTypeIndex];
7848 VMA_ASSERT(pDedicatedAllocVector);
7849 if(pDedicatedAllocVector->empty() ==
false)
7851 if(dedicatedAllocationsStarted ==
false)
7853 dedicatedAllocationsStarted =
true;
7854 json.WriteString(
"DedicatedAllocations");
7858 json.BeginString(
"Type ");
7859 json.ContinueString(memTypeIndex);
7864 for(
size_t i = 0; i < pDedicatedAllocVector->size(); ++i)
7866 const VmaAllocation hAlloc = (*pDedicatedAllocVector)[i];
7867 json.BeginObject(
true);
7869 json.WriteString(
"Type");
7870 json.WriteString(VMA_SUBALLOCATION_TYPE_NAMES[hAlloc->GetSuballocationType()]);
7872 json.WriteString(
"Size");
7873 json.WriteNumber(hAlloc->GetSize());
7875 const void* pUserData = hAlloc->GetUserData();
7876 if(pUserData != VMA_NULL)
7878 json.WriteString(
"UserData");
7879 if(hAlloc->IsUserDataString())
7881 json.WriteString((
const char*)pUserData);
7886 json.ContinueString_Pointer(pUserData);
7897 if(dedicatedAllocationsStarted)
7903 bool allocationsStarted =
false;
7904 for(uint32_t memTypeIndex = 0; memTypeIndex < GetMemoryTypeCount(); ++memTypeIndex)
7906 if(m_pBlockVectors[memTypeIndex]->IsEmpty() ==
false)
7908 if(allocationsStarted ==
false)
7910 allocationsStarted =
true;
7911 json.WriteString(
"DefaultPools");
7915 json.BeginString(
"Type ");
7916 json.ContinueString(memTypeIndex);
7919 m_pBlockVectors[memTypeIndex]->PrintDetailedMap(json);
7922 if(allocationsStarted)
7929 VmaMutexLock lock(m_PoolsMutex, m_UseMutex);
7930 const size_t poolCount = m_Pools.size();
7933 json.WriteString(
"Pools");
7935 for(
size_t poolIndex = 0; poolIndex < poolCount; ++poolIndex)
7937 m_Pools[poolIndex]->m_BlockVector.PrintDetailedMap(json);
7944 #endif // #if VMA_STATS_STRING_ENABLED 7946 static VkResult AllocateMemoryForImage(
7947 VmaAllocator allocator,
7949 const VmaAllocationCreateInfo* pAllocationCreateInfo,
7950 VmaSuballocationType suballocType,
7951 VmaAllocation* pAllocation)
7953 VMA_ASSERT(allocator && (image != VK_NULL_HANDLE) && pAllocationCreateInfo && pAllocation);
7955 VkMemoryRequirements vkMemReq = {};
7956 bool requiresDedicatedAllocation =
false;
7957 bool prefersDedicatedAllocation =
false;
7958 allocator->GetImageMemoryRequirements(image, vkMemReq,
7959 requiresDedicatedAllocation, prefersDedicatedAllocation);
7961 return allocator->AllocateMemory(
7963 requiresDedicatedAllocation,
7964 prefersDedicatedAllocation,
7967 *pAllocationCreateInfo,
7975 VkResult vmaCreateAllocator(
7976 const VmaAllocatorCreateInfo* pCreateInfo,
7977 VmaAllocator* pAllocator)
7979 VMA_ASSERT(pCreateInfo && pAllocator);
7980 VMA_DEBUG_LOG(
"vmaCreateAllocator");
7981 *pAllocator = vma_new(pCreateInfo->pAllocationCallbacks, VmaAllocator_T)(pCreateInfo);
7985 void vmaDestroyAllocator(
7986 VmaAllocator allocator)
7988 if(allocator != VK_NULL_HANDLE)
7990 VMA_DEBUG_LOG(
"vmaDestroyAllocator");
7991 VkAllocationCallbacks allocationCallbacks = allocator->m_AllocationCallbacks;
7992 vma_delete(&allocationCallbacks, allocator);
7996 void vmaGetPhysicalDeviceProperties(
7997 VmaAllocator allocator,
7998 const VkPhysicalDeviceProperties **ppPhysicalDeviceProperties)
8000 VMA_ASSERT(allocator && ppPhysicalDeviceProperties);
8001 *ppPhysicalDeviceProperties = &allocator->m_PhysicalDeviceProperties;
8004 void vmaGetMemoryProperties(
8005 VmaAllocator allocator,
8006 const VkPhysicalDeviceMemoryProperties** ppPhysicalDeviceMemoryProperties)
8008 VMA_ASSERT(allocator && ppPhysicalDeviceMemoryProperties);
8009 *ppPhysicalDeviceMemoryProperties = &allocator->m_MemProps;
8012 void vmaGetMemoryTypeProperties(
8013 VmaAllocator allocator,
8014 uint32_t memoryTypeIndex,
8015 VkMemoryPropertyFlags* pFlags)
8017 VMA_ASSERT(allocator && pFlags);
8018 VMA_ASSERT(memoryTypeIndex < allocator->GetMemoryTypeCount());
8019 *pFlags = allocator->m_MemProps.memoryTypes[memoryTypeIndex].propertyFlags;
8022 void vmaSetCurrentFrameIndex(
8023 VmaAllocator allocator,
8024 uint32_t frameIndex)
8026 VMA_ASSERT(allocator);
8027 VMA_ASSERT(frameIndex != VMA_FRAME_INDEX_LOST);
8029 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8031 allocator->SetCurrentFrameIndex(frameIndex);
8034 void vmaCalculateStats(
8035 VmaAllocator allocator,
8038 VMA_ASSERT(allocator && pStats);
8039 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8040 allocator->CalculateStats(pStats);
8043 #if VMA_STATS_STRING_ENABLED 8045 void vmaBuildStatsString(
8046 VmaAllocator allocator,
8047 char** ppStatsString,
8048 VkBool32 detailedMap)
8050 VMA_ASSERT(allocator && ppStatsString);
8051 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8053 VmaStringBuilder sb(allocator);
8055 VmaJsonWriter json(allocator->GetAllocationCallbacks(), sb);
8059 allocator->CalculateStats(&stats);
8061 json.WriteString(
"Total");
8062 VmaPrintStatInfo(json, stats.total);
8064 for(uint32_t heapIndex = 0; heapIndex < allocator->GetMemoryHeapCount(); ++heapIndex)
8066 json.BeginString(
"Heap ");
8067 json.ContinueString(heapIndex);
8071 json.WriteString(
"Size");
8072 json.WriteNumber(allocator->m_MemProps.memoryHeaps[heapIndex].size);
8074 json.WriteString(
"Flags");
8075 json.BeginArray(
true);
8076 if((allocator->m_MemProps.memoryHeaps[heapIndex].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
8078 json.WriteString(
"DEVICE_LOCAL");
8082 if(stats.memoryHeap[heapIndex].blockCount > 0)
8084 json.WriteString(
"Stats");
8085 VmaPrintStatInfo(json, stats.memoryHeap[heapIndex]);
8088 for(uint32_t typeIndex = 0; typeIndex < allocator->GetMemoryTypeCount(); ++typeIndex)
8090 if(allocator->MemoryTypeIndexToHeapIndex(typeIndex) == heapIndex)
8092 json.BeginString(
"Type ");
8093 json.ContinueString(typeIndex);
8098 json.WriteString(
"Flags");
8099 json.BeginArray(
true);
8100 VkMemoryPropertyFlags flags = allocator->m_MemProps.memoryTypes[typeIndex].propertyFlags;
8101 if((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
8103 json.WriteString(
"DEVICE_LOCAL");
8105 if((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
8107 json.WriteString(
"HOST_VISIBLE");
8109 if((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
8111 json.WriteString(
"HOST_COHERENT");
8113 if((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
8115 json.WriteString(
"HOST_CACHED");
8117 if((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
8119 json.WriteString(
"LAZILY_ALLOCATED");
8123 if(stats.memoryType[typeIndex].blockCount > 0)
8125 json.WriteString(
"Stats");
8126 VmaPrintStatInfo(json, stats.memoryType[typeIndex]);
8135 if(detailedMap == VK_TRUE)
8137 allocator->PrintDetailedMap(json);
8143 const size_t len = sb.GetLength();
8144 char*
const pChars = vma_new_array(allocator,
char, len + 1);
8147 memcpy(pChars, sb.GetData(), len);
8150 *ppStatsString = pChars;
8153 void vmaFreeStatsString(
8154 VmaAllocator allocator,
8157 if(pStatsString != VMA_NULL)
8159 VMA_ASSERT(allocator);
8160 size_t len = strlen(pStatsString);
8161 vma_delete_array(allocator, pStatsString, len + 1);
8165 #endif // #if VMA_STATS_STRING_ENABLED 8170 VkResult vmaFindMemoryTypeIndex(
8171 VmaAllocator allocator,
8172 uint32_t memoryTypeBits,
8173 const VmaAllocationCreateInfo* pAllocationCreateInfo,
8174 uint32_t* pMemoryTypeIndex)
8176 VMA_ASSERT(allocator != VK_NULL_HANDLE);
8177 VMA_ASSERT(pAllocationCreateInfo != VMA_NULL);
8178 VMA_ASSERT(pMemoryTypeIndex != VMA_NULL);
8180 if(pAllocationCreateInfo->memoryTypeBits != 0)
8182 memoryTypeBits &= pAllocationCreateInfo->memoryTypeBits;
8185 uint32_t requiredFlags = pAllocationCreateInfo->requiredFlags;
8186 uint32_t preferredFlags = pAllocationCreateInfo->preferredFlags;
8189 switch(pAllocationCreateInfo->usage)
8191 case VMA_MEMORY_USAGE_UNKNOWN:
8193 case VMA_MEMORY_USAGE_GPU_ONLY:
8194 preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
8196 case VMA_MEMORY_USAGE_CPU_ONLY:
8197 requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
8199 case VMA_MEMORY_USAGE_CPU_TO_GPU:
8200 requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
8201 preferredFlags |= VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
8203 case VMA_MEMORY_USAGE_GPU_TO_CPU:
8204 requiredFlags |= VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
8205 preferredFlags |= VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
8211 *pMemoryTypeIndex = UINT32_MAX;
8212 uint32_t minCost = UINT32_MAX;
8213 for(uint32_t memTypeIndex = 0, memTypeBit = 1;
8214 memTypeIndex < allocator->GetMemoryTypeCount();
8215 ++memTypeIndex, memTypeBit <<= 1)
8218 if((memTypeBit & memoryTypeBits) != 0)
8220 const VkMemoryPropertyFlags currFlags =
8221 allocator->m_MemProps.memoryTypes[memTypeIndex].propertyFlags;
8223 if((requiredFlags & ~currFlags) == 0)
8226 uint32_t currCost = VmaCountBitsSet(preferredFlags & ~currFlags);
8228 if(currCost < minCost)
8230 *pMemoryTypeIndex = memTypeIndex;
8240 return (*pMemoryTypeIndex != UINT32_MAX) ? VK_SUCCESS : VK_ERROR_FEATURE_NOT_PRESENT;
8243 VkResult vmaCreatePool(
8244 VmaAllocator allocator,
8245 const VmaPoolCreateInfo* pCreateInfo,
8248 VMA_ASSERT(allocator && pCreateInfo && pPool);
8250 VMA_DEBUG_LOG(
"vmaCreatePool");
8252 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8254 return allocator->CreatePool(pCreateInfo, pPool);
8257 void vmaDestroyPool(
8258 VmaAllocator allocator,
8261 VMA_ASSERT(allocator);
8263 if(pool == VK_NULL_HANDLE)
8268 VMA_DEBUG_LOG(
"vmaDestroyPool");
8270 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8272 allocator->DestroyPool(pool);
8275 void vmaGetPoolStats(
8276 VmaAllocator allocator,
8278 VmaPoolStats* pPoolStats)
8280 VMA_ASSERT(allocator && pool && pPoolStats);
8282 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8284 allocator->GetPoolStats(pool, pPoolStats);
8287 void vmaMakePoolAllocationsLost(
8288 VmaAllocator allocator,
8290 size_t* pLostAllocationCount)
8292 VMA_ASSERT(allocator && pool);
8294 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8296 allocator->MakePoolAllocationsLost(pool, pLostAllocationCount);
8299 VkResult vmaAllocateMemory(
8300 VmaAllocator allocator,
8301 const VkMemoryRequirements* pVkMemoryRequirements,
8302 const VmaAllocationCreateInfo* pCreateInfo,
8303 VmaAllocation* pAllocation,
8304 VmaAllocationInfo* pAllocationInfo)
8306 VMA_ASSERT(allocator && pVkMemoryRequirements && pCreateInfo && pAllocation);
8308 VMA_DEBUG_LOG(
"vmaAllocateMemory");
8310 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8312 VkResult result = allocator->AllocateMemory(
8313 *pVkMemoryRequirements,
8319 VMA_SUBALLOCATION_TYPE_UNKNOWN,
8322 if(pAllocationInfo && result == VK_SUCCESS)
8324 allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
8330 VkResult vmaAllocateMemoryForBuffer(
8331 VmaAllocator allocator,
8333 const VmaAllocationCreateInfo* pCreateInfo,
8334 VmaAllocation* pAllocation,
8335 VmaAllocationInfo* pAllocationInfo)
8337 VMA_ASSERT(allocator && buffer != VK_NULL_HANDLE && pCreateInfo && pAllocation);
8339 VMA_DEBUG_LOG(
"vmaAllocateMemoryForBuffer");
8341 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8343 VkMemoryRequirements vkMemReq = {};
8344 bool requiresDedicatedAllocation =
false;
8345 bool prefersDedicatedAllocation =
false;
8346 allocator->GetBufferMemoryRequirements(buffer, vkMemReq,
8347 requiresDedicatedAllocation,
8348 prefersDedicatedAllocation);
8350 VkResult result = allocator->AllocateMemory(
8352 requiresDedicatedAllocation,
8353 prefersDedicatedAllocation,
8357 VMA_SUBALLOCATION_TYPE_BUFFER,
8360 if(pAllocationInfo && result == VK_SUCCESS)
8362 allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
8368 VkResult vmaAllocateMemoryForImage(
8369 VmaAllocator allocator,
8371 const VmaAllocationCreateInfo* pCreateInfo,
8372 VmaAllocation* pAllocation,
8373 VmaAllocationInfo* pAllocationInfo)
8375 VMA_ASSERT(allocator && image != VK_NULL_HANDLE && pCreateInfo && pAllocation);
8377 VMA_DEBUG_LOG(
"vmaAllocateMemoryForImage");
8379 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8381 VkResult result = AllocateMemoryForImage(
8385 VMA_SUBALLOCATION_TYPE_IMAGE_UNKNOWN,
8388 if(pAllocationInfo && result == VK_SUCCESS)
8390 allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
8397 VmaAllocator allocator,
8398 VmaAllocation allocation)
8400 VMA_ASSERT(allocator && allocation);
8402 VMA_DEBUG_LOG(
"vmaFreeMemory");
8404 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8406 allocator->FreeMemory(allocation);
8409 void vmaGetAllocationInfo(
8410 VmaAllocator allocator,
8411 VmaAllocation allocation,
8412 VmaAllocationInfo* pAllocationInfo)
8414 VMA_ASSERT(allocator && allocation && pAllocationInfo);
8416 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8418 allocator->GetAllocationInfo(allocation, pAllocationInfo);
8421 void vmaSetAllocationUserData(
8422 VmaAllocator allocator,
8423 VmaAllocation allocation,
8426 VMA_ASSERT(allocator && allocation);
8428 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8430 allocation->SetUserData(allocator, pUserData);
8433 void vmaCreateLostAllocation(
8434 VmaAllocator allocator,
8435 VmaAllocation* pAllocation)
8437 VMA_ASSERT(allocator && pAllocation);
8439 VMA_DEBUG_GLOBAL_MUTEX_LOCK;
8441 allocator->CreateLostAllocation(pAllocation);
8444 VkResult vmaMapMemory(
8445 VmaAllocator allocator,
8446 VmaAllocation allocation,
8449 VMA_ASSERT(allocator && allocation && ppData);
8451 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8453 return allocator->Map(allocation, ppData);
8456 void vmaUnmapMemory(
8457 VmaAllocator allocator,
8458 VmaAllocation allocation)
8460 VMA_ASSERT(allocator && allocation);
8462 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8464 allocator->Unmap(allocation);
8467 VkResult vmaDefragment(
8468 VmaAllocator allocator,
8469 VmaAllocation* pAllocations,
8470 size_t allocationCount,
8471 VkBool32* pAllocationsChanged,
8472 const VmaDefragmentationInfo *pDefragmentationInfo,
8473 VmaDefragmentationStats* pDefragmentationStats)
8475 VMA_ASSERT(allocator && pAllocations);
8477 VMA_DEBUG_LOG(
"vmaDefragment");
8479 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8481 return allocator->Defragment(pAllocations, allocationCount, pAllocationsChanged, pDefragmentationInfo, pDefragmentationStats);
8484 VkResult vmaCreateBuffer(
8485 VmaAllocator allocator,
8486 const VkBufferCreateInfo* pBufferCreateInfo,
8487 const VmaAllocationCreateInfo* pAllocationCreateInfo,
8489 VmaAllocation* pAllocation,
8490 VmaAllocationInfo* pAllocationInfo)
8492 VMA_ASSERT(allocator && pBufferCreateInfo && pAllocationCreateInfo && pBuffer && pAllocation);
8494 VMA_DEBUG_LOG(
"vmaCreateBuffer");
8496 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8498 *pBuffer = VK_NULL_HANDLE;
8499 *pAllocation = VK_NULL_HANDLE;
8502 VkResult res = (*allocator->GetVulkanFunctions().vkCreateBuffer)(
8503 allocator->m_hDevice,
8505 allocator->GetAllocationCallbacks(),
8510 VkMemoryRequirements vkMemReq = {};
8511 bool requiresDedicatedAllocation =
false;
8512 bool prefersDedicatedAllocation =
false;
8513 allocator->GetBufferMemoryRequirements(*pBuffer, vkMemReq,
8514 requiresDedicatedAllocation, prefersDedicatedAllocation);
8518 if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) != 0)
8520 VMA_ASSERT(vkMemReq.alignment %
8521 allocator->m_PhysicalDeviceProperties.limits.minTexelBufferOffsetAlignment == 0);
8523 if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) != 0)
8525 VMA_ASSERT(vkMemReq.alignment %
8526 allocator->m_PhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment == 0);
8528 if((pBufferCreateInfo->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0)
8530 VMA_ASSERT(vkMemReq.alignment %
8531 allocator->m_PhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment == 0);
8535 res = allocator->AllocateMemory(
8537 requiresDedicatedAllocation,
8538 prefersDedicatedAllocation,
8541 *pAllocationCreateInfo,
8542 VMA_SUBALLOCATION_TYPE_BUFFER,
8547 res = (*allocator->GetVulkanFunctions().vkBindBufferMemory)(
8548 allocator->m_hDevice,
8550 (*pAllocation)->GetMemory(),
8551 (*pAllocation)->GetOffset());
8555 if(pAllocationInfo != VMA_NULL)
8557 allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
8561 allocator->FreeMemory(*pAllocation);
8562 *pAllocation = VK_NULL_HANDLE;
8563 (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
8564 *pBuffer = VK_NULL_HANDLE;
8567 (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, *pBuffer, allocator->GetAllocationCallbacks());
8568 *pBuffer = VK_NULL_HANDLE;
8574 void vmaDestroyBuffer(
8575 VmaAllocator allocator,
8577 VmaAllocation allocation)
8579 if(buffer != VK_NULL_HANDLE)
8581 VMA_ASSERT(allocator);
8583 VMA_DEBUG_LOG(
"vmaDestroyBuffer");
8585 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8587 (*allocator->GetVulkanFunctions().vkDestroyBuffer)(allocator->m_hDevice, buffer, allocator->GetAllocationCallbacks());
8589 allocator->FreeMemory(allocation);
8593 VkResult vmaCreateImage(
8594 VmaAllocator allocator,
8595 const VkImageCreateInfo* pImageCreateInfo,
8596 const VmaAllocationCreateInfo* pAllocationCreateInfo,
8598 VmaAllocation* pAllocation,
8599 VmaAllocationInfo* pAllocationInfo)
8601 VMA_ASSERT(allocator && pImageCreateInfo && pAllocationCreateInfo && pImage && pAllocation);
8603 VMA_DEBUG_LOG(
"vmaCreateImage");
8605 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8607 *pImage = VK_NULL_HANDLE;
8608 *pAllocation = VK_NULL_HANDLE;
8611 VkResult res = (*allocator->GetVulkanFunctions().vkCreateImage)(
8612 allocator->m_hDevice,
8614 allocator->GetAllocationCallbacks(),
8618 VmaSuballocationType suballocType = pImageCreateInfo->tiling == VK_IMAGE_TILING_OPTIMAL ?
8619 VMA_SUBALLOCATION_TYPE_IMAGE_OPTIMAL :
8620 VMA_SUBALLOCATION_TYPE_IMAGE_LINEAR;
8623 res = AllocateMemoryForImage(allocator, *pImage, pAllocationCreateInfo, suballocType, pAllocation);
8627 res = (*allocator->GetVulkanFunctions().vkBindImageMemory)(
8628 allocator->m_hDevice,
8630 (*pAllocation)->GetMemory(),
8631 (*pAllocation)->GetOffset());
8635 if(pAllocationInfo != VMA_NULL)
8637 allocator->GetAllocationInfo(*pAllocation, pAllocationInfo);
8641 allocator->FreeMemory(*pAllocation);
8642 *pAllocation = VK_NULL_HANDLE;
8643 (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
8644 *pImage = VK_NULL_HANDLE;
8647 (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, *pImage, allocator->GetAllocationCallbacks());
8648 *pImage = VK_NULL_HANDLE;
8654 void vmaDestroyImage(
8655 VmaAllocator allocator,
8657 VmaAllocation allocation)
8659 if(image != VK_NULL_HANDLE)
8661 VMA_ASSERT(allocator);
8663 VMA_DEBUG_LOG(
"vmaDestroyImage");
8665 VMA_DEBUG_GLOBAL_MUTEX_LOCK
8667 (*allocator->GetVulkanFunctions().vkDestroyImage)(allocator->m_hDevice, image, allocator->GetAllocationCallbacks());
8669 allocator->FreeMemory(allocation);
8673 #endif // #ifdef VMA_IMPLEMENTATION 8674 #endif // ifdef USING_VULKAN IMGUI_API void Value(const char *prefix, bool b)