@@ -117,6 +117,23 @@ static const wchar_t* DefragmentationAlgorithmToStr(uint32_t algorithm)
117
117
}
118
118
}
119
119
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
+
120
137
struct AllocationSize
121
138
{
122
139
uint32_t Probability;
@@ -6213,22 +6230,70 @@ static void TestDeviceCoherentMemory()
6213
6230
vmaDestroyAllocator (localAllocator);
6214
6231
}
6215
6232
6216
- static void TestBudget ( )
6233
+ static void InitEmptyDetailedStatistics (VmaDetailedStatistics& outStats )
6217
6234
{
6218
- wprintf (L" Testing budget...\n " );
6235
+ outStats = {};
6236
+ outStats.allocationSizeMin = VK_WHOLE_SIZE;
6237
+ outStats.unusedRangeSizeMin = VK_WHOLE_SIZE;
6238
+ }
6219
6239
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 );
6222
6277
6223
6278
const VkPhysicalDeviceMemoryProperties* memProps = {};
6224
6279
vmaGetMemoryProperties (g_hAllocator, &memProps);
6225
6280
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)
6227
6290
{
6228
6291
vmaSetCurrentFrameIndex (g_hAllocator, ++g_FrameIndex);
6229
6292
6230
6293
VmaBudget budgetBeg[VK_MAX_MEMORY_HEAPS] = {};
6231
6294
vmaGetHeapBudgets (g_hAllocator, budgetBeg);
6295
+ VmaTotalStatistics statsBeg = {};
6296
+ vmaCalculateStatistics (g_hAllocator, &statsBeg);
6232
6297
6233
6298
for (uint32_t i = 0 ; i < memProps->memoryHeapCount ; ++i)
6234
6299
{
@@ -6237,18 +6302,45 @@ static void TestBudget()
6237
6302
TEST (budgetBeg[i].statistics .allocationBytes <= budgetBeg[i].statistics .blockBytes );
6238
6303
}
6239
6304
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
6240
6332
VkBufferCreateInfo bufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
6241
6333
bufInfo.size = BUF_SIZE;
6242
6334
bufInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
6243
6335
6244
6336
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)
6248
6342
allocCreateInfo.flags |= VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT;
6249
- }
6250
6343
6251
- // CREATE BUFFERS
6252
6344
uint32_t heapIndex = 0 ;
6253
6345
BufferInfo bufInfos[BUF_COUNT] = {};
6254
6346
for (uint32_t bufIndex = 0 ; bufIndex < BUF_COUNT; ++bufIndex)
@@ -6259,6 +6351,8 @@ static void TestBudget()
6259
6351
TEST (res == VK_SUCCESS);
6260
6352
if (bufIndex == 0 )
6261
6353
{
6354
+ if (testIndex == 1 )
6355
+ memTypeIndex = allocInfo.memoryType ;
6262
6356
heapIndex = MemoryTypeToHeap (allocInfo.memoryType );
6263
6357
}
6264
6358
else
@@ -6270,32 +6364,150 @@ static void TestBudget()
6270
6364
6271
6365
VmaBudget budgetWithBufs[VK_MAX_MEMORY_HEAPS] = {};
6272
6366
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
+ }
6273
6377
6274
6378
// DESTROY BUFFERS
6275
6379
for (size_t bufIndex = BUF_COUNT; bufIndex--; )
6276
6380
{
6277
6381
vmaDestroyBuffer (g_hAllocator, bufInfos[bufIndex].Buffer , bufInfos[bufIndex].Allocation );
6278
6382
}
6279
6383
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
+
6280
6395
VmaBudget budgetEnd[VK_MAX_MEMORY_HEAPS] = {};
6281
6396
vmaGetHeapBudgets (g_hAllocator, budgetEnd);
6397
+ VmaTotalStatistics statsEnd = {};
6398
+ vmaCalculateStatistics (g_hAllocator, &statsEnd);
6282
6399
6283
- // CHECK
6400
+ // CHECK MEMORY HEAPS
6284
6401
for (uint32_t i = 0 ; i < memProps->memoryHeapCount ; ++i)
6285
6402
{
6286
6403
TEST (budgetEnd[i].statistics .allocationBytes <= budgetEnd[i].statistics .blockBytes );
6404
+
6405
+ // The heap in which we allocated the testing buffers.
6287
6406
if (i == heapIndex)
6288
6407
{
6408
+ // VmaBudget::usage
6409
+ TEST (budgetWithBufs[i].usage >= budgetBeg[i].usage );
6410
+ TEST (budgetEnd[i].usage <= budgetWithBufs[i].usage );
6411
+
6412
+ // VmaBudget - VmaStatistics::allocationBytes
6289
6413
TEST (budgetEnd[i].statistics .allocationBytes == budgetBeg[i].statistics .allocationBytes );
6290
6414
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
+ }
6292
6443
}
6293
6444
else
6294
6445
{
6295
- TEST (budgetEnd[i].statistics .allocationBytes == budgetEnd [i].statistics .allocationBytes &&
6446
+ TEST (budgetEnd[i].statistics .allocationBytes == budgetBeg [i].statistics .allocationBytes &&
6296
6447
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 &&
6298
6449
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
+ }
6299
6511
}
6300
6512
}
6301
6513
}
@@ -8146,7 +8358,7 @@ void Test()
8146
8358
#endif
8147
8359
TestMemoryUsage ();
8148
8360
TestDeviceCoherentMemory ();
8149
- TestBudget ();
8361
+ TestStatistics ();
8150
8362
TestAliasing ();
8151
8363
TestAllocationAliasing ();
8152
8364
TestMapping ();
0 commit comments