@@ -117,6 +117,23 @@ static const wchar_t* DefragmentationAlgorithmToStr(uint32_t algorithm)
117117 }
118118}
119119
120+ static inline bool operator ==(const VmaStatistics& lhs, const VmaStatistics& rhs)
121+ {
122+ return lhs.allocationBytes == rhs.allocationBytes &&
123+ lhs.allocationCount == rhs.allocationCount &&
124+ lhs.blockBytes == rhs.blockBytes &&
125+ lhs.blockCount == rhs.blockCount ;
126+ }
127+ static inline bool operator ==(const VmaDetailedStatistics& lhs, const VmaDetailedStatistics& rhs)
128+ {
129+ return lhs.statistics == rhs.statistics &&
130+ lhs.unusedRangeCount == rhs.unusedRangeCount &&
131+ lhs.allocationSizeMax == rhs.allocationSizeMax &&
132+ lhs.allocationSizeMin == rhs.allocationSizeMin &&
133+ lhs.unusedRangeSizeMax == rhs.unusedRangeSizeMax &&
134+ lhs.unusedRangeSizeMin == rhs.unusedRangeSizeMin ;
135+ }
136+
120137struct AllocationSize
121138{
122139 uint32_t Probability;
@@ -6213,22 +6230,70 @@ static void TestDeviceCoherentMemory()
62136230 vmaDestroyAllocator (localAllocator);
62146231}
62156232
6216- static void TestBudget ( )
6233+ static void InitEmptyDetailedStatistics (VmaDetailedStatistics& outStats )
62176234{
6218- wprintf (L" Testing budget...\n " );
6235+ outStats = {};
6236+ outStats.allocationSizeMin = VK_WHOLE_SIZE;
6237+ outStats.unusedRangeSizeMin = VK_WHOLE_SIZE;
6238+ }
62196239
6220- static const VkDeviceSize BUF_SIZE = 10ull * 1024 * 1024 ;
6221- static const uint32_t BUF_COUNT = 4 ;
6240+ static void AddDetailedStatistics (VmaDetailedStatistics& inoutSum, const VmaDetailedStatistics& stats)
6241+ {
6242+ inoutSum.statistics .allocationBytes += stats.statistics .allocationBytes ;
6243+ inoutSum.statistics .allocationCount += stats.statistics .allocationCount ;
6244+ inoutSum.statistics .blockBytes += stats.statistics .blockBytes ;
6245+ inoutSum.statistics .blockCount += stats.statistics .blockCount ;
6246+ inoutSum.unusedRangeCount += stats.unusedRangeCount ;
6247+ inoutSum.allocationSizeMax = std::max (inoutSum.allocationSizeMax , stats.allocationSizeMax );
6248+ inoutSum.allocationSizeMin = std::min (inoutSum.allocationSizeMin , stats.allocationSizeMin );
6249+ inoutSum.unusedRangeSizeMax = std::max (inoutSum.unusedRangeSizeMax , stats.unusedRangeSizeMax );
6250+ inoutSum.unusedRangeSizeMin = std::min (inoutSum.unusedRangeSizeMin , stats.unusedRangeSizeMin );
6251+ }
6252+
6253+ static void ValidateTotalStatistics (const VmaTotalStatistics& stats)
6254+ {
6255+ const VkPhysicalDeviceMemoryProperties* memProps = nullptr ;
6256+ vmaGetMemoryProperties (g_hAllocator, &memProps);
6257+
6258+ VmaDetailedStatistics sum;
6259+ InitEmptyDetailedStatistics (sum);
6260+ for (uint32_t i = 0 ; i < memProps->memoryHeapCount ; ++i)
6261+ AddDetailedStatistics (sum, stats.memoryHeap [i]);
6262+ TEST (sum == stats.total );
6263+
6264+ InitEmptyDetailedStatistics (sum);
6265+ for (uint32_t i = 0 ; i < memProps->memoryTypeCount ; ++i)
6266+ AddDetailedStatistics (sum, stats.memoryType [i]);
6267+ TEST (sum == stats.total );
6268+ }
6269+
6270+ static void TestStatistics ()
6271+ {
6272+ wprintf (L" Testing statistics...\n " );
6273+
6274+ constexpr VkDeviceSize BUF_SIZE = 10ull * 1024 * 1024 ;
6275+ constexpr uint32_t BUF_COUNT = 4 ;
6276+ constexpr VkDeviceSize PREALLOCATED_BLOCK_SIZE = BUF_SIZE * (BUF_COUNT + 1 );
62226277
62236278 const VkPhysicalDeviceMemoryProperties* memProps = {};
62246279 vmaGetMemoryProperties (g_hAllocator, &memProps);
62256280
6226- for (uint32_t testIndex = 0 ; testIndex < 2 ; ++testIndex)
6281+ /*
6282+ Test 0: VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT.
6283+ Test 1: normal allocations.
6284+ Test 2: allocations in a custom pool.
6285+ Test 3: allocations in a custom pool, DEDICATED_MEMORY.
6286+ Test 4: allocations in a custom pool with preallocated memory.
6287+ */
6288+ uint32_t memTypeIndex = UINT32_MAX;
6289+ for (uint32_t testIndex = 0 ; testIndex < 5 ; ++testIndex)
62276290 {
62286291 vmaSetCurrentFrameIndex (g_hAllocator, ++g_FrameIndex);
62296292
62306293 VmaBudget budgetBeg[VK_MAX_MEMORY_HEAPS] = {};
62316294 vmaGetHeapBudgets (g_hAllocator, budgetBeg);
6295+ VmaTotalStatistics statsBeg = {};
6296+ vmaCalculateStatistics (g_hAllocator, &statsBeg);
62326297
62336298 for (uint32_t i = 0 ; i < memProps->memoryHeapCount ; ++i)
62346299 {
@@ -6237,18 +6302,45 @@ static void TestBudget()
62376302 TEST (budgetBeg[i].statistics .allocationBytes <= budgetBeg[i].statistics .blockBytes );
62386303 }
62396304
6305+ // Create pool.
6306+ const bool usePool = testIndex >= 2 ;
6307+ const bool useDedicated = testIndex == 0 || testIndex == 3 ;
6308+ const bool usePreallocated = testIndex == 4 ;
6309+ VmaPool pool = VK_NULL_HANDLE;
6310+ if (usePool)
6311+ {
6312+ assert (memTypeIndex != UINT32_MAX);
6313+ VmaPoolCreateInfo poolCreateInfo = {};
6314+ poolCreateInfo.memoryTypeIndex = memTypeIndex;
6315+ if (usePreallocated)
6316+ {
6317+ poolCreateInfo.blockSize = PREALLOCATED_BLOCK_SIZE;
6318+ poolCreateInfo.minBlockCount = poolCreateInfo.maxBlockCount = 1 ;
6319+ }
6320+ TEST (vmaCreatePool (g_hAllocator, &poolCreateInfo, &pool) == VK_SUCCESS);
6321+ }
6322+
6323+ VmaStatistics poolStatsBeg = {};
6324+ VmaDetailedStatistics detailedPoolStatsBeg = {};
6325+ if (usePool)
6326+ {
6327+ vmaGetPoolStatistics (g_hAllocator, pool, &poolStatsBeg);
6328+ vmaCalculatePoolStatistics (g_hAllocator, pool, &detailedPoolStatsBeg);
6329+ }
6330+
6331+ // CREATE BUFFERS
62406332 VkBufferCreateInfo bufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
62416333 bufInfo.size = BUF_SIZE;
62426334 bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
62436335
62446336 VmaAllocationCreateInfo allocCreateInfo = {};
6245- allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
6246- if (testIndex == 0 )
6247- {
6337+ if (usePool)
6338+ allocCreateInfo.pool = pool;
6339+ else
6340+ allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE;
6341+ if (useDedicated)
62486342 allocCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
6249- }
62506343
6251- // CREATE BUFFERS
62526344 uint32_t heapIndex = 0 ;
62536345 BufferInfo bufInfos[BUF_COUNT] = {};
62546346 for (uint32_t bufIndex = 0 ; bufIndex < BUF_COUNT; ++bufIndex)
@@ -6259,6 +6351,8 @@ static void TestBudget()
62596351 TEST (res == VK_SUCCESS);
62606352 if (bufIndex == 0 )
62616353 {
6354+ if (testIndex == 1 )
6355+ memTypeIndex = allocInfo.memoryType ;
62626356 heapIndex = MemoryTypeToHeap (allocInfo.memoryType );
62636357 }
62646358 else
@@ -6270,32 +6364,150 @@ static void TestBudget()
62706364
62716365 VmaBudget budgetWithBufs[VK_MAX_MEMORY_HEAPS] = {};
62726366 vmaGetHeapBudgets (g_hAllocator, budgetWithBufs);
6367+ VmaTotalStatistics statsWithBufs = {};
6368+ vmaCalculateStatistics (g_hAllocator, &statsWithBufs);
6369+
6370+ VmaStatistics poolStatsWithBufs = {};
6371+ VmaDetailedStatistics detailedPoolStatsWithBufs = {};
6372+ if (usePool)
6373+ {
6374+ vmaGetPoolStatistics (g_hAllocator, pool, &poolStatsWithBufs);
6375+ vmaCalculatePoolStatistics (g_hAllocator, pool, &detailedPoolStatsWithBufs);
6376+ }
62736377
62746378 // DESTROY BUFFERS
62756379 for (size_t bufIndex = BUF_COUNT; bufIndex--; )
62766380 {
62776381 vmaDestroyBuffer (g_hAllocator, bufInfos[bufIndex].Buffer , bufInfos[bufIndex].Allocation );
62786382 }
62796383
6384+ VmaStatistics poolStatsEnd = {};
6385+ VmaDetailedStatistics detailedPoolStatsEnd = {};
6386+ if (usePool)
6387+ {
6388+ vmaGetPoolStatistics (g_hAllocator, pool, &poolStatsEnd);
6389+ vmaCalculatePoolStatistics (g_hAllocator, pool, &detailedPoolStatsEnd);
6390+ }
6391+
6392+ // Destroy the pool.
6393+ vmaDestroyPool (g_hAllocator, pool);
6394+
62806395 VmaBudget budgetEnd[VK_MAX_MEMORY_HEAPS] = {};
62816396 vmaGetHeapBudgets (g_hAllocator, budgetEnd);
6397+ VmaTotalStatistics statsEnd = {};
6398+ vmaCalculateStatistics (g_hAllocator, &statsEnd);
62826399
6283- // CHECK
6400+ // CHECK MEMORY HEAPS
62846401 for (uint32_t i = 0 ; i < memProps->memoryHeapCount ; ++i)
62856402 {
62866403 TEST (budgetEnd[i].statistics .allocationBytes <= budgetEnd[i].statistics .blockBytes );
6404+
6405+ // The heap in which we allocated the testing buffers.
62876406 if (i == heapIndex)
62886407 {
6408+ // VmaBudget::usage
6409+ TEST (budgetWithBufs[i].usage >= budgetBeg[i].usage );
6410+ TEST (budgetEnd[i].usage <= budgetWithBufs[i].usage );
6411+
6412+ // VmaBudget - VmaStatistics::allocationBytes
62896413 TEST (budgetEnd[i].statistics .allocationBytes == budgetBeg[i].statistics .allocationBytes );
62906414 TEST (budgetWithBufs[i].statistics .allocationBytes == budgetBeg[i].statistics .allocationBytes + BUF_SIZE * BUF_COUNT);
6291- TEST (budgetWithBufs[i].statistics .blockBytes >= budgetEnd[i].statistics .blockBytes );
6415+
6416+ // VmaBudget - VmaStatistics::blockBytes
6417+ if (usePool)
6418+ {
6419+ TEST (budgetEnd[i].statistics .blockBytes == budgetBeg[i].statistics .blockBytes );
6420+ TEST (budgetWithBufs[i].statistics .blockBytes > budgetBeg[i].statistics .blockBytes );
6421+ }
6422+ else
6423+ TEST (budgetWithBufs[i].statistics .blockBytes >= budgetBeg[i].statistics .blockBytes );
6424+
6425+ // VmaBudget - VmaStatistics::allocationCount
6426+ TEST (budgetEnd[i].statistics .allocationCount == budgetBeg[i].statistics .allocationCount );
6427+ TEST (budgetWithBufs[i].statistics .allocationCount == budgetBeg[i].statistics .allocationCount + BUF_COUNT);
6428+
6429+ // VmaBudget - VmaStatistics::blockCount
6430+ if (useDedicated)
6431+ {
6432+ TEST (budgetEnd[i].statistics .blockCount == budgetBeg[i].statistics .blockCount );
6433+ TEST (budgetWithBufs[i].statistics .blockCount == budgetBeg[i].statistics .blockCount + BUF_COUNT);
6434+ }
6435+ else if (usePool)
6436+ {
6437+ TEST (budgetEnd[i].statistics .blockCount == budgetBeg[i].statistics .blockCount );
6438+ if (usePreallocated)
6439+ TEST (budgetWithBufs[i].statistics .blockCount == budgetBeg[i].statistics .blockCount + 1 );
6440+ else
6441+ TEST (budgetWithBufs[i].statistics .blockCount > budgetBeg[i].statistics .blockCount );
6442+ }
62926443 }
62936444 else
62946445 {
6295- TEST (budgetEnd[i].statistics .allocationBytes == budgetEnd [i].statistics .allocationBytes &&
6446+ TEST (budgetEnd[i].statistics .allocationBytes == budgetBeg [i].statistics .allocationBytes &&
62966447 budgetEnd[i].statistics .allocationBytes == budgetWithBufs[i].statistics .allocationBytes );
6297- TEST (budgetEnd[i].statistics .blockBytes == budgetEnd [i].statistics .blockBytes &&
6448+ TEST (budgetEnd[i].statistics .blockBytes == budgetBeg [i].statistics .blockBytes &&
62986449 budgetEnd[i].statistics .blockBytes == budgetWithBufs[i].statistics .blockBytes );
6450+ TEST (budgetEnd[i].statistics .allocationCount == budgetBeg[i].statistics .allocationCount &&
6451+ budgetEnd[i].statistics .allocationCount == budgetWithBufs[i].statistics .allocationCount );
6452+ TEST (budgetEnd[i].statistics .blockCount == budgetBeg[i].statistics .blockCount &&
6453+ budgetEnd[i].statistics .blockCount == budgetWithBufs[i].statistics .blockCount );
6454+ }
6455+
6456+ // Validate that statistics per heap and per type sum up to total correctly.
6457+ ValidateTotalStatistics (statsBeg);
6458+ ValidateTotalStatistics (statsWithBufs);
6459+ ValidateTotalStatistics (statsEnd);
6460+
6461+ // Compare vmaCalculateStatistics per heap with vmaGetBudget.
6462+ TEST (statsBeg.memoryHeap [i].statistics == budgetBeg[i].statistics );
6463+ TEST (statsWithBufs.memoryHeap [i].statistics == budgetWithBufs[i].statistics );
6464+ TEST (statsEnd.memoryHeap [i].statistics == budgetEnd[i].statistics );
6465+
6466+ if (usePool)
6467+ {
6468+ // Compare simple stats with calculated stats to make sure they are identical.
6469+ TEST (poolStatsBeg == detailedPoolStatsBeg.statistics );
6470+ TEST (poolStatsWithBufs == detailedPoolStatsWithBufs.statistics );
6471+ TEST (poolStatsEnd == detailedPoolStatsEnd.statistics );
6472+
6473+ // Validate stats of an empty pool.
6474+ TEST (detailedPoolStatsBeg.allocationSizeMax == 0 );
6475+ TEST (detailedPoolStatsEnd.allocationSizeMax == 0 );
6476+ TEST (detailedPoolStatsBeg.allocationSizeMin == VK_WHOLE_SIZE);
6477+ TEST (detailedPoolStatsEnd.allocationSizeMin == VK_WHOLE_SIZE);
6478+ TEST (poolStatsBeg.allocationCount == 0 );
6479+ TEST (poolStatsBeg.allocationBytes == 0 );
6480+ TEST (poolStatsEnd.allocationCount == 0 );
6481+ TEST (poolStatsEnd.allocationBytes == 0 );
6482+ if (usePreallocated)
6483+ {
6484+ TEST (poolStatsBeg.blockCount == 1 );
6485+ TEST (poolStatsEnd.blockCount == 1 );
6486+ TEST (poolStatsBeg.blockBytes == PREALLOCATED_BLOCK_SIZE);
6487+ TEST (poolStatsEnd.blockBytes == PREALLOCATED_BLOCK_SIZE);
6488+ }
6489+ else
6490+ {
6491+ TEST (poolStatsBeg.blockCount == 0 );
6492+ TEST (poolStatsBeg.blockBytes == 0 );
6493+ // Not checking poolStatsEnd.blockCount, blockBytes, because an empty block may stay allocated.
6494+ }
6495+
6496+ // Validate stats of a pool with buffers.
6497+ TEST (detailedPoolStatsWithBufs.allocationSizeMin == BUF_SIZE);
6498+ TEST (detailedPoolStatsWithBufs.allocationSizeMax == BUF_SIZE);
6499+ TEST (poolStatsWithBufs.allocationCount == BUF_COUNT);
6500+ TEST (poolStatsWithBufs.allocationBytes == BUF_COUNT * BUF_SIZE);
6501+ if (usePreallocated)
6502+ {
6503+ TEST (poolStatsWithBufs.blockCount == 1 );
6504+ TEST (poolStatsWithBufs.blockBytes == PREALLOCATED_BLOCK_SIZE);
6505+ }
6506+ else
6507+ {
6508+ TEST (poolStatsWithBufs.blockCount > 0 );
6509+ TEST (poolStatsWithBufs.blockBytes >= poolStatsWithBufs.allocationBytes );
6510+ }
62996511 }
63006512 }
63016513 }
@@ -8146,7 +8358,7 @@ void Test()
81468358#endif
81478359 TestMemoryUsage ();
81488360 TestDeviceCoherentMemory ();
8149- TestBudget ();
8361+ TestStatistics ();
81508362 TestAliasing ();
81518363 TestAllocationAliasing ();
81528364 TestMapping ();
0 commit comments